Code formatting (indents etc.) to get it consistent, simplify it for contributors.

This commit is contained in:
Robin Krom 2021-03-28 19:24:26 +02:00
parent 726644de99
commit e8c0b307ee
No known key found for this signature in database
GPG key ID: BCC01364F1371490
435 changed files with 46647 additions and 39014 deletions

View file

@ -25,12 +25,14 @@ using Greenshot.Plugin.Box.Forms;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.Box { namespace Greenshot.Plugin.Box
{
/// <summary> /// <summary>
/// Description of ImgurConfiguration. /// Description of ImgurConfiguration.
/// </summary> /// </summary>
[IniSection("Box", Description = "Greenshot Box Plugin configuration")] [IniSection("Box", Description = "Greenshot Box Plugin configuration")]
public class BoxConfiguration : IniSection { public class BoxConfiguration : IniSection
{
[IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")]
public OutputFormat UploadFormat { get; set; } public OutputFormat UploadFormat { get; set; }
@ -42,6 +44,7 @@ namespace Greenshot.Plugin.Box {
[IniProperty("UseSharedLink", Description = "Use the shared link, instead of the private, on the clipboard", DefaultValue = "True")] [IniProperty("UseSharedLink", Description = "Use the shared link, instead of the private, on the clipboard", DefaultValue = "True")]
public bool UseSharedLink { get; set; } public bool UseSharedLink { get; set; }
[IniProperty("FolderId", Description = "Folder ID to upload to, only change if you know what you are doing!", DefaultValue = "0")] [IniProperty("FolderId", Description = "Folder ID to upload to, only change if you know what you are doing!", DefaultValue = "0")]
public string FolderId { get; set; } public string FolderId { get; set; }
@ -51,30 +54,26 @@ namespace Greenshot.Plugin.Box {
/// <summary> /// <summary>
/// Not stored /// Not stored
/// </summary> /// </summary>
public string AccessToken { public string AccessToken { get; set; }
get;
set;
}
/// <summary> /// <summary>
/// Not stored /// Not stored
/// </summary> /// </summary>
public DateTimeOffset AccessTokenExpires { public DateTimeOffset AccessTokenExpires { get; set; }
get;
set;
}
/// <summary> /// <summary>
/// A form for token /// A form for token
/// </summary> /// </summary>
/// <returns>bool true if OK was pressed, false if cancel</returns> /// <returns>bool true if OK was pressed, false if cancel</returns>
public bool ShowConfigDialog() { public bool ShowConfigDialog()
{
DialogResult result = new SettingsForm().ShowDialog(); DialogResult result = new SettingsForm().ShowDialog();
if (result == DialogResult.OK) { if (result == DialogResult.OK)
{
return true; return true;
} }
return false; return false;
} }
} }
} }

View file

@ -24,10 +24,14 @@ using System.Drawing;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
namespace Greenshot.Plugin.Box { namespace Greenshot.Plugin.Box
public class BoxDestination : AbstractDestination { {
public class BoxDestination : AbstractDestination
{
private readonly BoxPlugin _plugin; private readonly BoxPlugin _plugin;
public BoxDestination(BoxPlugin plugin) {
public BoxDestination(BoxPlugin plugin)
{
_plugin = plugin; _plugin = plugin;
} }
@ -35,20 +39,25 @@ namespace Greenshot.Plugin.Box {
public override string Description => Language.GetString("box", LangKey.upload_menu_item); public override string Description => Language.GetString("box", LangKey.upload_menu_item);
public override Image DisplayIcon { public override Image DisplayIcon
get { {
get
{
ComponentResourceManager resources = new ComponentResourceManager(typeof(BoxPlugin)); ComponentResourceManager resources = new ComponentResourceManager(typeof(BoxPlugin));
return (Image) resources.GetObject("Box"); return (Image) resources.GetObject("Box");
} }
} }
public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails)
{
ExportInformation exportInformation = new ExportInformation(Designation, Description); ExportInformation exportInformation = new ExportInformation(Designation, Description);
string uploadUrl = _plugin.Upload(captureDetails, surface); string uploadUrl = _plugin.Upload(captureDetails, surface);
if (uploadUrl != null) { if (uploadUrl != null)
{
exportInformation.ExportMade = true; exportInformation.ExportMade = true;
exportInformation.Uri = uploadUrl; exportInformation.Uri = uploadUrl;
} }
ProcessExport(exportInformation, surface); ProcessExport(exportInformation, surface);
return exportInformation; return exportInformation;
} }

View file

@ -22,39 +22,35 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.Serialization; using System.Runtime.Serialization;
namespace Greenshot.Plugin.Box { namespace Greenshot.Plugin.Box
{
[DataContract] [DataContract]
public class Authorization { public class Authorization
[DataMember(Name = "access_token")] {
public string AccessToken { get; set; } [DataMember(Name = "access_token")] public string AccessToken { get; set; }
[DataMember(Name = "expires_in")] [DataMember(Name = "expires_in")] public int ExpiresIn { get; set; }
public int ExpiresIn { get; set; } [DataMember(Name = "refresh_token")] public string RefreshToken { get; set; }
[DataMember(Name = "refresh_token")] [DataMember(Name = "token_type")] public string TokenType { get; set; }
public string RefreshToken { get; set; }
[DataMember(Name = "token_type")]
public string TokenType { get; set; }
}
[DataContract]
public class SharedLink {
[DataMember(Name = "url")]
public string Url { get; set; }
[DataMember(Name = "download_url")]
public string DownloadUrl { get; set; }
} }
[DataContract] [DataContract]
public class FileEntry { public class SharedLink
[DataMember(Name = "id")] {
public string Id { get; set; } [DataMember(Name = "url")] public string Url { get; set; }
[DataMember(Name = "name")] [DataMember(Name = "download_url")] public string DownloadUrl { get; set; }
public string Name { get; set; }
[DataMember(Name = "shared_link")]
public SharedLink SharedLink { get; set; }
} }
[DataContract] [DataContract]
public class Upload { public class FileEntry
[DataMember(Name = "entries")] {
public List<FileEntry> Entries { get; set; } [DataMember(Name = "id")] public string Id { get; set; }
[DataMember(Name = "name")] public string Name { get; set; }
[DataMember(Name = "shared_link")] public SharedLink SharedLink { get; set; }
}
[DataContract]
public class Upload
{
[DataMember(Name = "entries")] public List<FileEntry> Entries { get; set; }
} }
} }

View file

@ -30,18 +30,21 @@ using GreenshotPlugin.IniFile;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin; using GreenshotPlugin.Interfaces.Plugin;
namespace Greenshot.Plugin.Box { namespace Greenshot.Plugin.Box
{
/// <summary> /// <summary>
/// This is the Box base code /// This is the Box base code
/// </summary> /// </summary>
[Plugin("Box", true)] [Plugin("Box", true)]
public class BoxPlugin : IGreenshotPlugin { public class BoxPlugin : IGreenshotPlugin
{
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(BoxPlugin)); private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(BoxPlugin));
private static BoxConfiguration _config; private static BoxConfiguration _config;
private ComponentResourceManager _resources; private ComponentResourceManager _resources;
private ToolStripMenuItem _itemPlugInConfig; private ToolStripMenuItem _itemPlugInConfig;
public void Dispose() { public void Dispose()
{
Dispose(true); Dispose(true);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
@ -59,13 +62,14 @@ namespace Greenshot.Plugin.Box {
/// <summary> /// <summary>
/// Implementation of the IGreenshotPlugin.Initialize /// Implementation of the IGreenshotPlugin.Initialize
/// </summary> /// </summary>
public bool Initialize() { public bool Initialize()
{
// Register configuration (don't need the configuration itself) // Register configuration (don't need the configuration itself)
_config = IniConfig.GetIniSection<BoxConfiguration>(); _config = IniConfig.GetIniSection<BoxConfiguration>();
_resources = new ComponentResourceManager(typeof(BoxPlugin)); _resources = new ComponentResourceManager(typeof(BoxPlugin));
SimpleServiceProvider.Current.AddService<IDestination>(new BoxDestination(this)); SimpleServiceProvider.Current.AddService<IDestination>(new BoxDestination(this));
_itemPlugInConfig = new ToolStripMenuItem { _itemPlugInConfig = new ToolStripMenuItem
{
Image = (Image) _resources.GetObject("Box"), Image = (Image) _resources.GetObject("Box"),
Text = Language.GetString("box", LangKey.Configure) Text = Language.GetString("box", LangKey.Configure)
}; };
@ -76,49 +80,57 @@ namespace Greenshot.Plugin.Box {
return true; return true;
} }
public void OnLanguageChanged(object sender, EventArgs e) { public void OnLanguageChanged(object sender, EventArgs e)
if (_itemPlugInConfig != null) { {
if (_itemPlugInConfig != null)
{
_itemPlugInConfig.Text = Language.GetString("box", LangKey.Configure); _itemPlugInConfig.Text = Language.GetString("box", LangKey.Configure);
} }
} }
public void Shutdown() { public void Shutdown()
{
LOG.Debug("Box Plugin shutdown."); LOG.Debug("Box Plugin shutdown.");
} }
/// <summary> /// <summary>
/// Implementation of the IPlugin.Configure /// Implementation of the IPlugin.Configure
/// </summary> /// </summary>
public void Configure() { public void Configure()
{
_config.ShowConfigDialog(); _config.ShowConfigDialog();
} }
public void ConfigMenuClick(object sender, EventArgs eventArgs) { public void ConfigMenuClick(object sender, EventArgs eventArgs)
{
_config.ShowConfigDialog(); _config.ShowConfigDialog();
} }
/// <summary> /// <summary>
/// This will be called when the menu item in the Editor is clicked /// This will be called when the menu item in the Editor is clicked
/// </summary> /// </summary>
public string Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload) { public string Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload)
{
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, false); SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, false);
try { try
{
string url = null; string url = null;
string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails)); string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails));
SurfaceContainer imageToUpload = new SurfaceContainer(surfaceToUpload, outputSettings, filename); SurfaceContainer imageToUpload = new SurfaceContainer(surfaceToUpload, outputSettings, filename);
new PleaseWaitForm().ShowAndWait("Box", Language.GetString("box", LangKey.communication_wait), new PleaseWaitForm().ShowAndWait("Box", Language.GetString("box", LangKey.communication_wait),
delegate { delegate { url = BoxUtils.UploadToBox(imageToUpload, captureDetails.Title, filename); }
url = BoxUtils.UploadToBox(imageToUpload, captureDetails.Title, filename);
}
); );
if (url != null && _config.AfterUploadLinkToClipBoard) { if (url != null && _config.AfterUploadLinkToClipBoard)
{
ClipboardHelper.SetClipboardData(url); ClipboardHelper.SetClipboardData(url);
} }
return url; return url;
} catch (Exception ex) { }
catch (Exception ex)
{
LOG.Error("Error uploading.", ex); LOG.Error("Error uploading.", ex);
MessageBox.Show(Language.GetString("box", LangKey.upload_failure) + " " + ex.Message); MessageBox.Show(Language.GetString("box", LangKey.upload_failure) + " " + ex.Message);
return null; return null;

View file

@ -27,12 +27,13 @@ using GreenshotPlugin.Core;
using GreenshotPlugin.Core.OAuth; using GreenshotPlugin.Core.OAuth;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.Box { namespace Greenshot.Plugin.Box
{
/// <summary> /// <summary>
/// Description of BoxUtils. /// Description of BoxUtils.
/// </summary> /// </summary>
public static class BoxUtils { public static class BoxUtils
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(BoxUtils)); private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(BoxUtils));
private static readonly BoxConfiguration Config = IniConfig.GetIniSection<BoxConfiguration>(); private static readonly BoxConfiguration Config = IniConfig.GetIniSection<BoxConfiguration>();
private const string UploadFileUri = "https://upload.box.com/api/2.0/files/content"; private const string UploadFileUri = "https://upload.box.com/api/2.0/files/content";
@ -45,13 +46,16 @@ namespace Greenshot.Plugin.Box {
/// <param name="content"></param> /// <param name="content"></param>
/// <param name="settings">OAuth2Settings</param> /// <param name="settings">OAuth2Settings</param>
/// <returns>response</returns> /// <returns>response</returns>
public static string HttpPut(string url, string content, OAuth2Settings settings) { public static string HttpPut(string url, string content, OAuth2Settings settings)
{
var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.PUT, url, settings); var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.PUT, url, settings);
byte[] data = Encoding.UTF8.GetBytes(content); byte[] data = Encoding.UTF8.GetBytes(content);
using (var requestStream = webRequest.GetRequestStream()) { using (var requestStream = webRequest.GetRequestStream())
{
requestStream.Write(data, 0, data.Length); requestStream.Write(data, 0, data.Length);
} }
return NetworkHelper.GetResponseAsString(webRequest); return NetworkHelper.GetResponseAsString(webRequest);
} }
@ -63,8 +67,8 @@ namespace Greenshot.Plugin.Box {
/// <param name="title">Title of box upload</param> /// <param name="title">Title of box upload</param>
/// <param name="filename">Filename of box upload</param> /// <param name="filename">Filename of box upload</param>
/// <returns>url to uploaded image</returns> /// <returns>url to uploaded image</returns>
public static string UploadToBox(SurfaceContainer image, string title, string filename) { public static string UploadToBox(SurfaceContainer image, string title, string filename)
{
// Fill the OAuth2Settings // Fill the OAuth2Settings
var settings = new OAuth2Settings var settings = new OAuth2Settings
{ {
@ -83,12 +87,17 @@ namespace Greenshot.Plugin.Box {
// Copy the settings from the config, which is kept in memory and on the disk // Copy the settings from the config, which is kept in memory and on the disk
try { try
{
var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, UploadFileUri, settings); var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, UploadFileUri, settings);
IDictionary<string, object> parameters = new Dictionary<string, object> IDictionary<string, object> parameters = new Dictionary<string, object>
{ {
{ "file", image }, {
{ "parent_id", Config.FolderId } "file", image
},
{
"parent_id", Config.FolderId
}
}; };
NetworkHelper.WriteMultipartFormData(webRequest, parameters); NetworkHelper.WriteMultipartFormData(webRequest, parameters);
@ -100,13 +109,17 @@ namespace Greenshot.Plugin.Box {
var upload = JsonSerializer.Deserialize<Upload>(response); var upload = JsonSerializer.Deserialize<Upload>(response);
if (upload?.Entries == null || upload.Entries.Count == 0) return null; if (upload?.Entries == null || upload.Entries.Count == 0) return null;
if (Config.UseSharedLink) { if (Config.UseSharedLink)
{
string filesResponse = HttpPut(string.Format(FilesUri, upload.Entries[0].Id), "{\"shared_link\": {\"access\": \"open\"}}", settings); string filesResponse = HttpPut(string.Format(FilesUri, upload.Entries[0].Id), "{\"shared_link\": {\"access\": \"open\"}}", settings);
var file = JsonSerializer.Deserialize<FileEntry>(filesResponse); var file = JsonSerializer.Deserialize<FileEntry>(filesResponse);
return file.SharedLink.Url; return file.SharedLink.Url;
} }
return $"http://www.box.com/files/0/f/0/1/f_{upload.Entries[0].Id}"; return $"http://www.box.com/files/0/f/0/1/f_{upload.Entries[0].Id}";
} finally { }
finally
{
// Copy the settings back to the config, so they are stored. // Copy the settings back to the config, so they are stored.
Config.RefreshToken = settings.RefreshToken; Config.RefreshToken = settings.RefreshToken;
Config.AccessToken = settings.AccessToken; Config.AccessToken = settings.AccessToken;
@ -116,17 +129,20 @@ namespace Greenshot.Plugin.Box {
} }
} }
} }
/// <summary> /// <summary>
/// A simple helper class for the DataContractJsonSerializer /// A simple helper class for the DataContractJsonSerializer
/// </summary> /// </summary>
internal static class JsonSerializer { internal static class JsonSerializer
{
/// <summary> /// <summary>
/// Helper method to parse JSON to object /// Helper method to parse JSON to object
/// </summary> /// </summary>
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
/// <param name="jsonString"></param> /// <param name="jsonString"></param>
/// <returns></returns> /// <returns></returns>
public static T Deserialize<T>(string jsonString) { public static T Deserialize<T>(string jsonString)
{
var deserializer = new DataContractJsonSerializer(typeof(T)); var deserializer = new DataContractJsonSerializer(typeof(T));
using var stream = new MemoryStream(); using var stream = new MemoryStream();
byte[] content = Encoding.UTF8.GetBytes(jsonString); byte[] content = Encoding.UTF8.GetBytes(jsonString);

View file

@ -21,7 +21,9 @@
using GreenshotPlugin.Controls; using GreenshotPlugin.Controls;
namespace Greenshot.Plugin.Box.Forms { namespace Greenshot.Plugin.Box.Forms
public class BoxForm : GreenshotForm { {
public class BoxForm : GreenshotForm
{
} }
} }

View file

@ -19,12 +19,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace Greenshot.Plugin.Box.Forms { namespace Greenshot.Plugin.Box.Forms
{
/// <summary> /// <summary>
/// Description of PasswordRequestForm. /// Description of PasswordRequestForm.
/// </summary> /// </summary>
public partial class SettingsForm : BoxForm { public partial class SettingsForm : BoxForm
public SettingsForm() { {
public SettingsForm()
{
// //
// The InitializeComponent() call is required for Windows Forms designer support. // The InitializeComponent() call is required for Windows Forms designer support.
// //

View file

@ -18,8 +18,11 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace Greenshot.Plugin.Box {
public enum LangKey { namespace Greenshot.Plugin.Box
{
public enum LangKey
{
upload_menu_item, upload_menu_item,
upload_failure, upload_failure,
communication_wait, communication_wait,

View file

@ -26,16 +26,21 @@ using GreenshotConfluencePlugin.confluence;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.Confluence { namespace Greenshot.Plugin.Confluence
public class Page { {
public Page(RemotePage page) { public class Page
{
public Page(RemotePage page)
{
Id = page.id; Id = page.id;
Title = page.title; Title = page.title;
SpaceKey = page.space; SpaceKey = page.space;
Url = page.url; Url = page.url;
Content = page.content; Content = page.content;
} }
public Page(RemoteSearchResult searchResult, string space) {
public Page(RemoteSearchResult searchResult, string space)
{
Id = searchResult.id; Id = searchResult.id;
Title = searchResult.title; Title = searchResult.title;
SpaceKey = space; SpaceKey = space;
@ -43,53 +48,39 @@ namespace Greenshot.Plugin.Confluence {
Content = searchResult.excerpt; Content = searchResult.excerpt;
} }
public Page(RemotePageSummary pageSummary) { public Page(RemotePageSummary pageSummary)
{
Id = pageSummary.id; Id = pageSummary.id;
Title = pageSummary.title; Title = pageSummary.title;
SpaceKey = pageSummary.space; SpaceKey = pageSummary.space;
Url = pageSummary.url; Url = pageSummary.url;
} }
public long Id {
get; public long Id { get; set; }
set; public string Title { get; set; }
public string Url { get; set; }
public string Content { get; set; }
public string SpaceKey { get; set; }
} }
public string Title {
get; public class Space
set; {
} public Space(RemoteSpaceSummary space)
public string Url { {
get;
set;
}
public string Content {
get;
set;
}
public string SpaceKey {
get;
set;
}
}
public class Space {
public Space(RemoteSpaceSummary space) {
Key = space.key; Key = space.key;
Name = space.name; Name = space.name;
} }
public string Key {
get; public string Key { get; set; }
set; public string Name { get; set; }
}
public string Name {
get;
set;
}
} }
/// <summary> /// <summary>
/// For details see the Confluence API site /// For details see the Confluence API site
/// See: http://confluence.atlassian.com/display/CONFDEV/Remote+API+Specification /// See: http://confluence.atlassian.com/display/CONFDEV/Remote+API+Specification
/// </summary> /// </summary>
public class ConfluenceConnector : IDisposable { public class ConfluenceConnector : IDisposable
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ConfluenceConnector)); private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ConfluenceConnector));
private const string AuthFailedExceptionName = "com.atlassian.confluence.rpc.AuthenticationFailedException"; private const string AuthFailedExceptionName = "com.atlassian.confluence.rpc.AuthenticationFailedException";
private const string V2Failed = "AXIS"; private const string V2Failed = "AXIS";
@ -102,29 +93,37 @@ namespace Greenshot.Plugin.Confluence {
private string _url; private string _url;
private readonly Cache<string, RemotePage> _pageCache = new Cache<string, RemotePage>(60 * Config.Timeout); private readonly Cache<string, RemotePage> _pageCache = new Cache<string, RemotePage>(60 * Config.Timeout);
public void Dispose() { public void Dispose()
{
Dispose(true); Dispose(true);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
protected void Dispose(bool disposing) { protected void Dispose(bool disposing)
if (_confluence != null) { {
if (_confluence != null)
{
Logout(); Logout();
} }
if (disposing) {
if (_confluence != null) { if (disposing)
{
if (_confluence != null)
{
_confluence.Dispose(); _confluence.Dispose();
_confluence = null; _confluence = null;
} }
} }
} }
public ConfluenceConnector(string url, int timeout) { public ConfluenceConnector(string url, int timeout)
{
_timeout = timeout; _timeout = timeout;
Init(url); Init(url);
} }
private void Init(string url) { private void Init(string url)
{
_url = url; _url = url;
_confluence = new ConfluenceSoapServiceService _confluence = new ConfluenceSoapServiceService
{ {
@ -133,7 +132,8 @@ namespace Greenshot.Plugin.Confluence {
}; };
} }
~ConfluenceConnector() { ~ConfluenceConnector()
{
Dispose(false); Dispose(false);
} }
@ -141,21 +141,29 @@ namespace Greenshot.Plugin.Confluence {
/// Internal login which catches the exceptions /// Internal login which catches the exceptions
/// </summary> /// </summary>
/// <returns>true if login was done sucessfully</returns> /// <returns>true if login was done sucessfully</returns>
private bool DoLogin(string user, string password) { private bool DoLogin(string user, string password)
try { {
try
{
_credentials = _confluence.login(user, password); _credentials = _confluence.login(user, password);
_loggedInTime = DateTime.Now; _loggedInTime = DateTime.Now;
_loggedIn = true; _loggedIn = true;
} catch (Exception e) { }
catch (Exception e)
{
// Check if confluence-v2 caused an error, use v1 instead // Check if confluence-v2 caused an error, use v1 instead
if (e.Message.Contains(V2Failed) && _url.Contains("v2")) { if (e.Message.Contains(V2Failed) && _url.Contains("v2"))
{
Init(_url.Replace("v2", "v1")); Init(_url.Replace("v2", "v1"));
return DoLogin(user, password); return DoLogin(user, password);
} }
// check if auth failed // check if auth failed
if (e.Message.Contains(AuthFailedExceptionName)) { if (e.Message.Contains(AuthFailedExceptionName))
{
return false; return false;
} }
// Not an authentication issue // Not an authentication issue
_loggedIn = false; _loggedIn = false;
_credentials = null; _credentials = null;
@ -163,12 +171,15 @@ namespace Greenshot.Plugin.Confluence {
e.Data.Add("url", _url); e.Data.Add("url", _url);
throw; throw;
} }
return true; return true;
} }
public void Login() { public void Login()
{
Logout(); Logout();
try { try
{
// Get the system name, so the user knows where to login to // Get the system name, so the user knows where to login to
string systemName = _url.Replace(ConfluenceConfiguration.DEFAULT_POSTFIX1, ""); string systemName = _url.Replace(ConfluenceConfiguration.DEFAULT_POSTFIX1, "");
systemName = systemName.Replace(ConfluenceConfiguration.DEFAULT_POSTFIX2, ""); systemName = systemName.Replace(ConfluenceConfiguration.DEFAULT_POSTFIX2, "");
@ -176,53 +187,73 @@ namespace Greenshot.Plugin.Confluence {
{ {
Name = null Name = null
}; };
while (dialog.Show(dialog.Name) == DialogResult.OK) { while (dialog.Show(dialog.Name) == DialogResult.OK)
if (DoLogin(dialog.Name, dialog.Password)) { {
if (dialog.SaveChecked) { if (DoLogin(dialog.Name, dialog.Password))
{
if (dialog.SaveChecked)
{
dialog.Confirm(true); dialog.Confirm(true);
} }
return; return;
} else { }
try { else
{
try
{
dialog.Confirm(false); dialog.Confirm(false);
} catch (ApplicationException e) { }
catch (ApplicationException e)
{
// exception handling ... // exception handling ...
Log.Error("Problem using the credentials dialog", e); Log.Error("Problem using the credentials dialog", e);
} }
// For every windows version after XP show an incorrect password baloon // For every windows version after XP show an incorrect password baloon
dialog.IncorrectPassword = true; dialog.IncorrectPassword = true;
// Make sure the dialog is display, the password was false! // Make sure the dialog is display, the password was false!
dialog.AlwaysDisplay = true; dialog.AlwaysDisplay = true;
} }
} }
} catch (ApplicationException e) { }
catch (ApplicationException e)
{
// exception handling ... // exception handling ...
Log.Error("Problem using the credentials dialog", e); Log.Error("Problem using the credentials dialog", e);
} }
} }
public void Logout() { public void Logout()
if (_credentials != null) { {
if (_credentials != null)
{
_confluence.logout(_credentials); _confluence.logout(_credentials);
_credentials = null; _credentials = null;
_loggedIn = false; _loggedIn = false;
} }
} }
private void CheckCredentials() { private void CheckCredentials()
if (_loggedIn) { {
if (_loggedInTime.AddMinutes(_timeout-1).CompareTo(DateTime.Now) < 0) { if (_loggedIn)
{
if (_loggedInTime.AddMinutes(_timeout - 1).CompareTo(DateTime.Now) < 0)
{
Logout(); Logout();
Login(); Login();
} }
} else { }
else
{
Login(); Login();
} }
} }
public bool IsLoggedIn => _loggedIn; public bool IsLoggedIn => _loggedIn;
public void AddAttachment(long pageId, string mime, string comment, string filename, IBinaryContainer image) { public void AddAttachment(long pageId, string mime, string comment, string filename, IBinaryContainer image)
{
CheckCredentials(); CheckCredentials();
// Comment is ignored, see: http://jira.atlassian.com/browse/CONF-9395 // Comment is ignored, see: http://jira.atlassian.com/browse/CONF-9395
var attachment = new RemoteAttachment var attachment = new RemoteAttachment
@ -234,69 +265,88 @@ namespace Greenshot.Plugin.Confluence {
_confluence.addAttachment(_credentials, pageId, attachment, image.ToByteArray()); _confluence.addAttachment(_credentials, pageId, attachment, image.ToByteArray());
} }
public Page GetPage(string spaceKey, string pageTitle) { public Page GetPage(string spaceKey, string pageTitle)
{
RemotePage page = null; RemotePage page = null;
string cacheKey = spaceKey + pageTitle; string cacheKey = spaceKey + pageTitle;
if (_pageCache.Contains(cacheKey)) { if (_pageCache.Contains(cacheKey))
{
page = _pageCache[cacheKey]; page = _pageCache[cacheKey];
} }
if (page == null) {
if (page == null)
{
CheckCredentials(); CheckCredentials();
page = _confluence.getPage(_credentials, spaceKey, pageTitle); page = _confluence.getPage(_credentials, spaceKey, pageTitle);
_pageCache.Add(cacheKey, page); _pageCache.Add(cacheKey, page);
} }
return new Page(page); return new Page(page);
} }
public Page GetPage(long pageId) { public Page GetPage(long pageId)
{
RemotePage page = null; RemotePage page = null;
string cacheKey = pageId.ToString(); string cacheKey = pageId.ToString();
if (_pageCache.Contains(cacheKey)) { if (_pageCache.Contains(cacheKey))
{
page = _pageCache[cacheKey]; page = _pageCache[cacheKey];
} }
if (page == null) {
if (page == null)
{
CheckCredentials(); CheckCredentials();
page = _confluence.getPage(_credentials, pageId); page = _confluence.getPage(_credentials, pageId);
_pageCache.Add(cacheKey, page); _pageCache.Add(cacheKey, page);
} }
return new Page(page); return new Page(page);
} }
public Page GetSpaceHomepage(Space spaceSummary) { public Page GetSpaceHomepage(Space spaceSummary)
{
CheckCredentials(); CheckCredentials();
RemoteSpace spaceDetail = _confluence.getSpace(_credentials, spaceSummary.Key); RemoteSpace spaceDetail = _confluence.getSpace(_credentials, spaceSummary.Key);
RemotePage page = _confluence.getPage(_credentials, spaceDetail.homePage); RemotePage page = _confluence.getPage(_credentials, spaceDetail.homePage);
return new Page(page); return new Page(page);
} }
public IEnumerable<Space> GetSpaceSummaries() { public IEnumerable<Space> GetSpaceSummaries()
{
CheckCredentials(); CheckCredentials();
RemoteSpaceSummary[] spaces = _confluence.getSpaces(_credentials); RemoteSpaceSummary[] spaces = _confluence.getSpaces(_credentials);
foreach(RemoteSpaceSummary space in spaces) { foreach (RemoteSpaceSummary space in spaces)
{
yield return new Space(space); yield return new Space(space);
} }
} }
public IEnumerable<Page> GetPageChildren(Page parentPage) { public IEnumerable<Page> GetPageChildren(Page parentPage)
{
CheckCredentials(); CheckCredentials();
RemotePageSummary[] pages = _confluence.getChildren(_credentials, parentPage.Id); RemotePageSummary[] pages = _confluence.getChildren(_credentials, parentPage.Id);
foreach(RemotePageSummary page in pages) { foreach (RemotePageSummary page in pages)
{
yield return new Page(page); yield return new Page(page);
} }
} }
public IEnumerable<Page> GetPageSummaries(Space space) { public IEnumerable<Page> GetPageSummaries(Space space)
{
CheckCredentials(); CheckCredentials();
RemotePageSummary[] pages = _confluence.getPages(_credentials, space.Key); RemotePageSummary[] pages = _confluence.getPages(_credentials, space.Key);
foreach(RemotePageSummary page in pages) { foreach (RemotePageSummary page in pages)
{
yield return new Page(page); yield return new Page(page);
} }
} }
public IEnumerable<Page> SearchPages(string query, string space) { public IEnumerable<Page> SearchPages(string query, string space)
{
CheckCredentials(); CheckCredentials();
foreach(var searchResult in _confluence.search(_credentials, query, 20)) { foreach (var searchResult in _confluence.search(_credentials, query, 20))
{
Log.DebugFormat("Got result of type {0}", searchResult.type); Log.DebugFormat("Got result of type {0}", searchResult.type);
if ("page".Equals(searchResult.type)) if ("page".Equals(searchResult.type))
{ {

View file

@ -23,63 +23,45 @@ using System;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.Confluence { namespace Greenshot.Plugin.Confluence
{
/// <summary> /// <summary>
/// Description of ConfluenceConfiguration. /// Description of ConfluenceConfiguration.
/// </summary> /// </summary>
[Serializable] [Serializable]
[IniSection("Confluence", Description = "Greenshot Confluence Plugin configuration")] [IniSection("Confluence", Description = "Greenshot Confluence Plugin configuration")]
public class ConfluenceConfiguration : IniSection { public class ConfluenceConfiguration : IniSection
{
public const string DEFAULT_POSTFIX1 = "/rpc/soap-axis/confluenceservice-v1?wsdl"; public const string DEFAULT_POSTFIX1 = "/rpc/soap-axis/confluenceservice-v1?wsdl";
public const string DEFAULT_POSTFIX2 = "/rpc/soap-axis/confluenceservice-v2?wsdl"; public const string DEFAULT_POSTFIX2 = "/rpc/soap-axis/confluenceservice-v2?wsdl";
public const string DEFAULT_PREFIX = "http://"; public const string DEFAULT_PREFIX = "http://";
private const string DEFAULT_URL = DEFAULT_PREFIX + "confluence"; private const string DEFAULT_URL = DEFAULT_PREFIX + "confluence";
[IniProperty("Url", Description = "Url to Confluence system, including wsdl.", DefaultValue = DEFAULT_URL)] [IniProperty("Url", Description = "Url to Confluence system, including wsdl.", DefaultValue = DEFAULT_URL)]
public string Url { public string Url { get; set; }
get;
set;
}
[IniProperty("Timeout", Description = "Session timeout in minutes", DefaultValue = "30")] [IniProperty("Timeout", Description = "Session timeout in minutes", DefaultValue = "30")]
public int Timeout { public int Timeout { get; set; }
get;
set;
}
[IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")]
public OutputFormat UploadFormat { public OutputFormat UploadFormat { get; set; }
get;
set;
}
[IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")]
public int UploadJpegQuality { public int UploadJpegQuality { get; set; }
get;
set;
}
[IniProperty("UploadReduceColors", Description = "Reduce color amount of the uploaded image to 256", DefaultValue = "False")] [IniProperty("UploadReduceColors", Description = "Reduce color amount of the uploaded image to 256", DefaultValue = "False")]
public bool UploadReduceColors { public bool UploadReduceColors { get; set; }
get;
set;
}
[IniProperty("OpenPageAfterUpload", Description = "Open the page where the picture is uploaded after upload", DefaultValue = "True")] [IniProperty("OpenPageAfterUpload", Description = "Open the page where the picture is uploaded after upload", DefaultValue = "True")]
public bool OpenPageAfterUpload { public bool OpenPageAfterUpload { get; set; }
get;
set;
}
[IniProperty("CopyWikiMarkupForImageToClipboard", Description = "Copy the Wikimarkup for the recently uploaded image to the Clipboard", DefaultValue = "True")] [IniProperty("CopyWikiMarkupForImageToClipboard", Description = "Copy the Wikimarkup for the recently uploaded image to the Clipboard", DefaultValue = "True")]
public bool CopyWikiMarkupForImageToClipboard { public bool CopyWikiMarkupForImageToClipboard { get; set; }
get;
set;
}
[IniProperty("SearchSpaceKey", Description = "Key of last space that was searched for")] [IniProperty("SearchSpaceKey", Description = "Key of last space that was searched for")]
public string SearchSpaceKey { public string SearchSpaceKey { get; set; }
get;
set;
}
[IniProperty("IncludePersonSpaces", Description = "Include personal spaces in the search & browse spaces list", DefaultValue = "False")] [IniProperty("IncludePersonSpaces", Description = "Include personal spaces in the search & browse spaces list", DefaultValue = "False")]
public bool IncludePersonSpaces { public bool IncludePersonSpaces { get; set; }
get;
set;
}
} }
} }

View file

@ -32,121 +32,145 @@ using GreenshotPlugin.IniFile;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin; using GreenshotPlugin.Interfaces.Plugin;
namespace Greenshot.Plugin.Confluence { namespace Greenshot.Plugin.Confluence
{
/// <summary> /// <summary>
/// Description of ConfluenceDestination. /// Description of ConfluenceDestination.
/// </summary> /// </summary>
public class ConfluenceDestination : AbstractDestination { public class ConfluenceDestination : AbstractDestination
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ConfluenceDestination)); private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ConfluenceDestination));
private static readonly ConfluenceConfiguration ConfluenceConfig = IniConfig.GetIniSection<ConfluenceConfiguration>(); private static readonly ConfluenceConfiguration ConfluenceConfig = IniConfig.GetIniSection<ConfluenceConfiguration>();
private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>(); private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>();
private static readonly Image ConfluenceIcon; private static readonly Image ConfluenceIcon;
private readonly Page _page; private readonly Page _page;
static ConfluenceDestination() { static ConfluenceDestination()
{
IsInitialized = false; IsInitialized = false;
try { try
{
Uri confluenceIconUri = new Uri("/GreenshotConfluencePlugin;component/Images/Confluence.ico", UriKind.Relative); Uri confluenceIconUri = new Uri("/GreenshotConfluencePlugin;component/Images/Confluence.ico", UriKind.Relative);
using (Stream iconStream = Application.GetResourceStream(confluenceIconUri)?.Stream) using (Stream iconStream = Application.GetResourceStream(confluenceIconUri)?.Stream)
{ {
// TODO: Check what to do with the IImage // TODO: Check what to do with the IImage
ConfluenceIcon = ImageHelper.FromStream(iconStream); ConfluenceIcon = ImageHelper.FromStream(iconStream);
} }
IsInitialized = true; IsInitialized = true;
} catch (Exception ex) { }
catch (Exception ex)
{
Log.ErrorFormat("Problem in the confluence static initializer: {0}", ex.Message); Log.ErrorFormat("Problem in the confluence static initializer: {0}", ex.Message);
} }
} }
public static bool IsInitialized public static bool IsInitialized { get; private set; }
public ConfluenceDestination()
{ {
get;
private set;
} }
public ConfluenceDestination() { public ConfluenceDestination(Page page)
} {
public ConfluenceDestination(Page page) {
_page = page; _page = page;
} }
public override string Designation { public override string Designation
get { {
return "Confluence"; get { return "Confluence"; }
}
} }
public override string Description { public override string Description
get { {
if (_page == null) { get
{
if (_page == null)
{
return Language.GetString("confluence", LangKey.upload_menu_item); return Language.GetString("confluence", LangKey.upload_menu_item);
} else { }
else
{
return Language.GetString("confluence", LangKey.upload_menu_item) + ": \"" + _page.Title + "\""; return Language.GetString("confluence", LangKey.upload_menu_item) + ": \"" + _page.Title + "\"";
} }
} }
} }
public override bool IsDynamic { public override bool IsDynamic
get { {
return true; get { return true; }
}
} }
public override bool IsActive { public override bool IsActive
get { {
return base.IsActive && !string.IsNullOrEmpty(ConfluenceConfig.Url); get { return base.IsActive && !string.IsNullOrEmpty(ConfluenceConfig.Url); }
}
} }
public override Image DisplayIcon { public override Image DisplayIcon
get { {
return ConfluenceIcon; get { return ConfluenceIcon; }
}
} }
public override IEnumerable<IDestination> DynamicDestinations() { public override IEnumerable<IDestination> DynamicDestinations()
if (ConfluencePlugin.ConfluenceConnectorNoLogin == null || !ConfluencePlugin.ConfluenceConnectorNoLogin.IsLoggedIn) { {
if (ConfluencePlugin.ConfluenceConnectorNoLogin == null || !ConfluencePlugin.ConfluenceConnectorNoLogin.IsLoggedIn)
{
yield break; yield break;
} }
List<Page> currentPages = ConfluenceUtils.GetCurrentPages(); List<Page> currentPages = ConfluenceUtils.GetCurrentPages();
if (currentPages == null || currentPages.Count == 0) { if (currentPages == null || currentPages.Count == 0)
{
yield break; yield break;
} }
foreach(Page currentPage in currentPages) {
foreach (Page currentPage in currentPages)
{
yield return new ConfluenceDestination(currentPage); yield return new ConfluenceDestination(currentPage);
} }
} }
public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails)
{
ExportInformation exportInformation = new ExportInformation(Designation, Description); ExportInformation exportInformation = new ExportInformation(Designation, Description);
// force password check to take place before the pages load // force password check to take place before the pages load
if (!ConfluencePlugin.ConfluenceConnector.IsLoggedIn) { if (!ConfluencePlugin.ConfluenceConnector.IsLoggedIn)
{
return exportInformation; return exportInformation;
} }
Page selectedPage = _page; Page selectedPage = _page;
bool openPage = (_page == null) && ConfluenceConfig.OpenPageAfterUpload; bool openPage = (_page == null) && ConfluenceConfig.OpenPageAfterUpload;
string filename = FilenameHelper.GetFilenameWithoutExtensionFromPattern(CoreConfig.OutputFileFilenamePattern, captureDetails); string filename = FilenameHelper.GetFilenameWithoutExtensionFromPattern(CoreConfig.OutputFileFilenamePattern, captureDetails);
if (selectedPage == null) { if (selectedPage == null)
{
Forms.ConfluenceUpload confluenceUpload = new Forms.ConfluenceUpload(filename); Forms.ConfluenceUpload confluenceUpload = new Forms.ConfluenceUpload(filename);
bool? dialogResult = confluenceUpload.ShowDialog(); bool? dialogResult = confluenceUpload.ShowDialog();
if (dialogResult.HasValue && dialogResult.Value) { if (dialogResult.HasValue && dialogResult.Value)
{
selectedPage = confluenceUpload.SelectedPage; selectedPage = confluenceUpload.SelectedPage;
if (confluenceUpload.IsOpenPageSelected) { if (confluenceUpload.IsOpenPageSelected)
{
openPage = false; openPage = false;
} }
filename = confluenceUpload.Filename; filename = confluenceUpload.Filename;
} }
} }
string extension = "." + ConfluenceConfig.UploadFormat; string extension = "." + ConfluenceConfig.UploadFormat;
if (!filename.ToLower().EndsWith(extension)) { if (!filename.ToLower().EndsWith(extension))
{
filename += extension; filename += extension;
} }
if (selectedPage != null) {
if (selectedPage != null)
{
bool uploaded = Upload(surface, selectedPage, filename, out var errorMessage); bool uploaded = Upload(surface, selectedPage, filename, out var errorMessage);
if (uploaded) { if (uploaded)
if (openPage) { {
if (openPage)
{
try try
{ {
Process.Start(selectedPage.Url); Process.Start(selectedPage.Url);
@ -156,23 +180,32 @@ namespace Greenshot.Plugin.Confluence {
// Ignore // Ignore
} }
} }
exportInformation.ExportMade = true; exportInformation.ExportMade = true;
exportInformation.Uri = selectedPage.Url; exportInformation.Uri = selectedPage.Url;
} else { }
else
{
exportInformation.ErrorMessage = errorMessage; exportInformation.ErrorMessage = errorMessage;
} }
} }
ProcessExport(exportInformation, surface); ProcessExport(exportInformation, surface);
return exportInformation; return exportInformation;
} }
private bool Upload(ISurface surfaceToUpload, Page page, string filename, out string errorMessage) { private bool Upload(ISurface surfaceToUpload, Page page, string filename, out string errorMessage)
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(ConfluenceConfig.UploadFormat, ConfluenceConfig.UploadJpegQuality, ConfluenceConfig.UploadReduceColors); {
SurfaceOutputSettings outputSettings =
new SurfaceOutputSettings(ConfluenceConfig.UploadFormat, ConfluenceConfig.UploadJpegQuality, ConfluenceConfig.UploadReduceColors);
errorMessage = null; errorMessage = null;
try { try
{
new PleaseWaitForm().ShowAndWait(Description, Language.GetString("confluence", LangKey.communication_wait), new PleaseWaitForm().ShowAndWait(Description, Language.GetString("confluence", LangKey.communication_wait),
delegate { delegate
ConfluencePlugin.ConfluenceConnector.AddAttachment(page.Id, "image/" + ConfluenceConfig.UploadFormat.ToString().ToLower(), null, filename, new SurfaceContainer(surfaceToUpload, outputSettings, filename)); {
ConfluencePlugin.ConfluenceConnector.AddAttachment(page.Id, "image/" + ConfluenceConfig.UploadFormat.ToString().ToLower(), null, filename,
new SurfaceContainer(surfaceToUpload, outputSettings, filename));
} }
); );
Log.Debug("Uploaded to Confluence."); Log.Debug("Uploaded to Confluence.");
@ -180,25 +213,39 @@ namespace Greenshot.Plugin.Confluence {
{ {
return true; return true;
} }
int retryCount = 2; int retryCount = 2;
while (retryCount >= 0) { while (retryCount >= 0)
try { {
try
{
Clipboard.SetText("!" + filename + "!"); Clipboard.SetText("!" + filename + "!");
break; break;
} catch (Exception ee) { }
if (retryCount == 0) { catch (Exception ee)
{
if (retryCount == 0)
{
Log.Error(ee); Log.Error(ee);
} else { }
else
{
Thread.Sleep(100); Thread.Sleep(100);
} }
} finally { }
finally
{
--retryCount; --retryCount;
} }
} }
return true; return true;
} catch(Exception e) { }
catch (Exception e)
{
errorMessage = e.Message; errorMessage = e.Message;
} }
return false; return false;
} }
} }

View file

@ -28,53 +28,70 @@ using GreenshotPlugin.IniFile;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin; using GreenshotPlugin.Interfaces.Plugin;
namespace Greenshot.Plugin.Confluence { namespace Greenshot.Plugin.Confluence
{
/// <summary> /// <summary>
/// This is the ConfluencePlugin base code /// This is the ConfluencePlugin base code
/// </summary> /// </summary>
[Plugin("Confluence", true)] [Plugin("Confluence", true)]
public class ConfluencePlugin : IGreenshotPlugin { public class ConfluencePlugin : IGreenshotPlugin
{
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ConfluencePlugin)); private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ConfluencePlugin));
private static ConfluenceConnector _confluenceConnector; private static ConfluenceConnector _confluenceConnector;
private static ConfluenceConfiguration _config; private static ConfluenceConfiguration _config;
public void Dispose() { public void Dispose()
{
Dispose(true); Dispose(true);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
protected void Dispose(bool disposing) { protected void Dispose(bool disposing)
{
//if (disposing) {} //if (disposing) {}
} }
private static void CreateConfluenceConnector() { private static void CreateConfluenceConnector()
if (_confluenceConnector == null) { {
if (_config.Url.Contains("soap-axis")) { if (_confluenceConnector == null)
{
if (_config.Url.Contains("soap-axis"))
{
_confluenceConnector = new ConfluenceConnector(_config.Url, _config.Timeout); _confluenceConnector = new ConfluenceConnector(_config.Url, _config.Timeout);
} else { }
else
{
_confluenceConnector = new ConfluenceConnector(_config.Url + ConfluenceConfiguration.DEFAULT_POSTFIX2, _config.Timeout); _confluenceConnector = new ConfluenceConnector(_config.Url + ConfluenceConfiguration.DEFAULT_POSTFIX2, _config.Timeout);
} }
} }
} }
public static ConfluenceConnector ConfluenceConnectorNoLogin { public static ConfluenceConnector ConfluenceConnectorNoLogin
get { {
return _confluenceConnector; get { return _confluenceConnector; }
}
} }
public static ConfluenceConnector ConfluenceConnector { public static ConfluenceConnector ConfluenceConnector
get { {
if (_confluenceConnector == null) { get
{
if (_confluenceConnector == null)
{
CreateConfluenceConnector(); CreateConfluenceConnector();
} }
try {
if (_confluenceConnector != null && !_confluenceConnector.IsLoggedIn) { try
{
if (_confluenceConnector != null && !_confluenceConnector.IsLoggedIn)
{
_confluenceConnector.Login(); _confluenceConnector.Login();
} }
} catch (Exception e) { }
catch (Exception e)
{
MessageBox.Show(Language.GetFormattedString("confluence", LangKey.login_error, e.Message)); MessageBox.Show(Language.GetFormattedString("confluence", LangKey.login_error, e.Message));
} }
return _confluenceConnector; return _confluenceConnector;
} }
} }
@ -82,29 +99,39 @@ namespace Greenshot.Plugin.Confluence {
/// <summary> /// <summary>
/// Implementation of the IGreenshotPlugin.Initialize /// Implementation of the IGreenshotPlugin.Initialize
/// </summary> /// </summary>
public bool Initialize() { public bool Initialize()
{
// Register configuration (don't need the configuration itself) // Register configuration (don't need the configuration itself)
_config = IniConfig.GetIniSection<ConfluenceConfiguration>(); _config = IniConfig.GetIniSection<ConfluenceConfiguration>();
if(_config.IsDirty) { if (_config.IsDirty)
{
IniConfig.Save(); IniConfig.Save();
} }
try {
try
{
TranslationManager.Instance.TranslationProvider = new LanguageXMLTranslationProvider(); TranslationManager.Instance.TranslationProvider = new LanguageXMLTranslationProvider();
//resources = new ComponentResourceManager(typeof(ConfluencePlugin)); //resources = new ComponentResourceManager(typeof(ConfluencePlugin));
} catch (Exception ex) { }
catch (Exception ex)
{
LOG.ErrorFormat("Problem in ConfluencePlugin.Initialize: {0}", ex.Message); LOG.ErrorFormat("Problem in ConfluencePlugin.Initialize: {0}", ex.Message);
return false; return false;
} }
if (ConfluenceDestination.IsInitialized) if (ConfluenceDestination.IsInitialized)
{ {
SimpleServiceProvider.Current.AddService<IDestination>(new ConfluenceDestination()); SimpleServiceProvider.Current.AddService<IDestination>(new ConfluenceDestination());
} }
return true; return true;
} }
public void Shutdown() { public void Shutdown()
{
LOG.Debug("Confluence Plugin shutdown."); LOG.Debug("Confluence Plugin shutdown.");
if (_confluenceConnector != null) { if (_confluenceConnector != null)
{
_confluenceConnector.Logout(); _confluenceConnector.Logout();
_confluenceConnector = null; _confluenceConnector = null;
} }
@ -113,20 +140,26 @@ namespace Greenshot.Plugin.Confluence {
/// <summary> /// <summary>
/// Implementation of the IPlugin.Configure /// Implementation of the IPlugin.Configure
/// </summary> /// </summary>
public void Configure() { public void Configure()
{
ConfluenceConfiguration clonedConfig = _config.Clone(); ConfluenceConfiguration clonedConfig = _config.Clone();
ConfluenceConfigurationForm configForm = new ConfluenceConfigurationForm(clonedConfig); ConfluenceConfigurationForm configForm = new ConfluenceConfigurationForm(clonedConfig);
string url = _config.Url; string url = _config.Url;
bool? dialogResult = configForm.ShowDialog(); bool? dialogResult = configForm.ShowDialog();
if (dialogResult.HasValue && dialogResult.Value) { if (dialogResult.HasValue && dialogResult.Value)
{
// copy the new object to the old... // copy the new object to the old...
clonedConfig.CloneTo(_config); clonedConfig.CloneTo(_config);
IniConfig.Save(); IniConfig.Save();
if (_confluenceConnector != null) { if (_confluenceConnector != null)
if (!url.Equals(_config.Url)) { {
if (_confluenceConnector.IsLoggedIn) { if (!url.Equals(_config.Url))
{
if (_confluenceConnector.IsLoggedIn)
{
_confluenceConnector.Logout(); _confluenceConnector.Logout();
} }
_confluenceConnector = null; _confluenceConnector = null;
} }
} }

View file

@ -26,76 +26,106 @@ using System.Text.RegularExpressions;
using System.Windows.Automation; using System.Windows.Automation;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
namespace Greenshot.Plugin.Confluence { namespace Greenshot.Plugin.Confluence
{
/// <summary> /// <summary>
/// Description of ConfluenceUtils. /// Description of ConfluenceUtils.
/// </summary> /// </summary>
public class ConfluenceUtils { public class ConfluenceUtils
{
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ConfluenceUtils)); private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ConfluenceUtils));
public static List<Page> GetCurrentPages() { public static List<Page> GetCurrentPages()
{
List<Page> pages = new List<Page>(); List<Page> pages = new List<Page>();
Regex pageIdRegex = new Regex(@"pageId=(\d+)"); Regex pageIdRegex = new Regex(@"pageId=(\d+)");
Regex spacePageRegex = new Regex(@"\/display\/([^\/]+)\/([^#]+)"); Regex spacePageRegex = new Regex(@"\/display\/([^\/]+)\/([^#]+)");
foreach(string browserurl in GetBrowserUrls()) { foreach (string browserurl in GetBrowserUrls())
{
string url; string url;
try { try
{
url = Uri.UnescapeDataString(browserurl).Replace("+", " "); url = Uri.UnescapeDataString(browserurl).Replace("+", " ");
} catch { }
catch
{
LOG.WarnFormat("Error processing URL: {0}", browserurl); LOG.WarnFormat("Error processing URL: {0}", browserurl);
continue; continue;
} }
MatchCollection pageIdMatch = pageIdRegex.Matches(url); MatchCollection pageIdMatch = pageIdRegex.Matches(url);
if (pageIdMatch != null && pageIdMatch.Count > 0) { if (pageIdMatch != null && pageIdMatch.Count > 0)
{
long pageId = long.Parse(pageIdMatch[0].Groups[1].Value); long pageId = long.Parse(pageIdMatch[0].Groups[1].Value);
try { try
{
bool pageDouble = false; bool pageDouble = false;
foreach(Page page in pages) { foreach (Page page in pages)
if (page.Id == pageId) { {
if (page.Id == pageId)
{
pageDouble = true; pageDouble = true;
LOG.DebugFormat("Skipping double page with ID {0}", pageId); LOG.DebugFormat("Skipping double page with ID {0}", pageId);
break; break;
} }
} }
if (!pageDouble) {
if (!pageDouble)
{
Page page = ConfluencePlugin.ConfluenceConnector.GetPage(pageId); Page page = ConfluencePlugin.ConfluenceConnector.GetPage(pageId);
LOG.DebugFormat("Adding page {0}", page.Title); LOG.DebugFormat("Adding page {0}", page.Title);
pages.Add(page); pages.Add(page);
} }
continue; continue;
} catch (Exception ex) { }
catch (Exception ex)
{
// Preventing security problems // Preventing security problems
LOG.DebugFormat("Couldn't get page details for PageID {0}", pageId); LOG.DebugFormat("Couldn't get page details for PageID {0}", pageId);
LOG.Warn(ex); LOG.Warn(ex);
} }
} }
MatchCollection spacePageMatch = spacePageRegex.Matches(url); MatchCollection spacePageMatch = spacePageRegex.Matches(url);
if (spacePageMatch != null && spacePageMatch.Count > 0) { if (spacePageMatch != null && spacePageMatch.Count > 0)
if (spacePageMatch[0].Groups.Count >= 2) { {
if (spacePageMatch[0].Groups.Count >= 2)
{
string space = spacePageMatch[0].Groups[1].Value; string space = spacePageMatch[0].Groups[1].Value;
string title = spacePageMatch[0].Groups[2].Value; string title = spacePageMatch[0].Groups[2].Value;
if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(space)) { if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(space))
{
continue; continue;
} }
if (title.EndsWith("#")) {
if (title.EndsWith("#"))
{
title = title.Substring(0, title.Length - 1); title = title.Substring(0, title.Length - 1);
} }
try {
try
{
bool pageDouble = false; bool pageDouble = false;
foreach(Page page in pages) { foreach (Page page in pages)
if (page.Title.Equals(title)) { {
if (page.Title.Equals(title))
{
LOG.DebugFormat("Skipping double page with title {0}", title); LOG.DebugFormat("Skipping double page with title {0}", title);
pageDouble = true; pageDouble = true;
break; break;
} }
} }
if (!pageDouble) {
if (!pageDouble)
{
Page page = ConfluencePlugin.ConfluenceConnector.GetPage(space, title); Page page = ConfluencePlugin.ConfluenceConnector.GetPage(space, title);
LOG.DebugFormat("Adding page {0}", page.Title); LOG.DebugFormat("Adding page {0}", page.Title);
pages.Add(page); pages.Add(page);
} }
} catch (Exception ex) { }
catch (Exception ex)
{
// Preventing security problems // Preventing security problems
LOG.DebugFormat("Couldn't get page details for space {0} / title {1}", space, title); LOG.DebugFormat("Couldn't get page details for space {0} / title {1}", space, title);
LOG.Warn(ex); LOG.Warn(ex);
@ -103,49 +133,65 @@ namespace Greenshot.Plugin.Confluence {
} }
} }
} }
return pages; return pages;
} }
private static IEnumerable<string> GetBrowserUrls() { private static IEnumerable<string> GetBrowserUrls()
{
HashSet<string> urls = new HashSet<string>(); HashSet<string> urls = new HashSet<string>();
// FireFox // FireFox
foreach (WindowDetails window in WindowDetails.GetAllWindows("MozillaWindowClass")) { foreach (WindowDetails window in WindowDetails.GetAllWindows("MozillaWindowClass"))
if (window.Text.Length == 0) { {
continue; if (window.Text.Length == 0)
} {
AutomationElement currentElement = AutomationElement.FromHandle(window.Handle);
Condition conditionCustom = new AndCondition(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Custom), new PropertyCondition(AutomationElement.IsOffscreenProperty, false));
for (int i = 5; i > 0 && currentElement != null; i--) {
currentElement = currentElement.FindFirst(TreeScope.Children, conditionCustom);
}
if (currentElement == null) {
continue; continue;
} }
Condition conditionDocument = new AndCondition(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Document), new PropertyCondition(AutomationElement.IsOffscreenProperty, false)); AutomationElement currentElement = AutomationElement.FromHandle(window.Handle);
Condition conditionCustom = new AndCondition(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Custom),
new PropertyCondition(AutomationElement.IsOffscreenProperty, false));
for (int i = 5; i > 0 && currentElement != null; i--)
{
currentElement = currentElement.FindFirst(TreeScope.Children, conditionCustom);
}
if (currentElement == null)
{
continue;
}
Condition conditionDocument = new AndCondition(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Document),
new PropertyCondition(AutomationElement.IsOffscreenProperty, false));
AutomationElement docElement = currentElement.FindFirst(TreeScope.Children, conditionDocument); AutomationElement docElement = currentElement.FindFirst(TreeScope.Children, conditionDocument);
if (docElement == null) { if (docElement == null)
{
continue; continue;
} }
foreach (AutomationPattern pattern in docElement.GetSupportedPatterns()) {
if (pattern.ProgrammaticName != "ValuePatternIdentifiers.Pattern") { foreach (AutomationPattern pattern in docElement.GetSupportedPatterns())
{
if (pattern.ProgrammaticName != "ValuePatternIdentifiers.Pattern")
{
continue; continue;
} }
string url = (docElement.GetCurrentPattern(pattern) as ValuePattern).Current.Value; string url = (docElement.GetCurrentPattern(pattern) as ValuePattern).Current.Value;
if (!string.IsNullOrEmpty(url)) { if (!string.IsNullOrEmpty(url))
{
urls.Add(url); urls.Add(url);
break; break;
} }
} }
} }
foreach(string url in IEHelper.GetIEUrls().Distinct()) { foreach (string url in IEHelper.GetIEUrls().Distinct())
{
urls.Add(url); urls.Add(url);
} }
return urls; return urls;
} }
} }
} }

View file

@ -28,24 +28,32 @@ using System.Reflection;
using System.Windows.Data; using System.Windows.Data;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
namespace Greenshot.Plugin.Confluence { namespace Greenshot.Plugin.Confluence
public class EnumDisplayer : IValueConverter { {
public class EnumDisplayer : IValueConverter
{
private Type _type; private Type _type;
private IDictionary _displayValues; private IDictionary _displayValues;
private IDictionary _reverseValues; private IDictionary _reverseValues;
public Type Type { public Type Type
{
get { return _type; } get { return _type; }
set { set
if (!value.IsEnum) { {
if (!value.IsEnum)
{
throw new ArgumentException("parameter is not an Enumerated type", nameof(value)); throw new ArgumentException("parameter is not an Enumerated type", nameof(value));
} }
_type = value; _type = value;
} }
} }
public ReadOnlyCollection<string> DisplayNames { public ReadOnlyCollection<string> DisplayNames
get { {
get
{
var genericTypeDefinition = typeof(Dictionary<,>).GetGenericTypeDefinition(); var genericTypeDefinition = typeof(Dictionary<,>).GetGenericTypeDefinition();
if (genericTypeDefinition != null) if (genericTypeDefinition != null)
{ {
@ -59,38 +67,47 @@ namespace Greenshot.Plugin.Confluence {
} }
var fields = _type.GetFields(BindingFlags.Public | BindingFlags.Static); var fields = _type.GetFields(BindingFlags.Public | BindingFlags.Static);
foreach (var field in fields) { foreach (var field in fields)
{
DisplayKeyAttribute[] a = (DisplayKeyAttribute[]) field.GetCustomAttributes(typeof(DisplayKeyAttribute), false); DisplayKeyAttribute[] a = (DisplayKeyAttribute[]) field.GetCustomAttributes(typeof(DisplayKeyAttribute), false);
string displayKey = GetDisplayKeyValue(a); string displayKey = GetDisplayKeyValue(a);
object enumValue = field.GetValue(null); object enumValue = field.GetValue(null);
string displayString; string displayString;
if (displayKey != null && Language.HasKey(displayKey)) { if (displayKey != null && Language.HasKey(displayKey))
{
displayString = Language.GetString(displayKey); displayString = Language.GetString(displayKey);
} }
displayString = displayKey ?? enumValue.ToString(); displayString = displayKey ?? enumValue.ToString();
_displayValues.Add(enumValue, displayString); _displayValues.Add(enumValue, displayString);
_reverseValues.Add(displayString, enumValue); _reverseValues.Add(displayString, enumValue);
} }
return new List<string>((IEnumerable<string>) _displayValues.Values).AsReadOnly(); return new List<string>((IEnumerable<string>) _displayValues.Values).AsReadOnly();
} }
} }
private static string GetDisplayKeyValue(DisplayKeyAttribute[] a) { private static string GetDisplayKeyValue(DisplayKeyAttribute[] a)
if (a == null || a.Length == 0) { {
if (a == null || a.Length == 0)
{
return null; return null;
} }
DisplayKeyAttribute dka = a[0]; DisplayKeyAttribute dka = a[0];
return dka.Value; return dka.Value;
} }
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) { object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return _displayValues[value]; return _displayValues[value];
} }
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return _reverseValues[value]; return _reverseValues[value];
} }
} }

View file

@ -21,20 +21,24 @@
using System.Windows; using System.Windows;
namespace Greenshot.Plugin.Confluence.Forms { namespace Greenshot.Plugin.Confluence.Forms
{
/// <summary> /// <summary>
/// Interaction logic for ConfluenceConfigurationForm.xaml /// Interaction logic for ConfluenceConfigurationForm.xaml
/// </summary> /// </summary>
public partial class ConfluenceConfigurationForm : Window { public partial class ConfluenceConfigurationForm : Window
{
public ConfluenceConfiguration Config { get; } public ConfluenceConfiguration Config { get; }
public ConfluenceConfigurationForm(ConfluenceConfiguration config) { public ConfluenceConfigurationForm(ConfluenceConfiguration config)
{
DataContext = config; DataContext = config;
Config = config; Config = config;
InitializeComponent(); InitializeComponent();
} }
private void Button_OK_Click(object sender, RoutedEventArgs e) { private void Button_OK_Click(object sender, RoutedEventArgs e)
{
DialogResult = true; DialogResult = true;
} }
} }

View file

@ -21,7 +21,8 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace Greenshot.Plugin.Confluence.Forms { namespace Greenshot.Plugin.Confluence.Forms
{
/// <summary> /// <summary>
/// Interaction logic for ConfluencePagePicker.xaml /// Interaction logic for ConfluencePagePicker.xaml
/// </summary> /// </summary>
@ -29,27 +30,34 @@ namespace Greenshot.Plugin.Confluence.Forms {
{ {
private readonly ConfluenceUpload _confluenceUpload; private readonly ConfluenceUpload _confluenceUpload;
public ConfluencePagePicker(ConfluenceUpload confluenceUpload, List<Page> pagesToPick) { public ConfluencePagePicker(ConfluenceUpload confluenceUpload, List<Page> pagesToPick)
{
_confluenceUpload = confluenceUpload; _confluenceUpload = confluenceUpload;
DataContext = pagesToPick; DataContext = pagesToPick;
InitializeComponent(); InitializeComponent();
} }
private void PageListView_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) { private void PageListView_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
SelectionChanged(); SelectionChanged();
} }
private void SelectionChanged() { private void SelectionChanged()
if (PageListView.HasItems && PageListView.SelectedItems.Count > 0) { {
if (PageListView.HasItems && PageListView.SelectedItems.Count > 0)
{
_confluenceUpload.SelectedPage = (Page) PageListView.SelectedItem; _confluenceUpload.SelectedPage = (Page) PageListView.SelectedItem;
// Make sure the uploader knows we selected an already opened page // Make sure the uploader knows we selected an already opened page
_confluenceUpload.IsOpenPageSelected = true; _confluenceUpload.IsOpenPageSelected = true;
} else { }
else
{
_confluenceUpload.SelectedPage = null; _confluenceUpload.SelectedPage = null;
} }
} }
private void Page_Loaded(object sender, System.Windows.RoutedEventArgs e) { private void Page_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
SelectionChanged(); SelectionChanged();
} }
} }

View file

@ -25,7 +25,8 @@ using System.Linq;
using System.Windows; using System.Windows;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.Confluence.Forms { namespace Greenshot.Plugin.Confluence.Forms
{
public partial class ConfluenceSearch public partial class ConfluenceSearch
{ {
private static readonly ConfluenceConfiguration ConfluenceConfig = IniConfig.GetIniSection<ConfluenceConfiguration>(); private static readonly ConfluenceConfiguration ConfluenceConfig = IniConfig.GetIniSection<ConfluenceConfiguration>();
@ -35,58 +36,76 @@ namespace Greenshot.Plugin.Confluence.Forms {
public ObservableCollection<Page> Pages { get; } = new ObservableCollection<Page>(); public ObservableCollection<Page> Pages { get; } = new ObservableCollection<Page>();
public ConfluenceSearch(ConfluenceUpload confluenceUpload) { public ConfluenceSearch(ConfluenceUpload confluenceUpload)
{
_confluenceUpload = confluenceUpload; _confluenceUpload = confluenceUpload;
DataContext = this; DataContext = this;
InitializeComponent(); InitializeComponent();
if (ConfluenceConfig.SearchSpaceKey == null) { if (ConfluenceConfig.SearchSpaceKey == null)
{
SpaceComboBox.SelectedItem = Spaces.FirstOrDefault(); SpaceComboBox.SelectedItem = Spaces.FirstOrDefault();
} else { }
foreach(var space in Spaces) { else
if (space.Key.Equals(ConfluenceConfig.SearchSpaceKey)) { {
foreach (var space in Spaces)
{
if (space.Key.Equals(ConfluenceConfig.SearchSpaceKey))
{
SpaceComboBox.SelectedItem = space; SpaceComboBox.SelectedItem = space;
} }
} }
} }
} }
private void PageListView_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) { private void PageListView_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
SelectionChanged(); SelectionChanged();
} }
private void SelectionChanged() { private void SelectionChanged()
if (PageListView.HasItems && PageListView.SelectedItems.Count > 0) { {
if (PageListView.HasItems && PageListView.SelectedItems.Count > 0)
{
_confluenceUpload.SelectedPage = (Page) PageListView.SelectedItem; _confluenceUpload.SelectedPage = (Page) PageListView.SelectedItem;
} else { }
else
{
_confluenceUpload.SelectedPage = null; _confluenceUpload.SelectedPage = null;
} }
} }
private void Search_Click(object sender, RoutedEventArgs e) { private void Search_Click(object sender, RoutedEventArgs e)
{
DoSearch(); DoSearch();
} }
private void DoSearch() { private void DoSearch()
{
string spaceKey = (string) SpaceComboBox.SelectedValue; string spaceKey = (string) SpaceComboBox.SelectedValue;
ConfluenceConfig.SearchSpaceKey = spaceKey; ConfluenceConfig.SearchSpaceKey = spaceKey;
Pages.Clear(); Pages.Clear();
foreach(var page in ConfluencePlugin.ConfluenceConnector.SearchPages(searchText.Text, spaceKey).OrderBy(p => p.Title)) { foreach (var page in ConfluencePlugin.ConfluenceConnector.SearchPages(searchText.Text, spaceKey).OrderBy(p => p.Title))
{
Pages.Add(page); Pages.Add(page);
} }
} }
private void SearchText_KeyDown(object sender, System.Windows.Input.KeyEventArgs e) { private void SearchText_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
if (e.Key == System.Windows.Input.Key.Return && Search.IsEnabled) { {
if (e.Key == System.Windows.Input.Key.Return && Search.IsEnabled)
{
DoSearch(); DoSearch();
e.Handled = true; e.Handled = true;
} }
} }
private void Page_Loaded(object sender, RoutedEventArgs e) { private void Page_Loaded(object sender, RoutedEventArgs e)
{
SelectionChanged(); SelectionChanged();
} }
private void SearchText_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e) { private void SearchText_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
Search.IsEnabled = !string.IsNullOrEmpty(searchText.Text); Search.IsEnabled = !string.IsNullOrEmpty(searchText.Text);
} }
} }

View file

@ -27,7 +27,8 @@ using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Threading; using System.Windows.Threading;
namespace Greenshot.Plugin.Confluence.Forms { namespace Greenshot.Plugin.Confluence.Forms
{
/// <summary> /// <summary>
/// Interaction logic for ConfluenceTreePicker.xaml /// Interaction logic for ConfluenceTreePicker.xaml
/// </summary> /// </summary>
@ -38,28 +39,36 @@ namespace Greenshot.Plugin.Confluence.Forms {
private readonly ConfluenceUpload _confluenceUpload; private readonly ConfluenceUpload _confluenceUpload;
private bool _isInitDone; private bool _isInitDone;
public ConfluenceTreePicker(ConfluenceUpload confluenceUpload) { public ConfluenceTreePicker(ConfluenceUpload confluenceUpload)
{
_confluenceConnector = ConfluencePlugin.ConfluenceConnector; _confluenceConnector = ConfluencePlugin.ConfluenceConnector;
_confluenceUpload = confluenceUpload; _confluenceUpload = confluenceUpload;
InitializeComponent(); InitializeComponent();
} }
private void PageTreeViewItem_DoubleClick(object sender, MouseButtonEventArgs eventArgs) { private void PageTreeViewItem_DoubleClick(object sender, MouseButtonEventArgs eventArgs)
{
Log.Debug("spaceTreeViewItem_MouseLeftButtonDown is called!"); Log.Debug("spaceTreeViewItem_MouseLeftButtonDown is called!");
TreeViewItem clickedItem = eventArgs.Source as TreeViewItem; TreeViewItem clickedItem = eventArgs.Source as TreeViewItem;
if (clickedItem?.Tag is not Page page) { if (clickedItem?.Tag is not Page page)
{
return; return;
} }
if (clickedItem.HasItems) if (clickedItem.HasItems)
{ {
return; return;
} }
Log.Debug("Loading pages for page: " + page.Title); Log.Debug("Loading pages for page: " + page.Title);
new Thread(() => { new Thread(() =>
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart) (() => { ShowBusy.Visibility = Visibility.Visible; })); Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart) (() => { ShowBusy.Visibility = Visibility.Visible; }));
var pages = _confluenceConnector.GetPageChildren(page).OrderBy(p => p.Title); var pages = _confluenceConnector.GetPageChildren(page).OrderBy(p => p.Title);
Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)(() => { Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart) (() =>
foreach(var childPage in pages) { {
foreach (var childPage in pages)
{
Log.Debug("Adding page: " + childPage.Title); Log.Debug("Adding page: " + childPage.Title);
var pageTreeViewItem = new TreeViewItem var pageTreeViewItem = new TreeViewItem
{ {
@ -70,32 +79,46 @@ namespace Greenshot.Plugin.Confluence.Forms {
pageTreeViewItem.PreviewMouseDoubleClick += PageTreeViewItem_DoubleClick; pageTreeViewItem.PreviewMouseDoubleClick += PageTreeViewItem_DoubleClick;
pageTreeViewItem.PreviewMouseLeftButtonDown += PageTreeViewItem_Click; pageTreeViewItem.PreviewMouseLeftButtonDown += PageTreeViewItem_Click;
} }
ShowBusy.Visibility = Visibility.Collapsed; ShowBusy.Visibility = Visibility.Collapsed;
})); }));
}) { Name = "Loading childpages for confluence page " + page.Title }.Start(); })
{
Name = "Loading childpages for confluence page " + page.Title
}.Start();
} }
private void PageTreeViewItem_Click(object sender, MouseButtonEventArgs eventArgs) { private void PageTreeViewItem_Click(object sender, MouseButtonEventArgs eventArgs)
{
Log.Debug("pageTreeViewItem_PreviewMouseDoubleClick is called!"); Log.Debug("pageTreeViewItem_PreviewMouseDoubleClick is called!");
if (eventArgs.Source is not TreeViewItem clickedItem) { if (eventArgs.Source is not TreeViewItem clickedItem)
{
return; return;
} }
Page page = clickedItem.Tag as Page; Page page = clickedItem.Tag as Page;
_confluenceUpload.SelectedPage = page; _confluenceUpload.SelectedPage = page;
if (page != null) { if (page != null)
{
Log.Debug("Page selected: " + page.Title); Log.Debug("Page selected: " + page.Title);
} }
} }
private void Page_Loaded(object sender, RoutedEventArgs e) { private void Page_Loaded(object sender, RoutedEventArgs e)
{
_confluenceUpload.SelectedPage = null; _confluenceUpload.SelectedPage = null;
if (_isInitDone) { if (_isInitDone)
{
return; return;
} }
ShowBusy.Visibility = Visibility.Visible; ShowBusy.Visibility = Visibility.Visible;
new Thread(() => { new Thread(() =>
Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)(() => { {
foreach (Space space in _confluenceUpload.Spaces) { Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart) (() =>
{
foreach (Space space in _confluenceUpload.Spaces)
{
TreeViewItem spaceTreeViewItem = new TreeViewItem TreeViewItem spaceTreeViewItem = new TreeViewItem
{ {
Header = space.Name, Header = space.Name,
@ -103,7 +126,8 @@ namespace Greenshot.Plugin.Confluence.Forms {
}; };
// Get homepage // Get homepage
try { try
{
Page page = _confluenceConnector.GetSpaceHomepage(space); Page page = _confluenceConnector.GetSpaceHomepage(space);
TreeViewItem pageTreeViewItem = new TreeViewItem TreeViewItem pageTreeViewItem = new TreeViewItem
{ {
@ -114,14 +138,20 @@ namespace Greenshot.Plugin.Confluence.Forms {
pageTreeViewItem.PreviewMouseLeftButtonDown += PageTreeViewItem_Click; pageTreeViewItem.PreviewMouseLeftButtonDown += PageTreeViewItem_Click;
spaceTreeViewItem.Items.Add(pageTreeViewItem); spaceTreeViewItem.Items.Add(pageTreeViewItem);
ConfluenceTreeView.Items.Add(spaceTreeViewItem); ConfluenceTreeView.Items.Add(spaceTreeViewItem);
} catch (Exception ex) { }
catch (Exception ex)
{
Log.Error("Can't get homepage for space : " + space.Name + " (" + ex.Message + ")"); Log.Error("Can't get homepage for space : " + space.Name + " (" + ex.Message + ")");
} }
} }
ShowBusy.Visibility = Visibility.Collapsed; ShowBusy.Visibility = Visibility.Collapsed;
_isInitDone = true; _isInitDone = true;
})); }));
}) { Name = "Loading spaces for confluence"}.Start(); })
{
Name = "Loading spaces for confluence"
}.Start();
} }
} }
} }

View file

@ -25,91 +25,116 @@ using System.Linq;
using System.Threading; using System.Threading;
using System.Windows; using System.Windows;
namespace Greenshot.Plugin.Confluence.Forms { namespace Greenshot.Plugin.Confluence.Forms
{
/// <summary> /// <summary>
/// Interaction logic for ConfluenceUpload.xaml /// Interaction logic for ConfluenceUpload.xaml
/// </summary> /// </summary>
public partial class ConfluenceUpload : Window { public partial class ConfluenceUpload : Window
{
private System.Windows.Controls.Page _pickerPage; private System.Windows.Controls.Page _pickerPage;
public System.Windows.Controls.Page PickerPage {
get { public System.Windows.Controls.Page PickerPage
if (_pickerPage == null) { {
get
{
if (_pickerPage == null)
{
List<Page> pages = ConfluenceUtils.GetCurrentPages(); List<Page> pages = ConfluenceUtils.GetCurrentPages();
if (pages != null && pages.Count > 0) { if (pages != null && pages.Count > 0)
{
_pickerPage = new ConfluencePagePicker(this, pages); _pickerPage = new ConfluencePagePicker(this, pages);
} }
} }
return _pickerPage; return _pickerPage;
} }
} }
private System.Windows.Controls.Page _searchPage; private System.Windows.Controls.Page _searchPage;
public System.Windows.Controls.Page SearchPage {
public System.Windows.Controls.Page SearchPage
{
get { return _searchPage ??= new ConfluenceSearch(this); } get { return _searchPage ??= new ConfluenceSearch(this); }
} }
private System.Windows.Controls.Page _browsePage; private System.Windows.Controls.Page _browsePage;
public System.Windows.Controls.Page BrowsePage {
public System.Windows.Controls.Page BrowsePage
{
get { return _browsePage ??= new ConfluenceTreePicker(this); } get { return _browsePage ??= new ConfluenceTreePicker(this); }
} }
private Page _selectedPage; private Page _selectedPage;
public Page SelectedPage {
public Page SelectedPage
{
get => _selectedPage; get => _selectedPage;
set { set
{
_selectedPage = value; _selectedPage = value;
Upload.IsEnabled = _selectedPage != null; Upload.IsEnabled = _selectedPage != null;
IsOpenPageSelected = false; IsOpenPageSelected = false;
} }
} }
public bool IsOpenPageSelected { public bool IsOpenPageSelected { get; set; }
get; public string Filename { get; set; }
set;
}
public string Filename {
get;
set;
}
private static DateTime _lastLoad = DateTime.Now; private static DateTime _lastLoad = DateTime.Now;
private static IList<Space> _spaces; private static IList<Space> _spaces;
public IList<Space> Spaces {
get { public IList<Space> Spaces
{
get
{
UpdateSpaces(); UpdateSpaces();
while (_spaces == null) { while (_spaces == null)
{
Thread.Sleep(300); Thread.Sleep(300);
} }
return _spaces; return _spaces;
} }
} }
public ConfluenceUpload(string filename) { public ConfluenceUpload(string filename)
{
Filename = filename; Filename = filename;
InitializeComponent(); InitializeComponent();
DataContext = this; DataContext = this;
UpdateSpaces(); UpdateSpaces();
if (PickerPage == null) { if (PickerPage == null)
{
PickerTab.Visibility = Visibility.Collapsed; PickerTab.Visibility = Visibility.Collapsed;
SearchTab.IsSelected = true; SearchTab.IsSelected = true;
} }
} }
private void UpdateSpaces() { private void UpdateSpaces()
if (_spaces != null && DateTime.Now.AddMinutes(-60).CompareTo(_lastLoad) > 0) { {
if (_spaces != null && DateTime.Now.AddMinutes(-60).CompareTo(_lastLoad) > 0)
{
// Reset // Reset
_spaces = null; _spaces = null;
} }
// Check if load is needed // Check if load is needed
if (_spaces == null) { if (_spaces == null)
(new Thread(() => { {
(new Thread(() =>
{
_spaces = ConfluencePlugin.ConfluenceConnector.GetSpaceSummaries().OrderBy(s => s.Name).ToList(); _spaces = ConfluencePlugin.ConfluenceConnector.GetSpaceSummaries().OrderBy(s => s.Name).ToList();
_lastLoad = DateTime.Now; _lastLoad = DateTime.Now;
}) { Name = "Loading spaces for confluence"}).Start(); })
{
Name = "Loading spaces for confluence"
}).Start();
} }
} }
private void Upload_Click(object sender, RoutedEventArgs e) { private void Upload_Click(object sender, RoutedEventArgs e)
{
DialogResult = true; DialogResult = true;
} }
} }

View file

@ -19,8 +19,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace Greenshot.Plugin.Confluence { namespace Greenshot.Plugin.Confluence
public enum LangKey { {
public enum LangKey
{
login_error, login_error,
upload_menu_item, upload_menu_item,
communication_wait communication_wait

View file

@ -1,5 +1,7 @@
namespace Greenshot.Plugin.Confluence.Support { namespace Greenshot.Plugin.Confluence.Support
public interface ITranslationProvider { {
public interface ITranslationProvider
{
/// <summary> /// <summary>
/// Translates the specified key. /// Translates the specified key.
/// </summary> /// </summary>

View file

@ -43,9 +43,9 @@ namespace Greenshot.Plugin.Confluence.Support
manager = new LanguageChangedEventManager(); manager = new LanguageChangedEventManager();
SetCurrentManager(managerType, manager); SetCurrentManager(managerType, manager);
} }
return manager; return manager;
} }
} }
} }
} }

View file

@ -1,17 +1,22 @@
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
namespace Greenshot.Plugin.Confluence.Support { namespace Greenshot.Plugin.Confluence.Support
{
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public class LanguageXMLTranslationProvider : ITranslationProvider { public class LanguageXMLTranslationProvider : ITranslationProvider
{
/// <summary> /// <summary>
/// See <see cref="ITranslationProvider.Translate" /> /// See <see cref="ITranslationProvider.Translate" />
/// </summary> /// </summary>
public object Translate(string key) { public object Translate(string key)
if (Language.HasKey("confluence", key)) { {
if (Language.HasKey("confluence", key))
{
return Language.GetString("confluence", key); return Language.GetString("confluence", key);
} }
return key; return key;
} }
} }

View file

@ -2,15 +2,18 @@
using System.ComponentModel; using System.ComponentModel;
using System.Windows; using System.Windows;
namespace Greenshot.Plugin.Confluence.Support { namespace Greenshot.Plugin.Confluence.Support
public class TranslationData : IWeakEventListener, INotifyPropertyChanged { {
public class TranslationData : IWeakEventListener, INotifyPropertyChanged
{
private readonly string _key; private readonly string _key;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="TranslationData"/> class. /// Initializes a new instance of the <see cref="TranslationData"/> class.
/// </summary> /// </summary>
/// <param name="key">The key.</param> /// <param name="key">The key.</param>
public TranslationData( string key) { public TranslationData(string key)
{
_key = key; _key = key;
LanguageChangedEventManager.AddListener(TranslationManager.Instance, this); LanguageChangedEventManager.AddListener(TranslationManager.Instance, this);
} }
@ -19,7 +22,8 @@ namespace Greenshot.Plugin.Confluence.Support {
/// Releases unmanaged resources and performs other cleanup operations before the /// Releases unmanaged resources and performs other cleanup operations before the
/// <see cref="TranslationData"/> is reclaimed by garbage collection. /// <see cref="TranslationData"/> is reclaimed by garbage collection.
/// </summary> /// </summary>
~TranslationData() { ~TranslationData()
{
LanguageChangedEventManager.RemoveListener(TranslationManager.Instance, this); LanguageChangedEventManager.RemoveListener(TranslationManager.Instance, this);
} }
@ -32,6 +36,7 @@ namespace Greenshot.Plugin.Confluence.Support {
OnLanguageChanged(sender, e); OnLanguageChanged(sender, e);
return true; return true;
} }
return false; return false;
} }

View file

@ -1,7 +1,9 @@
using System; using System;
namespace Greenshot.Plugin.Confluence.Support { namespace Greenshot.Plugin.Confluence.Support
public class TranslationManager { {
public class TranslationManager
{
private static TranslationManager _translationManager; private static TranslationManager _translationManager;
public event EventHandler LanguageChanged; public event EventHandler LanguageChanged;
@ -29,11 +31,14 @@ namespace Greenshot.Plugin.Confluence.Support {
public ITranslationProvider TranslationProvider { get; set; } public ITranslationProvider TranslationProvider { get; set; }
public object Translate(string key) { public object Translate(string key)
{
object translatedValue = TranslationProvider?.Translate(key); object translatedValue = TranslationProvider?.Translate(key);
if( translatedValue != null) { if (translatedValue != null)
{
return translatedValue; return translatedValue;
} }
return $"!{key}!"; return $"!{key}!";
} }
} }

View file

@ -25,12 +25,16 @@ using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
namespace Greenshot.Plugin.Dropbox { namespace Greenshot.Plugin.Dropbox
internal class DropboxDestination : AbstractDestination { {
internal class DropboxDestination : AbstractDestination
{
private static readonly DropboxPluginConfiguration DropboxConfig = IniConfig.GetIniSection<DropboxPluginConfiguration>(); private static readonly DropboxPluginConfiguration DropboxConfig = IniConfig.GetIniSection<DropboxPluginConfiguration>();
private readonly DropboxPlugin _plugin; private readonly DropboxPlugin _plugin;
public DropboxDestination(DropboxPlugin plugin) {
public DropboxDestination(DropboxPlugin plugin)
{
_plugin = plugin; _plugin = plugin;
} }
@ -38,23 +42,29 @@ namespace Greenshot.Plugin.Dropbox {
public override string Description => Language.GetString("dropbox", LangKey.upload_menu_item); public override string Description => Language.GetString("dropbox", LangKey.upload_menu_item);
public override Image DisplayIcon { public override Image DisplayIcon
get { {
get
{
ComponentResourceManager resources = new ComponentResourceManager(typeof(DropboxPlugin)); ComponentResourceManager resources = new ComponentResourceManager(typeof(DropboxPlugin));
return (Image) resources.GetObject("Dropbox"); return (Image) resources.GetObject("Dropbox");
} }
} }
public override ExportInformation ExportCapture(bool manually, ISurface surface, ICaptureDetails captureDetails) { public override ExportInformation ExportCapture(bool manually, ISurface surface, ICaptureDetails captureDetails)
{
ExportInformation exportInformation = new ExportInformation(Designation, Description); ExportInformation exportInformation = new ExportInformation(Designation, Description);
bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl); bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl);
if (uploaded) { if (uploaded)
{
exportInformation.Uri = uploadUrl; exportInformation.Uri = uploadUrl;
exportInformation.ExportMade = true; exportInformation.ExportMade = true;
if (DropboxConfig.AfterUploadLinkToClipBoard) { if (DropboxConfig.AfterUploadLinkToClipBoard)
{
ClipboardHelper.SetClipboardData(uploadUrl); ClipboardHelper.SetClipboardData(uploadUrl);
} }
} }
ProcessExport(exportInformation, surface); ProcessExport(exportInformation, surface);
return exportInformation; return exportInformation;
} }

View file

@ -29,18 +29,21 @@ using GreenshotPlugin.IniFile;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin; using GreenshotPlugin.Interfaces.Plugin;
namespace Greenshot.Plugin.Dropbox { namespace Greenshot.Plugin.Dropbox
{
/// <summary> /// <summary>
/// This is the Dropbox base code /// This is the Dropbox base code
/// </summary> /// </summary>
[Plugin("Dropbox", true)] [Plugin("Dropbox", true)]
public class DropboxPlugin : IGreenshotPlugin { public class DropboxPlugin : IGreenshotPlugin
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DropboxPlugin)); private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DropboxPlugin));
private static DropboxPluginConfiguration _config; private static DropboxPluginConfiguration _config;
private ComponentResourceManager _resources; private ComponentResourceManager _resources;
private ToolStripMenuItem _itemPlugInConfig; private ToolStripMenuItem _itemPlugInConfig;
public void Dispose() { public void Dispose()
{
Dispose(true); Dispose(true);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
@ -56,8 +59,8 @@ namespace Greenshot.Plugin.Dropbox {
/// <summary> /// <summary>
/// Implementation of the IGreenshotPlugin.Initialize /// Implementation of the IGreenshotPlugin.Initialize
/// </summary> /// </summary>
public bool Initialize() { public bool Initialize()
{
// Register configuration (don't need the configuration itself) // Register configuration (don't need the configuration itself)
_config = IniConfig.GetIniSection<DropboxPluginConfiguration>(); _config = IniConfig.GetIniSection<DropboxPluginConfiguration>();
_resources = new ComponentResourceManager(typeof(DropboxPlugin)); _resources = new ComponentResourceManager(typeof(DropboxPlugin));
@ -74,44 +77,49 @@ namespace Greenshot.Plugin.Dropbox {
return true; return true;
} }
public void OnLanguageChanged(object sender, EventArgs e) { public void OnLanguageChanged(object sender, EventArgs e)
if (_itemPlugInConfig != null) { {
if (_itemPlugInConfig != null)
{
_itemPlugInConfig.Text = Language.GetString("dropbox", LangKey.Configure); _itemPlugInConfig.Text = Language.GetString("dropbox", LangKey.Configure);
} }
} }
public void Shutdown() { public void Shutdown()
{
Log.Debug("Dropbox Plugin shutdown."); Log.Debug("Dropbox Plugin shutdown.");
} }
/// <summary> /// <summary>
/// Implementation of the IPlugin.Configure /// Implementation of the IPlugin.Configure
/// </summary> /// </summary>
public void Configure() { public void Configure()
{
_config.ShowConfigDialog(); _config.ShowConfigDialog();
} }
public void ConfigMenuClick(object sender, EventArgs eventArgs) { public void ConfigMenuClick(object sender, EventArgs eventArgs)
{
_config.ShowConfigDialog(); _config.ShowConfigDialog();
} }
/// <summary> /// <summary>
/// This will be called when the menu item in the Editor is clicked /// This will be called when the menu item in the Editor is clicked
/// </summary> /// </summary>
public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) { public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl)
{
uploadUrl = null; uploadUrl = null;
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, false); SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, false);
try try
{ {
bool result = false; bool result = false;
new PleaseWaitForm().ShowAndWait("Dropbox", Language.GetString("dropbox", LangKey.communication_wait), new PleaseWaitForm().ShowAndWait("Dropbox", Language.GetString("dropbox", LangKey.communication_wait),
delegate delegate { result = DropboxUtils.UploadToDropbox(surfaceToUpload, outputSettings, captureDetails); }
{
result = DropboxUtils.UploadToDropbox(surfaceToUpload, outputSettings, captureDetails);
}
); );
return result; return result;
} catch (Exception e) { }
catch (Exception e)
{
Log.Error(e); Log.Error(e);
MessageBox.Show(Language.GetString("dropbox", LangKey.upload_failure) + " " + e.Message); MessageBox.Show(Language.GetString("dropbox", LangKey.upload_failure) + " " + e.Message);
return false; return false;

View file

@ -25,12 +25,14 @@ using Greenshot.Plugin.Dropbox.Forms;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.Dropbox { namespace Greenshot.Plugin.Dropbox
{
/// <summary> /// <summary>
/// Description of ImgurConfiguration. /// Description of ImgurConfiguration.
/// </summary> /// </summary>
[IniSection("Dropbox", Description = "Greenshot Dropbox Plugin configuration")] [IniSection("Dropbox", Description = "Greenshot Dropbox Plugin configuration")]
public class DropboxPluginConfiguration : IniSection { public class DropboxPluginConfiguration : IniSection
{
[IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")]
public OutputFormat UploadFormat { get; set; } public OutputFormat UploadFormat { get; set; }
@ -57,11 +59,14 @@ namespace Greenshot.Plugin.Dropbox {
/// A form for token /// A form for token
/// </summary> /// </summary>
/// <returns>bool true if OK was pressed, false if cancel</returns> /// <returns>bool true if OK was pressed, false if cancel</returns>
public bool ShowConfigDialog() { public bool ShowConfigDialog()
{
DialogResult result = new SettingsForm().ShowDialog(); DialogResult result = new SettingsForm().ShowDialog();
if (result == DialogResult.OK) { if (result == DialogResult.OK)
{
return true; return true;
} }
return false; return false;
} }
} }

View file

@ -29,15 +29,18 @@ using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin; using GreenshotPlugin.Interfaces.Plugin;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Greenshot.Plugin.Dropbox { namespace Greenshot.Plugin.Dropbox
{
/// <summary> /// <summary>
/// Description of DropboxUtils. /// Description of DropboxUtils.
/// </summary> /// </summary>
public class DropboxUtils { public class DropboxUtils
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DropboxUtils)); private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DropboxUtils));
private static readonly DropboxPluginConfiguration DropboxConfig = IniConfig.GetIniSection<DropboxPluginConfiguration>(); private static readonly DropboxPluginConfiguration DropboxConfig = IniConfig.GetIniSection<DropboxPluginConfiguration>();
private DropboxUtils() { private DropboxUtils()
{
} }
public static bool UploadToDropbox(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, ICaptureDetails captureDetails) public static bool UploadToDropbox(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, ICaptureDetails captureDetails)
@ -62,13 +65,21 @@ namespace Greenshot.Plugin.Dropbox {
IDictionary<string, object> arguments = new Dictionary<string, object> IDictionary<string, object> arguments = new Dictionary<string, object>
{ {
{ "autorename", true }, {
{ "mute", true }, "autorename", true
{ "path", "/" + filename.Replace(Path.DirectorySeparatorChar, '\\')} },
{
"mute", true
},
{
"path", "/" + filename.Replace(Path.DirectorySeparatorChar, '\\')
}
}; };
IDictionary<string, object> headers = new Dictionary<string, object> IDictionary<string, object> headers = new Dictionary<string, object>
{ {
{ "Dropbox-API-Arg", JsonConvert.SerializeObject(arguments)} {
"Dropbox-API-Arg", JsonConvert.SerializeObject(arguments)
}
}; };
var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, "https://content.dropboxapi.com/2/files/upload", oauth2Settings); var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, "https://content.dropboxapi.com/2/files/upload", oauth2Settings);
@ -78,10 +89,13 @@ namespace Greenshot.Plugin.Dropbox {
var response = JsonConvert.DeserializeObject<IDictionary<string, string>>(responseString); var response = JsonConvert.DeserializeObject<IDictionary<string, string>>(responseString);
return response.ContainsKey("id"); return response.ContainsKey("id");
} }
catch (Exception ex) { catch (Exception ex)
{
Log.Error("Upload error: ", ex); Log.Error("Upload error: ", ex);
throw; throw;
} finally { }
finally
{
DropboxConfig.RefreshToken = oauth2Settings.RefreshToken; DropboxConfig.RefreshToken = oauth2Settings.RefreshToken;
DropboxConfig.AccessToken = oauth2Settings.AccessToken; DropboxConfig.AccessToken = oauth2Settings.AccessToken;
DropboxConfig.AccessTokenExpires = oauth2Settings.AccessTokenExpires; DropboxConfig.AccessTokenExpires = oauth2Settings.AccessTokenExpires;

View file

@ -21,7 +21,9 @@
using GreenshotPlugin.Controls; using GreenshotPlugin.Controls;
namespace Greenshot.Plugin.Dropbox.Forms { namespace Greenshot.Plugin.Dropbox.Forms
public class DropboxForm : GreenshotForm { {
public class DropboxForm : GreenshotForm
{
} }
} }

View file

@ -19,12 +19,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace Greenshot.Plugin.Dropbox.Forms { namespace Greenshot.Plugin.Dropbox.Forms
{
/// <summary> /// <summary>
/// Description of PasswordRequestForm. /// Description of PasswordRequestForm.
/// </summary> /// </summary>
public partial class SettingsForm : DropboxForm { public partial class SettingsForm : DropboxForm
public SettingsForm() { {
public SettingsForm()
{
// //
// The InitializeComponent() call is required for Windows Forms designer support. // The InitializeComponent() call is required for Windows Forms designer support.
// //
@ -32,6 +35,5 @@ namespace Greenshot.Plugin.Dropbox.Forms {
AcceptButton = buttonOK; AcceptButton = buttonOK;
CancelButton = buttonCancel; CancelButton = buttonCancel;
} }
} }
} }

View file

@ -18,8 +18,11 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace Greenshot.Plugin.Dropbox {
public enum LangKey { namespace Greenshot.Plugin.Dropbox
{
public enum LangKey
{
upload_menu_item, upload_menu_item,
upload_failure, upload_failure,
communication_wait, communication_wait,

View file

@ -25,31 +25,42 @@ using System.IO;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.ExternalCommand { namespace Greenshot.Plugin.ExternalCommand
{
/// <summary> /// <summary>
/// Description of FlickrConfiguration. /// Description of FlickrConfiguration.
/// </summary> /// </summary>
[IniSection("ExternalCommand", Description = "Greenshot ExternalCommand Plugin configuration")] [IniSection("ExternalCommand", Description = "Greenshot ExternalCommand Plugin configuration")]
public class ExternalCommandConfiguration : IniSection { public class ExternalCommandConfiguration : IniSection
{
[IniProperty("Commands", Description = "The commands that are available.")] [IniProperty("Commands", Description = "The commands that are available.")]
public List<string> Commands { get; set; } public List<string> Commands { get; set; }
[IniProperty("RedirectStandardError", Description = "Redirect the standard error of all external commands, used to output as warning to the greenshot.log.", DefaultValue = "true")] [IniProperty("RedirectStandardError", Description = "Redirect the standard error of all external commands, used to output as warning to the greenshot.log.",
DefaultValue = "true")]
public bool RedirectStandardError { get; set; } public bool RedirectStandardError { get; set; }
[IniProperty("RedirectStandardOutput", Description = "Redirect the standard output of all external commands, used for different other functions (more below).", DefaultValue = "true")] [IniProperty("RedirectStandardOutput", Description = "Redirect the standard output of all external commands, used for different other functions (more below).",
DefaultValue = "true")]
public bool RedirectStandardOutput { get; set; } public bool RedirectStandardOutput { get; set; }
[IniProperty("ShowStandardOutputInLog", Description = "Depends on 'RedirectStandardOutput': Show standard output of all external commands to the Greenshot log, this can be usefull for debugging.", DefaultValue = "false")] [IniProperty("ShowStandardOutputInLog",
Description = "Depends on 'RedirectStandardOutput': Show standard output of all external commands to the Greenshot log, this can be usefull for debugging.",
DefaultValue = "false")]
public bool ShowStandardOutputInLog { get; set; } public bool ShowStandardOutputInLog { get; set; }
[IniProperty("ParseForUri", Description = "Depends on 'RedirectStandardOutput': Parse the output and take the first found URI, if a URI is found than clicking on the notify bubble goes there.", DefaultValue = "true")] [IniProperty("ParseForUri",
Description = "Depends on 'RedirectStandardOutput': Parse the output and take the first found URI, if a URI is found than clicking on the notify bubble goes there.",
DefaultValue = "true")]
public bool ParseOutputForUri { get; set; } public bool ParseOutputForUri { get; set; }
[IniProperty("OutputToClipboard", Description = "Depends on 'RedirectStandardOutput': Place the standard output on the clipboard.", DefaultValue = "false")] [IniProperty("OutputToClipboard", Description = "Depends on 'RedirectStandardOutput': Place the standard output on the clipboard.", DefaultValue = "false")]
public bool OutputToClipboard { get; set; } public bool OutputToClipboard { get; set; }
[IniProperty("UriToClipboard", Description = "Depends on 'RedirectStandardOutput' & 'ParseForUri': If an URI is found in the standard input, place it on the clipboard. (This overwrites the output from OutputToClipboard setting.)", DefaultValue = "true")] [IniProperty("UriToClipboard",
Description =
"Depends on 'RedirectStandardOutput' & 'ParseForUri': If an URI is found in the standard input, place it on the clipboard. (This overwrites the output from OutputToClipboard setting.)",
DefaultValue = "true")]
public bool UriToClipboard { get; set; } public bool UriToClipboard { get; set; }
[IniProperty("Commandline", Description = "The commandline for the output command.")] [IniProperty("Commandline", Description = "The commandline for the output command.")]
@ -71,13 +82,19 @@ namespace Greenshot.Plugin.ExternalCommand {
private const string PaintDotNet = "Paint.NET"; private const string PaintDotNet = "Paint.NET";
private static readonly string PaintDotNetPath; private static readonly string PaintDotNetPath;
private static readonly bool HasPaintDotNet; private static readonly bool HasPaintDotNet;
static ExternalCommandConfiguration() {
try { static ExternalCommandConfiguration()
{
try
{
PaintPath = PluginUtils.GetExePath("pbrush.exe"); PaintPath = PluginUtils.GetExePath("pbrush.exe");
HasPaint = !string.IsNullOrEmpty(PaintPath) && File.Exists(PaintPath); HasPaint = !string.IsNullOrEmpty(PaintPath) && File.Exists(PaintPath);
} catch { }
catch
{
// Ignore // Ignore
} }
try try
{ {
PaintDotNetPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Paint.NET\PaintDotNet.exe"); PaintDotNetPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Paint.NET\PaintDotNet.exe");
@ -99,6 +116,7 @@ namespace Greenshot.Plugin.ExternalCommand {
{ {
return; return;
} }
Commands.Remove(command); Commands.Remove(command);
Commandline.Remove(command); Commandline.Remove(command);
Argument.Remove(command); Argument.Remove(command);

View file

@ -31,17 +31,24 @@ using GreenshotPlugin.IniFile;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin; using GreenshotPlugin.Interfaces.Plugin;
namespace Greenshot.Plugin.ExternalCommand { namespace Greenshot.Plugin.ExternalCommand
{
/// <summary> /// <summary>
/// Description of OCRDestination. /// Description of OCRDestination.
/// </summary> /// </summary>
public class ExternalCommandDestination : AbstractDestination { public class ExternalCommandDestination : AbstractDestination
{
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ExternalCommandDestination)); private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ExternalCommandDestination));
private static readonly Regex URI_REGEXP = new Regex(@"((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)");
private static readonly Regex URI_REGEXP =
new Regex(
@"((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)");
private static readonly ExternalCommandConfiguration config = IniConfig.GetIniSection<ExternalCommandConfiguration>(); private static readonly ExternalCommandConfiguration config = IniConfig.GetIniSection<ExternalCommandConfiguration>();
private readonly string _presetCommand; private readonly string _presetCommand;
public ExternalCommandDestination(string commando) { public ExternalCommandDestination(string commando)
{
_presetCommand = commando; _presetCommand = commando;
} }
@ -49,27 +56,33 @@ namespace Greenshot.Plugin.ExternalCommand {
public override string Description => _presetCommand; public override string Description => _presetCommand;
public override IEnumerable<IDestination> DynamicDestinations() { public override IEnumerable<IDestination> DynamicDestinations()
{
yield break; yield break;
} }
public override Image DisplayIcon => IconCache.IconForCommand(_presetCommand); public override Image DisplayIcon => IconCache.IconForCommand(_presetCommand);
public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails)
{
ExportInformation exportInformation = new ExportInformation(Designation, Description); ExportInformation exportInformation = new ExportInformation(Designation, Description);
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(); SurfaceOutputSettings outputSettings = new SurfaceOutputSettings();
outputSettings.PreventGreenshotFormat(); outputSettings.PreventGreenshotFormat();
if (_presetCommand != null) { if (_presetCommand != null)
if (!config.RunInbackground.ContainsKey(_presetCommand)) { {
if (!config.RunInbackground.ContainsKey(_presetCommand))
{
config.RunInbackground.Add(_presetCommand, true); config.RunInbackground.Add(_presetCommand, true);
} }
bool runInBackground = config.RunInbackground[_presetCommand]; bool runInBackground = config.RunInbackground[_presetCommand];
string fullPath = captureDetails.Filename ?? ImageOutput.SaveNamedTmpFile(surface, captureDetails, outputSettings); string fullPath = captureDetails.Filename ?? ImageOutput.SaveNamedTmpFile(surface, captureDetails, outputSettings);
string output; string output;
string error; string error;
if (runInBackground) { if (runInBackground)
{
Thread commandThread = new Thread(delegate() Thread commandThread = new Thread(delegate()
{ {
CallExternalCommand(exportInformation, fullPath, out output, out error); CallExternalCommand(exportInformation, fullPath, out output, out error);
@ -82,11 +95,14 @@ namespace Greenshot.Plugin.ExternalCommand {
commandThread.SetApartmentState(ApartmentState.STA); commandThread.SetApartmentState(ApartmentState.STA);
commandThread.Start(); commandThread.Start();
exportInformation.ExportMade = true; exportInformation.ExportMade = true;
} else { }
else
{
CallExternalCommand(exportInformation, fullPath, out output, out error); CallExternalCommand(exportInformation, fullPath, out output, out error);
ProcessExport(exportInformation, surface); ProcessExport(exportInformation, surface);
} }
} }
return exportInformation; return exportInformation;
} }
@ -98,32 +114,44 @@ namespace Greenshot.Plugin.ExternalCommand {
/// <param name="fullPath"></param> /// <param name="fullPath"></param>
/// <param name="output"></param> /// <param name="output"></param>
/// <param name="error"></param> /// <param name="error"></param>
private void CallExternalCommand(ExportInformation exportInformation, string fullPath, out string output, out string error) { private void CallExternalCommand(ExportInformation exportInformation, string fullPath, out string output, out string error)
{
output = null; output = null;
error = null; error = null;
try { try
if (CallExternalCommand(_presetCommand, fullPath, out output, out error) == 0) { {
if (CallExternalCommand(_presetCommand, fullPath, out output, out error) == 0)
{
exportInformation.ExportMade = true; exportInformation.ExportMade = true;
if (!string.IsNullOrEmpty(output)) { if (!string.IsNullOrEmpty(output))
{
MatchCollection uriMatches = URI_REGEXP.Matches(output); MatchCollection uriMatches = URI_REGEXP.Matches(output);
// Place output on the clipboard before the URI, so if one is found this overwrites // Place output on the clipboard before the URI, so if one is found this overwrites
if (config.OutputToClipboard) { if (config.OutputToClipboard)
{
ClipboardHelper.SetClipboardData(output); ClipboardHelper.SetClipboardData(output);
} }
if (uriMatches.Count > 0) {
if (uriMatches.Count > 0)
{
exportInformation.Uri = uriMatches[0].Groups[1].Value; exportInformation.Uri = uriMatches[0].Groups[1].Value;
LOG.InfoFormat("Got URI : {0} ", exportInformation.Uri); LOG.InfoFormat("Got URI : {0} ", exportInformation.Uri);
if (config.UriToClipboard) { if (config.UriToClipboard)
{
ClipboardHelper.SetClipboardData(exportInformation.Uri); ClipboardHelper.SetClipboardData(exportInformation.Uri);
} }
} }
} }
} else { }
else
{
LOG.WarnFormat("Error calling external command: {0} ", output); LOG.WarnFormat("Error calling external command: {0} ", output);
exportInformation.ExportMade = false; exportInformation.ExportMade = false;
exportInformation.ErrorMessage = error; exportInformation.ErrorMessage = error;
} }
} catch (Exception ex) { }
catch (Exception ex)
{
exportInformation.ExportMade = false; exportInformation.ExportMade = false;
exportInformation.ErrorMessage = ex.Message; exportInformation.ErrorMessage = ex.Message;
LOG.WarnFormat("Error calling external command: {0} ", exportInformation.ErrorMessage); LOG.WarnFormat("Error calling external command: {0} ", exportInformation.ErrorMessage);
@ -138,18 +166,27 @@ namespace Greenshot.Plugin.ExternalCommand {
/// <param name="output"></param> /// <param name="output"></param>
/// <param name="error"></param> /// <param name="error"></param>
/// <returns></returns> /// <returns></returns>
private int CallExternalCommand(string commando, string fullPath, out string output, out string error) { private int CallExternalCommand(string commando, string fullPath, out string output, out string error)
try { {
try
{
return CallExternalCommand(commando, fullPath, null, out output, out error); return CallExternalCommand(commando, fullPath, null, out output, out error);
} catch (Win32Exception w32Ex) { }
try { catch (Win32Exception w32Ex)
{
try
{
return CallExternalCommand(commando, fullPath, "runas", out output, out error); return CallExternalCommand(commando, fullPath, "runas", out output, out error);
} catch { }
catch
{
w32Ex.Data.Add("commandline", config.Commandline[_presetCommand]); w32Ex.Data.Add("commandline", config.Commandline[_presetCommand]);
w32Ex.Data.Add("arguments", config.Argument[_presetCommand]); w32Ex.Data.Add("arguments", config.Argument[_presetCommand]);
throw; throw;
} }
} catch (Exception ex) { }
catch (Exception ex)
{
ex.Data.Add("commandline", config.Commandline[_presetCommand]); ex.Data.Add("commandline", config.Commandline[_presetCommand]);
ex.Data.Add("arguments", config.Argument[_presetCommand]); ex.Data.Add("arguments", config.Argument[_presetCommand]);
throw; throw;
@ -165,7 +202,8 @@ namespace Greenshot.Plugin.ExternalCommand {
/// <param name="output"></param> /// <param name="output"></param>
/// <param name="error"></param> /// <param name="error"></param>
/// <returns></returns> /// <returns></returns>
private int CallExternalCommand(string commando, string fullPath, string verb, out string output, out string error) { private int CallExternalCommand(string commando, string fullPath, string verb, out string output, out string error)
{
string commandline = config.Commandline[commando]; string commandline = config.Commandline[commando];
string arguments = config.Argument[commando]; string arguments = config.Argument[commando];
output = null; output = null;
@ -183,33 +221,46 @@ namespace Greenshot.Plugin.ExternalCommand {
process.StartInfo.FileName = FilenameHelper.FillCmdVariables(commandline, true); process.StartInfo.FileName = FilenameHelper.FillCmdVariables(commandline, true);
process.StartInfo.Arguments = FormatArguments(arguments, fullPath); process.StartInfo.Arguments = FormatArguments(arguments, fullPath);
process.StartInfo.UseShellExecute = false; process.StartInfo.UseShellExecute = false;
if (config.RedirectStandardOutput) { if (config.RedirectStandardOutput)
{
process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardOutput = true;
} }
if (config.RedirectStandardError) {
if (config.RedirectStandardError)
{
process.StartInfo.RedirectStandardError = true; process.StartInfo.RedirectStandardError = true;
} }
if (verb != null) {
if (verb != null)
{
process.StartInfo.Verb = verb; process.StartInfo.Verb = verb;
} }
LOG.InfoFormat("Starting : {0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); LOG.InfoFormat("Starting : {0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
process.Start(); process.Start();
process.WaitForExit(); process.WaitForExit();
if (config.RedirectStandardOutput) { if (config.RedirectStandardOutput)
{
output = process.StandardOutput.ReadToEnd(); output = process.StandardOutput.ReadToEnd();
if (config.ShowStandardOutputInLog && output.Trim().Length > 0) { if (config.ShowStandardOutputInLog && output.Trim().Length > 0)
{
LOG.InfoFormat("Output:\n{0}", output); LOG.InfoFormat("Output:\n{0}", output);
} }
} }
if (config.RedirectStandardError) {
if (config.RedirectStandardError)
{
error = process.StandardError.ReadToEnd(); error = process.StandardError.ReadToEnd();
if (error.Trim().Length > 0) { if (error.Trim().Length > 0)
{
LOG.WarnFormat("Error:\n{0}", error); LOG.WarnFormat("Error:\n{0}", error);
} }
} }
LOG.InfoFormat("Finished : {0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); LOG.InfoFormat("Finished : {0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
return process.ExitCode; return process.ExitCode;
} }
return -1; return -1;
} }

View file

@ -21,10 +21,12 @@
using GreenshotPlugin.Controls; using GreenshotPlugin.Controls;
namespace Greenshot.Plugin.ExternalCommand { namespace Greenshot.Plugin.ExternalCommand
{
/// <summary> /// <summary>
/// This class is needed for design-time resolving of the language files /// This class is needed for design-time resolving of the language files
/// </summary> /// </summary>
public class ExternalCommandForm : GreenshotForm { public class ExternalCommandForm : GreenshotForm
{
} }
} }

View file

@ -55,6 +55,7 @@ namespace Greenshot.Plugin.ExternalCommand
_itemPlugInRoot.Dispose(); _itemPlugInRoot.Dispose();
_itemPlugInRoot = null; _itemPlugInRoot = null;
} }
private IEnumerable<IDestination> Destinations() private IEnumerable<IDestination> Destinations()
{ {
foreach (string command in ExternalCommandConfig.Commands) foreach (string command in ExternalCommandConfig.Commands)
@ -77,17 +78,20 @@ namespace Greenshot.Plugin.ExternalCommand
// Fix it // Fix it
ExternalCommandConfig.RunInbackground.Add(command, true); ExternalCommandConfig.RunInbackground.Add(command, true);
} }
if (!ExternalCommandConfig.Argument.ContainsKey(command)) if (!ExternalCommandConfig.Argument.ContainsKey(command))
{ {
Log.WarnFormat("Found missing argument for {0}", command); Log.WarnFormat("Found missing argument for {0}", command);
// Fix it // Fix it
ExternalCommandConfig.Argument.Add(command, "{0}"); ExternalCommandConfig.Argument.Add(command, "{0}");
} }
if (!ExternalCommandConfig.Commandline.ContainsKey(command)) if (!ExternalCommandConfig.Commandline.ContainsKey(command))
{ {
Log.WarnFormat("Found missing commandline for {0}", command); Log.WarnFormat("Found missing commandline for {0}", command);
return false; return false;
} }
string commandline = FilenameHelper.FillVariables(ExternalCommandConfig.Commandline[command], true); string commandline = FilenameHelper.FillVariables(ExternalCommandConfig.Commandline[command], true);
commandline = FilenameHelper.FillCmdVariables(commandline, true); commandline = FilenameHelper.FillCmdVariables(commandline, true);
@ -96,8 +100,10 @@ namespace Greenshot.Plugin.ExternalCommand
Log.WarnFormat("Found 'invalid' commandline {0} for command {1}", ExternalCommandConfig.Commandline[command], command); Log.WarnFormat("Found 'invalid' commandline {0} for command {1}", ExternalCommandConfig.Commandline[command], command);
return false; return false;
} }
return true; return true;
} }
/// <summary> /// <summary>
/// Implementation of the IGreenshotPlugin.Initialize /// Implementation of the IGreenshotPlugin.Initialize
/// </summary> /// </summary>
@ -114,11 +120,13 @@ namespace Greenshot.Plugin.ExternalCommand
commandsToDelete.Add(command); commandsToDelete.Add(command);
} }
} }
// cleanup // cleanup
foreach (string command in commandsToDelete) foreach (string command in commandsToDelete)
{ {
ExternalCommandConfig.Delete(command); ExternalCommandConfig.Delete(command);
} }
SimpleServiceProvider.Current.AddService(Destinations()); SimpleServiceProvider.Current.AddService(Destinations());
_itemPlugInRoot = new ToolStripMenuItem(); _itemPlugInRoot = new ToolStripMenuItem();

View file

@ -25,22 +25,31 @@ using System.IO;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.ExternalCommand { namespace Greenshot.Plugin.ExternalCommand
public static class IconCache { {
public static class IconCache
{
private static readonly ExternalCommandConfiguration config = IniConfig.GetIniSection<ExternalCommandConfiguration>(); private static readonly ExternalCommandConfiguration config = IniConfig.GetIniSection<ExternalCommandConfiguration>();
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(IconCache)); private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(IconCache));
public static Image IconForCommand(string commandName) { public static Image IconForCommand(string commandName)
{
Image icon = null; Image icon = null;
if (commandName != null) { if (commandName != null)
if (config.Commandline.ContainsKey(commandName) && File.Exists(config.Commandline[commandName])) { {
try { if (config.Commandline.ContainsKey(commandName) && File.Exists(config.Commandline[commandName]))
{
try
{
icon = PluginUtils.GetCachedExeIcon(config.Commandline[commandName], 0); icon = PluginUtils.GetCachedExeIcon(config.Commandline[commandName], 0);
} catch (Exception ex) { }
catch (Exception ex)
{
LOG.Warn("Problem loading icon for " + config.Commandline[commandName], ex); LOG.Warn("Problem loading icon for " + config.Commandline[commandName], ex);
} }
} }
} }
return icon; return icon;
} }
} }

View file

@ -24,14 +24,17 @@ using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.ExternalCommand { namespace Greenshot.Plugin.ExternalCommand
{
/// <summary> /// <summary>
/// Description of SettingsForm. /// Description of SettingsForm.
/// </summary> /// </summary>
public partial class SettingsForm : ExternalCommandForm { public partial class SettingsForm : ExternalCommandForm
{
private static readonly ExternalCommandConfiguration ExternalCommandConfig = IniConfig.GetIniSection<ExternalCommandConfiguration>(); private static readonly ExternalCommandConfiguration ExternalCommandConfig = IniConfig.GetIniSection<ExternalCommandConfiguration>();
public SettingsForm() { public SettingsForm()
{
// //
// The InitializeComponent() call is required for Windows Forms designer support. // The InitializeComponent() call is required for Windows Forms designer support.
// //
@ -41,65 +44,83 @@ namespace Greenshot.Plugin.ExternalCommand {
UpdateView(); UpdateView();
} }
private void ButtonOkClick(object sender, EventArgs e) { private void ButtonOkClick(object sender, EventArgs e)
{
IniConfig.Save(); IniConfig.Save();
} }
private void ButtonAddClick(object sender, EventArgs e) { private void ButtonAddClick(object sender, EventArgs e)
{
var form = new SettingsFormDetail(null); var form = new SettingsFormDetail(null);
form.ShowDialog(); form.ShowDialog();
UpdateView(); UpdateView();
} }
private void ButtonDeleteClick(object sender, EventArgs e) { private void ButtonDeleteClick(object sender, EventArgs e)
foreach(ListViewItem item in listView1.SelectedItems) { {
foreach (ListViewItem item in listView1.SelectedItems)
{
string commando = item.Tag as string; string commando = item.Tag as string;
ExternalCommandConfig.Delete(commando); ExternalCommandConfig.Delete(commando);
} }
UpdateView(); UpdateView();
} }
private void UpdateView() { private void UpdateView()
{
listView1.Items.Clear(); listView1.Items.Clear();
if(ExternalCommandConfig.Commands != null) { if (ExternalCommandConfig.Commands != null)
{
listView1.ListViewItemSorter = new ListviewComparer(); listView1.ListViewItemSorter = new ListviewComparer();
ImageList imageList = new ImageList(); ImageList imageList = new ImageList();
listView1.SmallImageList = imageList; listView1.SmallImageList = imageList;
int imageNr = 0; int imageNr = 0;
foreach(string commando in ExternalCommandConfig.Commands) { foreach (string commando in ExternalCommandConfig.Commands)
{
ListViewItem item; ListViewItem item;
Image iconForExe = IconCache.IconForCommand(commando); Image iconForExe = IconCache.IconForCommand(commando);
if(iconForExe != null) { if (iconForExe != null)
{
imageList.Images.Add(iconForExe); imageList.Images.Add(iconForExe);
item = new ListViewItem(commando, imageNr++); item = new ListViewItem(commando, imageNr++);
} else { }
else
{
item = new ListViewItem(commando); item = new ListViewItem(commando);
} }
item.Tag = commando; item.Tag = commando;
listView1.Items.Add(item); listView1.Items.Add(item);
} }
} }
// Fix for bug #1484, getting an ArgumentOutOfRangeException as there is nothing selected but the edit button was still active. // Fix for bug #1484, getting an ArgumentOutOfRangeException as there is nothing selected but the edit button was still active.
button_edit.Enabled = listView1.SelectedItems.Count > 0; button_edit.Enabled = listView1.SelectedItems.Count > 0;
} }
private void ListView1ItemSelectionChanged(object sender, EventArgs e) { private void ListView1ItemSelectionChanged(object sender, EventArgs e)
{
button_edit.Enabled = listView1.SelectedItems.Count > 0; button_edit.Enabled = listView1.SelectedItems.Count > 0;
} }
private void ButtonEditClick(object sender, EventArgs e) { private void ButtonEditClick(object sender, EventArgs e)
{
ListView1DoubleClick(sender, e); ListView1DoubleClick(sender, e);
} }
private void ListView1DoubleClick(object sender, EventArgs e) { private void ListView1DoubleClick(object sender, EventArgs e)
{
// Safety check for bug #1484 // Safety check for bug #1484
bool selectionActive = listView1.SelectedItems.Count > 0; bool selectionActive = listView1.SelectedItems.Count > 0;
if(!selectionActive) { if (!selectionActive)
{
button_edit.Enabled = false; button_edit.Enabled = false;
return; return;
} }
string commando = listView1.SelectedItems[0].Tag as string; string commando = listView1.SelectedItems[0].Tag as string;
var form = new SettingsFormDetail(commando); var form = new SettingsFormDetail(commando);
@ -109,12 +130,17 @@ namespace Greenshot.Plugin.ExternalCommand {
} }
} }
public class ListviewComparer : System.Collections.IComparer { public class ListviewComparer : System.Collections.IComparer
public int Compare(object x, object y) { {
if(!(x is ListViewItem)) { public int Compare(object x, object y)
{
if (!(x is ListViewItem))
{
return (0); return (0);
} }
if(!(y is ListViewItem)) {
if (!(y is ListViewItem))
{
return (0); return (0);
} }

View file

@ -26,52 +26,64 @@ using System.Windows.Forms;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.ExternalCommand { namespace Greenshot.Plugin.ExternalCommand
{
/// <summary> /// <summary>
/// Description of SettingsFormDetail. /// Description of SettingsFormDetail.
/// </summary> /// </summary>
public partial class SettingsFormDetail : ExternalCommandForm { public partial class SettingsFormDetail : ExternalCommandForm
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(SettingsFormDetail)); private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(SettingsFormDetail));
private static readonly ExternalCommandConfiguration ExternalCommandConfig = IniConfig.GetIniSection<ExternalCommandConfiguration>(); private static readonly ExternalCommandConfiguration ExternalCommandConfig = IniConfig.GetIniSection<ExternalCommandConfiguration>();
private readonly string _commando; private readonly string _commando;
private readonly int _commandIndex; private readonly int _commandIndex;
public SettingsFormDetail(string commando) { public SettingsFormDetail(string commando)
{
InitializeComponent(); InitializeComponent();
AcceptButton = buttonOk; AcceptButton = buttonOk;
CancelButton = buttonCancel; CancelButton = buttonCancel;
_commando = commando; _commando = commando;
if(commando != null) { if (commando != null)
{
textBox_name.Text = commando; textBox_name.Text = commando;
textBox_commandline.Text = ExternalCommandConfig.Commandline[commando]; textBox_commandline.Text = ExternalCommandConfig.Commandline[commando];
textBox_arguments.Text = ExternalCommandConfig.Argument[commando]; textBox_arguments.Text = ExternalCommandConfig.Argument[commando];
_commandIndex = ExternalCommandConfig.Commands.FindIndex(s => s == commando); _commandIndex = ExternalCommandConfig.Commands.FindIndex(s => s == commando);
} else { }
else
{
textBox_arguments.Text = "\"{0}\""; textBox_arguments.Text = "\"{0}\"";
} }
OkButtonState(); OkButtonState();
} }
private void ButtonOkClick(object sender, EventArgs e) { private void ButtonOkClick(object sender, EventArgs e)
{
string commandName = textBox_name.Text; string commandName = textBox_name.Text;
string commandLine = textBox_commandline.Text; string commandLine = textBox_commandline.Text;
string arguments = textBox_arguments.Text; string arguments = textBox_arguments.Text;
if(_commando != null) { if (_commando != null)
{
ExternalCommandConfig.Commands[_commandIndex] = commandName; ExternalCommandConfig.Commands[_commandIndex] = commandName;
ExternalCommandConfig.Commandline.Remove(_commando); ExternalCommandConfig.Commandline.Remove(_commando);
ExternalCommandConfig.Commandline.Add(commandName, commandLine); ExternalCommandConfig.Commandline.Add(commandName, commandLine);
ExternalCommandConfig.Argument.Remove(_commando); ExternalCommandConfig.Argument.Remove(_commando);
ExternalCommandConfig.Argument.Add(commandName, arguments); ExternalCommandConfig.Argument.Add(commandName, arguments);
} else { }
else
{
ExternalCommandConfig.Commands.Add(commandName); ExternalCommandConfig.Commands.Add(commandName);
ExternalCommandConfig.Commandline.Add(commandName, commandLine); ExternalCommandConfig.Commandline.Add(commandName, commandLine);
ExternalCommandConfig.Argument.Add(commandName, arguments); ExternalCommandConfig.Argument.Add(commandName, arguments);
} }
} }
private void Button3Click(object sender, EventArgs e) { private void Button3Click(object sender, EventArgs e)
{
var openFileDialog = new OpenFileDialog var openFileDialog = new OpenFileDialog
{ {
Filter = "Executables (*.exe, *.bat, *.com)|*.exe; *.bat; *.com|All files (*)|*", Filter = "Executables (*.exe, *.bat, *.com)|*.exe; *.bat; *.com|All files (*)|*",
@ -89,35 +101,47 @@ namespace Greenshot.Plugin.ExternalCommand {
Log.WarnFormat("Can't get the initial path via {0}", textBox_commandline.Text); Log.WarnFormat("Can't get the initial path via {0}", textBox_commandline.Text);
Log.Warn("Exception: ", ex); Log.Warn("Exception: ", ex);
} }
if(initialPath != null && Directory.Exists(initialPath)) {
if (initialPath != null && Directory.Exists(initialPath))
{
openFileDialog.InitialDirectory = initialPath; openFileDialog.InitialDirectory = initialPath;
} else { }
else
{
initialPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); initialPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
openFileDialog.InitialDirectory = initialPath; openFileDialog.InitialDirectory = initialPath;
} }
Log.DebugFormat("Starting OpenFileDialog at {0}", initialPath); Log.DebugFormat("Starting OpenFileDialog at {0}", initialPath);
if(openFileDialog.ShowDialog() == DialogResult.OK) { if (openFileDialog.ShowDialog() == DialogResult.OK)
{
textBox_commandline.Text = openFileDialog.FileName; textBox_commandline.Text = openFileDialog.FileName;
} }
} }
private void OkButtonState() { private void OkButtonState()
{
// Assume OK // Assume OK
buttonOk.Enabled = true; buttonOk.Enabled = true;
textBox_name.BackColor = Color.White; textBox_name.BackColor = Color.White;
textBox_commandline.BackColor = Color.White; textBox_commandline.BackColor = Color.White;
textBox_arguments.BackColor = Color.White; textBox_arguments.BackColor = Color.White;
// Is there a text in the name field // Is there a text in the name field
if(string.IsNullOrEmpty(textBox_name.Text)) { if (string.IsNullOrEmpty(textBox_name.Text))
{
buttonOk.Enabled = false; buttonOk.Enabled = false;
} }
// Check if commandname is unique // Check if commandname is unique
if(_commando == null && !string.IsNullOrEmpty(textBox_name.Text) && ExternalCommandConfig.Commands.Contains(textBox_name.Text)) { if (_commando == null && !string.IsNullOrEmpty(textBox_name.Text) && ExternalCommandConfig.Commands.Contains(textBox_name.Text))
{
buttonOk.Enabled = false; buttonOk.Enabled = false;
textBox_name.BackColor = Color.Red; textBox_name.BackColor = Color.Red;
} }
// Is there a text in the commandline field // Is there a text in the commandline field
if(string.IsNullOrEmpty(textBox_commandline.Text)) { if (string.IsNullOrEmpty(textBox_commandline.Text))
{
buttonOk.Enabled = false; buttonOk.Enabled = false;
} }
@ -134,6 +158,7 @@ namespace Greenshot.Plugin.ExternalCommand {
textBox_commandline.BackColor = Color.Red; textBox_commandline.BackColor = Color.Red;
} }
} }
// Are the arguments in a valid format? // Are the arguments in a valid format?
try try
{ {
@ -149,11 +174,13 @@ namespace Greenshot.Plugin.ExternalCommand {
} }
} }
private void textBox_name_TextChanged(object sender, EventArgs e) { private void textBox_name_TextChanged(object sender, EventArgs e)
{
OkButtonState(); OkButtonState();
} }
private void textBox_commandline_TextChanged(object sender, EventArgs e) { private void textBox_commandline_TextChanged(object sender, EventArgs e)
{
OkButtonState(); OkButtonState();
} }
@ -161,6 +188,5 @@ namespace Greenshot.Plugin.ExternalCommand {
{ {
OkButtonState(); OkButtonState();
} }
} }
} }

View file

@ -24,17 +24,21 @@ using Greenshot.Plugin.Flickr.Forms;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.Flickr { namespace Greenshot.Plugin.Flickr
public enum SafetyLevel { {
public enum SafetyLevel
{
Safe = 1, Safe = 1,
Moderate = 2, Moderate = 2,
Restricted = 3 Restricted = 3
} }
/// <summary> /// <summary>
/// Description of FlickrConfiguration. /// Description of FlickrConfiguration.
/// </summary> /// </summary>
[IniSection("Flickr", Description = "Greenshot Flickr Plugin configuration")] [IniSection("Flickr", Description = "Greenshot Flickr Plugin configuration")]
public class FlickrConfiguration : IniSection { public class FlickrConfiguration : IniSection
{
[IniProperty("flickrIsPublic", Description = "IsPublic.", DefaultValue = "true")] [IniProperty("flickrIsPublic", Description = "IsPublic.", DefaultValue = "true")]
public bool IsPublic { get; set; } public bool IsPublic { get; set; }
@ -64,6 +68,7 @@ namespace Greenshot.Plugin.Flickr {
[IniProperty("FlickrToken", Description = "The Flickr token", Encrypted = true, ExcludeIfNull = true)] [IniProperty("FlickrToken", Description = "The Flickr token", Encrypted = true, ExcludeIfNull = true)]
public string FlickrToken { get; set; } public string FlickrToken { get; set; }
[IniProperty("FlickrTokenSecret", Description = "The Flickr token secret", Encrypted = true, ExcludeIfNull = true)] [IniProperty("FlickrTokenSecret", Description = "The Flickr token secret", Encrypted = true, ExcludeIfNull = true)]
public string FlickrTokenSecret { get; set; } public string FlickrTokenSecret { get; set; }
@ -71,11 +76,14 @@ namespace Greenshot.Plugin.Flickr {
/// A form for token /// A form for token
/// </summary> /// </summary>
/// <returns>bool true if OK was pressed, false if cancel</returns> /// <returns>bool true if OK was pressed, false if cancel</returns>
public bool ShowConfigDialog() { public bool ShowConfigDialog()
{
DialogResult result = new SettingsForm().ShowDialog(); DialogResult result = new SettingsForm().ShowDialog();
if (result == DialogResult.OK) { if (result == DialogResult.OK)
{
return true; return true;
} }
return false; return false;
} }
} }

View file

@ -24,10 +24,14 @@ using System.Drawing;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
namespace Greenshot.Plugin.Flickr { namespace Greenshot.Plugin.Flickr
public class FlickrDestination : AbstractDestination { {
public class FlickrDestination : AbstractDestination
{
private readonly FlickrPlugin _plugin; private readonly FlickrPlugin _plugin;
public FlickrDestination(FlickrPlugin plugin) {
public FlickrDestination(FlickrPlugin plugin)
{
_plugin = plugin; _plugin = plugin;
} }
@ -35,20 +39,25 @@ namespace Greenshot.Plugin.Flickr {
public override string Description => Language.GetString("flickr", LangKey.upload_menu_item); public override string Description => Language.GetString("flickr", LangKey.upload_menu_item);
public override Image DisplayIcon { public override Image DisplayIcon
get { {
get
{
ComponentResourceManager resources = new ComponentResourceManager(typeof(FlickrPlugin)); ComponentResourceManager resources = new ComponentResourceManager(typeof(FlickrPlugin));
return (Image) resources.GetObject("flickr"); return (Image) resources.GetObject("flickr");
} }
} }
public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails)
{
ExportInformation exportInformation = new ExportInformation(Designation, Description); ExportInformation exportInformation = new ExportInformation(Designation, Description);
bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl); bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl);
if (uploaded) { if (uploaded)
{
exportInformation.ExportMade = true; exportInformation.ExportMade = true;
exportInformation.Uri = uploadUrl; exportInformation.Uri = uploadUrl;
} }
ProcessExport(exportInformation, surface); ProcessExport(exportInformation, surface);
return exportInformation; return exportInformation;
} }

View file

@ -37,24 +37,31 @@ namespace Greenshot.Plugin.Flickr
/// This is the Flickr base code /// This is the Flickr base code
/// </summary> /// </summary>
[Plugin("Flickr", true)] [Plugin("Flickr", true)]
public class FlickrPlugin : IGreenshotPlugin { public class FlickrPlugin : IGreenshotPlugin
{
private static readonly ILog Log = LogManager.GetLogger(typeof(FlickrPlugin)); private static readonly ILog Log = LogManager.GetLogger(typeof(FlickrPlugin));
private static FlickrConfiguration _config; private static FlickrConfiguration _config;
private ComponentResourceManager _resources; private ComponentResourceManager _resources;
private ToolStripMenuItem _itemPlugInConfig; private ToolStripMenuItem _itemPlugInConfig;
public void Dispose() { public void Dispose()
{
Dispose(true); Dispose(true);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
protected void Dispose(bool disposing) { protected void Dispose(bool disposing)
if (!disposing) { {
if (!disposing)
{
return; return;
} }
if (_itemPlugInConfig == null) {
if (_itemPlugInConfig == null)
{
return; return;
} }
_itemPlugInConfig.Dispose(); _itemPlugInConfig.Dispose();
_itemPlugInConfig = null; _itemPlugInConfig = null;
} }
@ -62,7 +69,8 @@ namespace Greenshot.Plugin.Flickr
/// <summary> /// <summary>
/// Implementation of the IGreenshotPlugin.Initialize /// Implementation of the IGreenshotPlugin.Initialize
/// </summary> /// </summary>
public bool Initialize() { public bool Initialize()
{
// Register configuration (don't need the configuration itself) // Register configuration (don't need the configuration itself)
_config = IniConfig.GetIniSection<FlickrConfiguration>(); _config = IniConfig.GetIniSection<FlickrConfiguration>();
_resources = new ComponentResourceManager(typeof(FlickrPlugin)); _resources = new ComponentResourceManager(typeof(FlickrPlugin));
@ -79,52 +87,67 @@ namespace Greenshot.Plugin.Flickr
return true; return true;
} }
public void OnLanguageChanged(object sender, EventArgs e) { public void OnLanguageChanged(object sender, EventArgs e)
if (_itemPlugInConfig != null) { {
if (_itemPlugInConfig != null)
{
_itemPlugInConfig.Text = Language.GetString("flickr", LangKey.Configure); _itemPlugInConfig.Text = Language.GetString("flickr", LangKey.Configure);
} }
} }
public void Shutdown() { public void Shutdown()
{
Log.Debug("Flickr Plugin shutdown."); Log.Debug("Flickr Plugin shutdown.");
} }
/// <summary> /// <summary>
/// Implementation of the IPlugin.Configure /// Implementation of the IPlugin.Configure
/// </summary> /// </summary>
public void Configure() { public void Configure()
{
_config.ShowConfigDialog(); _config.ShowConfigDialog();
} }
public void ConfigMenuClick(object sender, EventArgs eventArgs) { public void ConfigMenuClick(object sender, EventArgs eventArgs)
{
_config.ShowConfigDialog(); _config.ShowConfigDialog();
} }
public bool Upload(ICaptureDetails captureDetails, ISurface surface, out string uploadUrl) { public bool Upload(ICaptureDetails captureDetails, ISurface surface, out string uploadUrl)
{
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, false); SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, false);
uploadUrl = null; uploadUrl = null;
try { try
{
string flickrUrl = null; string flickrUrl = null;
new PleaseWaitForm().ShowAndWait("Flickr", Language.GetString("flickr", LangKey.communication_wait), new PleaseWaitForm().ShowAndWait("Flickr", Language.GetString("flickr", LangKey.communication_wait),
delegate { delegate
{
string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails)); string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails));
flickrUrl = FlickrUtils.UploadToFlickr(surface, outputSettings, captureDetails.Title, filename); flickrUrl = FlickrUtils.UploadToFlickr(surface, outputSettings, captureDetails.Title, filename);
} }
); );
if (flickrUrl == null) { if (flickrUrl == null)
{
return false; return false;
} }
uploadUrl = flickrUrl; uploadUrl = flickrUrl;
if (_config.AfterUploadLinkToClipBoard) { if (_config.AfterUploadLinkToClipBoard)
{
ClipboardHelper.SetClipboardData(flickrUrl); ClipboardHelper.SetClipboardData(flickrUrl);
} }
return true; return true;
} catch (Exception e) { }
catch (Exception e)
{
Log.Error("Error uploading.", e); Log.Error("Error uploading.", e);
MessageBox.Show(Language.GetString("flickr", LangKey.upload_failure) + " " + e.Message); MessageBox.Show(Language.GetString("flickr", LangKey.upload_failure) + " " + e.Message);
} }
return false; return false;
} }
} }

View file

@ -30,21 +30,27 @@ using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin; using GreenshotPlugin.Interfaces.Plugin;
using log4net; using log4net;
namespace Greenshot.Plugin.Flickr { namespace Greenshot.Plugin.Flickr
{
/// <summary> /// <summary>
/// Description of FlickrUtils. /// Description of FlickrUtils.
/// </summary> /// </summary>
public static class FlickrUtils { public static class FlickrUtils
{
private static readonly ILog LOG = LogManager.GetLogger(typeof(FlickrUtils)); private static readonly ILog LOG = LogManager.GetLogger(typeof(FlickrUtils));
private static readonly FlickrConfiguration config = IniConfig.GetIniSection<FlickrConfiguration>(); private static readonly FlickrConfiguration config = IniConfig.GetIniSection<FlickrConfiguration>();
private const string FLICKR_API_BASE_URL = "https://api.flickr.com/services/"; private const string FLICKR_API_BASE_URL = "https://api.flickr.com/services/";
private const string FLICKR_UPLOAD_URL = FLICKR_API_BASE_URL + "upload/"; private const string FLICKR_UPLOAD_URL = FLICKR_API_BASE_URL + "upload/";
// OAUTH // OAUTH
private const string FLICKR_OAUTH_BASE_URL = FLICKR_API_BASE_URL + "oauth/"; private const string FLICKR_OAUTH_BASE_URL = FLICKR_API_BASE_URL + "oauth/";
private const string FLICKR_ACCESS_TOKEN_URL = FLICKR_OAUTH_BASE_URL + "access_token"; private const string FLICKR_ACCESS_TOKEN_URL = FLICKR_OAUTH_BASE_URL + "access_token";
private const string FLICKR_AUTHORIZE_URL = FLICKR_OAUTH_BASE_URL + "authorize"; private const string FLICKR_AUTHORIZE_URL = FLICKR_OAUTH_BASE_URL + "authorize";
private const string FLICKR_REQUEST_TOKEN_URL = FLICKR_OAUTH_BASE_URL + "request_token"; private const string FLICKR_REQUEST_TOKEN_URL = FLICKR_OAUTH_BASE_URL + "request_token";
private const string FLICKR_FARM_URL = "https://farm{0}.staticflickr.com/{1}/{2}_{3}_o.{4}"; private const string FLICKR_FARM_URL = "https://farm{0}.staticflickr.com/{1}/{2}_{3}_o.{4}";
// REST // REST
private const string FLICKR_REST_URL = FLICKR_API_BASE_URL + "rest/"; private const string FLICKR_REST_URL = FLICKR_API_BASE_URL + "rest/";
private const string FLICKR_GET_INFO_URL = FLICKR_REST_URL + "?method=flickr.photos.getInfo"; private const string FLICKR_GET_INFO_URL = FLICKR_REST_URL + "?method=flickr.photos.getInfo";
@ -58,7 +64,8 @@ namespace Greenshot.Plugin.Flickr {
/// <param name="title"></param> /// <param name="title"></param>
/// <param name="filename"></param> /// <param name="filename"></param>
/// <returns>url to image</returns> /// <returns>url to image</returns>
public static string UploadToFlickr(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename) { public static string UploadToFlickr(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename)
{
var oAuth = new OAuthSession(FlickrCredentials.ConsumerKey, FlickrCredentials.ConsumerSecret) var oAuth = new OAuthSession(FlickrCredentials.ConsumerKey, FlickrCredentials.ConsumerSecret)
{ {
BrowserSize = new Size(520, 800), BrowserSize = new Size(520, 800),
@ -70,70 +77,116 @@ namespace Greenshot.Plugin.Flickr {
Token = config.FlickrToken, Token = config.FlickrToken,
TokenSecret = config.FlickrTokenSecret TokenSecret = config.FlickrTokenSecret
}; };
if (string.IsNullOrEmpty(oAuth.Token)) { if (string.IsNullOrEmpty(oAuth.Token))
if (!oAuth.Authorize()) { {
if (!oAuth.Authorize())
{
return null; return null;
} }
if (!string.IsNullOrEmpty(oAuth.Token)) {
if (!string.IsNullOrEmpty(oAuth.Token))
{
config.FlickrToken = oAuth.Token; config.FlickrToken = oAuth.Token;
} }
if (!string.IsNullOrEmpty(oAuth.TokenSecret)) {
if (!string.IsNullOrEmpty(oAuth.TokenSecret))
{
config.FlickrTokenSecret = oAuth.TokenSecret; config.FlickrTokenSecret = oAuth.TokenSecret;
} }
IniConfig.Save(); IniConfig.Save();
} }
try {
try
{
IDictionary<string, object> signedParameters = new Dictionary<string, object> IDictionary<string, object> signedParameters = new Dictionary<string, object>
{ {
{ "content_type", "2" }, // Screenshot {
{ "tags", "Greenshot" }, "content_type", "2"
{ "is_public", config.IsPublic ? "1" : "0" }, }, // Screenshot
{ "is_friend", config.IsFriend ? "1" : "0" }, {
{ "is_family", config.IsFamily ? "1" : "0" }, "tags", "Greenshot"
{ "safety_level", $"{(int)config.SafetyLevel}" }, },
{ "hidden", config.HiddenFromSearch ? "1" : "2" } {
"is_public", config.IsPublic ? "1" : "0"
},
{
"is_friend", config.IsFriend ? "1" : "0"
},
{
"is_family", config.IsFamily ? "1" : "0"
},
{
"safety_level", $"{(int) config.SafetyLevel}"
},
{
"hidden", config.HiddenFromSearch ? "1" : "2"
}
}; };
IDictionary<string, object> otherParameters = new Dictionary<string, object> IDictionary<string, object> otherParameters = new Dictionary<string, object>
{ {
{ "photo", new SurfaceContainer(surfaceToUpload, outputSettings, filename) } {
"photo", new SurfaceContainer(surfaceToUpload, outputSettings, filename)
}
}; };
string response = oAuth.MakeOAuthRequest(HTTPMethod.POST, FLICKR_UPLOAD_URL, signedParameters, otherParameters, null); string response = oAuth.MakeOAuthRequest(HTTPMethod.POST, FLICKR_UPLOAD_URL, signedParameters, otherParameters, null);
string photoId = GetPhotoId(response); string photoId = GetPhotoId(response);
// Get Photo Info // Get Photo Info
signedParameters = new Dictionary<string, object> { { "photo_id", photoId } }; signedParameters = new Dictionary<string, object>
{
{
"photo_id", photoId
}
};
string photoInfo = oAuth.MakeOAuthRequest(HTTPMethod.POST, FLICKR_GET_INFO_URL, signedParameters, null, null); string photoInfo = oAuth.MakeOAuthRequest(HTTPMethod.POST, FLICKR_GET_INFO_URL, signedParameters, null, null);
return GetUrl(photoInfo); return GetUrl(photoInfo);
} catch (Exception ex) { }
catch (Exception ex)
{
LOG.Error("Upload error: ", ex); LOG.Error("Upload error: ", ex);
throw; throw;
} finally { }
if (!string.IsNullOrEmpty(oAuth.Token)) { finally
{
if (!string.IsNullOrEmpty(oAuth.Token))
{
config.FlickrToken = oAuth.Token; config.FlickrToken = oAuth.Token;
} }
if (!string.IsNullOrEmpty(oAuth.TokenSecret)) {
if (!string.IsNullOrEmpty(oAuth.TokenSecret))
{
config.FlickrTokenSecret = oAuth.TokenSecret; config.FlickrTokenSecret = oAuth.TokenSecret;
} }
} }
} }
private static string GetUrl(string response) { private static string GetUrl(string response)
try { {
try
{
XmlDocument doc = new XmlDocument(); XmlDocument doc = new XmlDocument();
doc.LoadXml(response); doc.LoadXml(response);
if (config.UsePageLink) { if (config.UsePageLink)
{
XmlNodeList nodes = doc.GetElementsByTagName("url"); XmlNodeList nodes = doc.GetElementsByTagName("url");
if (nodes.Count > 0) { if (nodes.Count > 0)
{
var xmlNode = nodes.Item(0); var xmlNode = nodes.Item(0);
if (xmlNode != null) { if (xmlNode != null)
{
return xmlNode.InnerText; return xmlNode.InnerText;
} }
} }
} else { }
else
{
XmlNodeList nodes = doc.GetElementsByTagName("photo"); XmlNodeList nodes = doc.GetElementsByTagName("photo");
if (nodes.Count > 0) { if (nodes.Count > 0)
{
var item = nodes.Item(0); var item = nodes.Item(0);
if (item?.Attributes != null) { if (item?.Attributes != null)
{
string farmId = item.Attributes["farm"].Value; string farmId = item.Attributes["farm"].Value;
string serverId = item.Attributes["server"].Value; string serverId = item.Attributes["server"].Value;
string photoId = item.Attributes["id"].Value; string photoId = item.Attributes["id"].Value;
@ -143,26 +196,36 @@ namespace Greenshot.Plugin.Flickr {
} }
} }
} }
} catch (Exception ex) { }
catch (Exception ex)
{
LOG.Error("Error parsing Flickr Response.", ex); LOG.Error("Error parsing Flickr Response.", ex);
} }
return null; return null;
} }
private static string GetPhotoId(string response) { private static string GetPhotoId(string response)
try { {
try
{
XmlDocument doc = new XmlDocument(); XmlDocument doc = new XmlDocument();
doc.LoadXml(response); doc.LoadXml(response);
XmlNodeList nodes = doc.GetElementsByTagName("photoid"); XmlNodeList nodes = doc.GetElementsByTagName("photoid");
if (nodes.Count > 0) { if (nodes.Count > 0)
{
var xmlNode = nodes.Item(0); var xmlNode = nodes.Item(0);
if (xmlNode != null) { if (xmlNode != null)
{
return xmlNode.InnerText; return xmlNode.InnerText;
} }
} }
} catch (Exception ex) { }
catch (Exception ex)
{
LOG.Error("Error parsing Flickr Response.", ex); LOG.Error("Error parsing Flickr Response.", ex);
} }
return null; return null;
} }
} }

View file

@ -21,7 +21,9 @@
using GreenshotPlugin.Controls; using GreenshotPlugin.Controls;
namespace Greenshot.Plugin.Flickr.Forms { namespace Greenshot.Plugin.Flickr.Forms
public class FlickrForm : GreenshotForm { {
public class FlickrForm : GreenshotForm
{
} }
} }

View file

@ -19,12 +19,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace Greenshot.Plugin.Flickr.Forms { namespace Greenshot.Plugin.Flickr.Forms
{
/// <summary> /// <summary>
/// Description of PasswordRequestForm. /// Description of PasswordRequestForm.
/// </summary> /// </summary>
public partial class SettingsForm : FlickrForm { public partial class SettingsForm : FlickrForm
public SettingsForm() { {
public SettingsForm()
{
// //
// The InitializeComponent() call is required for Windows Forms designer support. // The InitializeComponent() call is required for Windows Forms designer support.
// //
@ -32,6 +35,5 @@ namespace Greenshot.Plugin.Flickr.Forms {
CancelButton = buttonCancel; CancelButton = buttonCancel;
AcceptButton = buttonOK; AcceptButton = buttonOK;
} }
} }
} }

View file

@ -18,8 +18,11 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace Greenshot.Plugin.Flickr {
public enum LangKey { namespace Greenshot.Plugin.Flickr
{
public enum LangKey
{
upload_menu_item, upload_menu_item,
upload_failure, upload_failure,
communication_wait, communication_wait,

View file

@ -20,7 +20,9 @@
using GreenshotPlugin.Controls; using GreenshotPlugin.Controls;
namespace Greenshot.Plugin.GooglePhotos.Forms { namespace Greenshot.Plugin.GooglePhotos.Forms
public class GooglePhotosForm : GreenshotForm { {
public class GooglePhotosForm : GreenshotForm
{
} }
} }

View file

@ -18,12 +18,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace Greenshot.Plugin.GooglePhotos.Forms { namespace Greenshot.Plugin.GooglePhotos.Forms
{
/// <summary> /// <summary>
/// Description of PasswordRequestForm. /// Description of PasswordRequestForm.
/// </summary> /// </summary>
public partial class SettingsForm : GooglePhotosForm { public partial class SettingsForm : GooglePhotosForm
{
public SettingsForm() public SettingsForm()
{ {
// //
@ -33,6 +34,5 @@ namespace Greenshot.Plugin.GooglePhotos.Forms {
CancelButton = buttonCancel; CancelButton = buttonCancel;
AcceptButton = buttonOK; AcceptButton = buttonOK;
} }
} }
} }

View file

@ -24,12 +24,14 @@ using Greenshot.Plugin.GooglePhotos.Forms;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.GooglePhotos { namespace Greenshot.Plugin.GooglePhotos
{
/// <summary> /// <summary>
/// Description of GooglePhotosConfiguration. /// Description of GooglePhotosConfiguration.
/// </summary> /// </summary>
[IniSection("GooglePhotos", Description = "Greenshot GooglePhotos Plugin configuration")] [IniSection("GooglePhotos", Description = "Greenshot GooglePhotos Plugin configuration")]
public class GooglePhotosConfiguration : IniSection { public class GooglePhotosConfiguration : IniSection
{
[IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")]
public OutputFormat UploadFormat { get; set; } public OutputFormat UploadFormat { get; set; }
@ -38,57 +40,42 @@ namespace Greenshot.Plugin.GooglePhotos {
[IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send GooglePhotos link to clipboard.", DefaultValue = "true")] [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send GooglePhotos link to clipboard.", DefaultValue = "true")]
public bool AfterUploadLinkToClipBoard { get; set; } public bool AfterUploadLinkToClipBoard { get; set; }
[IniProperty("AddFilename", Description = "Is the filename passed on to GooglePhotos", DefaultValue = "False")] [IniProperty("AddFilename", Description = "Is the filename passed on to GooglePhotos", DefaultValue = "False")]
public bool AddFilename { public bool AddFilename { get; set; }
get;
set;
}
[IniProperty("UploadUser", Description = "The GooglePhotos user to upload to", DefaultValue = "default")] [IniProperty("UploadUser", Description = "The GooglePhotos user to upload to", DefaultValue = "default")]
public string UploadUser { public string UploadUser { get; set; }
get;
set;
}
[IniProperty("UploadAlbum", Description = "The GooglePhotos album to upload to", DefaultValue = "default")] [IniProperty("UploadAlbum", Description = "The GooglePhotos album to upload to", DefaultValue = "default")]
public string UploadAlbum { public string UploadAlbum { get; set; }
get;
set;
}
[IniProperty("RefreshToken", Description = "GooglePhotos authorization refresh Token", Encrypted = true)] [IniProperty("RefreshToken", Description = "GooglePhotos authorization refresh Token", Encrypted = true)]
public string RefreshToken { public string RefreshToken { get; set; }
get;
set;
}
/// <summary> /// <summary>
/// Not stored /// Not stored
/// </summary> /// </summary>
public string AccessToken { public string AccessToken { get; set; }
get;
set;
}
/// <summary> /// <summary>
/// Not stored /// Not stored
/// </summary> /// </summary>
public DateTimeOffset AccessTokenExpires { public DateTimeOffset AccessTokenExpires { get; set; }
get;
set;
}
/// <summary> /// <summary>
/// A form for token /// A form for token
/// </summary> /// </summary>
/// <returns>bool true if OK was pressed, false if cancel</returns> /// <returns>bool true if OK was pressed, false if cancel</returns>
public bool ShowConfigDialog() { public bool ShowConfigDialog()
{
DialogResult result = new SettingsForm().ShowDialog(); DialogResult result = new SettingsForm().ShowDialog();
if (result == DialogResult.OK) { if (result == DialogResult.OK)
{
return true; return true;
} }
return false; return false;
} }
} }
} }

View file

@ -23,10 +23,14 @@ using System.Drawing;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
namespace Greenshot.Plugin.GooglePhotos { namespace Greenshot.Plugin.GooglePhotos
public class GooglePhotosDestination : AbstractDestination { {
public class GooglePhotosDestination : AbstractDestination
{
private readonly GooglePhotosPlugin _plugin; private readonly GooglePhotosPlugin _plugin;
public GooglePhotosDestination(GooglePhotosPlugin plugin) {
public GooglePhotosDestination(GooglePhotosPlugin plugin)
{
_plugin = plugin; _plugin = plugin;
} }
@ -34,20 +38,25 @@ namespace Greenshot.Plugin.GooglePhotos {
public override string Description => Language.GetString("googlephotos", LangKey.upload_menu_item); public override string Description => Language.GetString("googlephotos", LangKey.upload_menu_item);
public override Image DisplayIcon { public override Image DisplayIcon
get { {
get
{
ComponentResourceManager resources = new ComponentResourceManager(typeof(GooglePhotosPlugin)); ComponentResourceManager resources = new ComponentResourceManager(typeof(GooglePhotosPlugin));
return (Image) resources.GetObject("GooglePhotos"); return (Image) resources.GetObject("GooglePhotos");
} }
} }
public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails)
{
ExportInformation exportInformation = new ExportInformation(Designation, Description); ExportInformation exportInformation = new ExportInformation(Designation, Description);
bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl); bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl);
if (uploaded) { if (uploaded)
{
exportInformation.ExportMade = true; exportInformation.ExportMade = true;
exportInformation.Uri = uploadUrl; exportInformation.Uri = uploadUrl;
} }
ProcessExport(exportInformation, surface); ProcessExport(exportInformation, surface);
return exportInformation; return exportInformation;
} }

View file

@ -29,18 +29,21 @@ using GreenshotPlugin.IniFile;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin; using GreenshotPlugin.Interfaces.Plugin;
namespace Greenshot.Plugin.GooglePhotos { namespace Greenshot.Plugin.GooglePhotos
{
/// <summary> /// <summary>
/// This is the GooglePhotos base code /// This is the GooglePhotos base code
/// </summary> /// </summary>
[Plugin("GooglePhotos", true)] [Plugin("GooglePhotos", true)]
public class GooglePhotosPlugin : IGreenshotPlugin { public class GooglePhotosPlugin : IGreenshotPlugin
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(GooglePhotosPlugin)); private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(GooglePhotosPlugin));
private static GooglePhotosConfiguration _config; private static GooglePhotosConfiguration _config;
private ComponentResourceManager _resources; private ComponentResourceManager _resources;
private ToolStripMenuItem _itemPlugInRoot; private ToolStripMenuItem _itemPlugInRoot;
public void Dispose() { public void Dispose()
{
Dispose(true); Dispose(true);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
@ -56,7 +59,8 @@ namespace Greenshot.Plugin.GooglePhotos {
/// <summary> /// <summary>
/// Implementation of the IGreenshotPlugin.Initialize /// Implementation of the IGreenshotPlugin.Initialize
/// </summary> /// </summary>
public bool Initialize() { public bool Initialize()
{
SimpleServiceProvider.Current.AddService<IDestination>(new GooglePhotosDestination(this)); SimpleServiceProvider.Current.AddService<IDestination>(new GooglePhotosDestination(this));
// Get configuration // Get configuration
@ -74,13 +78,16 @@ namespace Greenshot.Plugin.GooglePhotos {
return true; return true;
} }
public void OnLanguageChanged(object sender, EventArgs e) { public void OnLanguageChanged(object sender, EventArgs e)
if (_itemPlugInRoot != null) { {
if (_itemPlugInRoot != null)
{
_itemPlugInRoot.Text = Language.GetString("googlephotos", LangKey.Configure); _itemPlugInRoot.Text = Language.GetString("googlephotos", LangKey.Configure);
} }
} }
public void Shutdown() { public void Shutdown()
{
Log.Debug("GooglePhotos Plugin shutdown."); Log.Debug("GooglePhotos Plugin shutdown.");
Language.LanguageChanged -= OnLanguageChanged; Language.LanguageChanged -= OnLanguageChanged;
//host.OnImageEditorOpen -= new OnImageEditorOpenHandler(ImageEditorOpened); //host.OnImageEditorOpen -= new OnImageEditorOpenHandler(ImageEditorOpened);
@ -89,17 +96,21 @@ namespace Greenshot.Plugin.GooglePhotos {
/// <summary> /// <summary>
/// Implementation of the IPlugin.Configure /// Implementation of the IPlugin.Configure
/// </summary> /// </summary>
public void Configure() { public void Configure()
{
_config.ShowConfigDialog(); _config.ShowConfigDialog();
} }
public void ConfigMenuClick(object sender, EventArgs eventArgs) { public void ConfigMenuClick(object sender, EventArgs eventArgs)
{
Configure(); Configure();
} }
public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) { public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl)
{
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality); SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality);
try { try
{
string url = null; string url = null;
new PleaseWaitForm().ShowAndWait("GooglePhotos", Language.GetString("googlephotos", LangKey.communication_wait), new PleaseWaitForm().ShowAndWait("GooglePhotos", Language.GetString("googlephotos", LangKey.communication_wait),
delegate delegate
@ -110,14 +121,19 @@ namespace Greenshot.Plugin.GooglePhotos {
); );
uploadUrl = url; uploadUrl = url;
if (uploadUrl != null && _config.AfterUploadLinkToClipBoard) { if (uploadUrl != null && _config.AfterUploadLinkToClipBoard)
{
ClipboardHelper.SetClipboardData(uploadUrl); ClipboardHelper.SetClipboardData(uploadUrl);
} }
return true; return true;
} catch (Exception e) { }
catch (Exception e)
{
Log.Error("Error uploading.", e); Log.Error("Error uploading.", e);
MessageBox.Show(Language.GetString("googlephotos", LangKey.upload_failure) + " " + e.Message); MessageBox.Show(Language.GetString("googlephotos", LangKey.upload_failure) + " " + e.Message);
} }
uploadUrl = null; uploadUrl = null;
return false; return false;
} }

View file

@ -26,15 +26,20 @@ using GreenshotPlugin.IniFile;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin; using GreenshotPlugin.Interfaces.Plugin;
namespace Greenshot.Plugin.GooglePhotos { namespace Greenshot.Plugin.GooglePhotos
{
/// <summary> /// <summary>
/// Description of GooglePhotosUtils. /// Description of GooglePhotosUtils.
/// </summary> /// </summary>
public static class GooglePhotosUtils { public static class GooglePhotosUtils
{
private const string GooglePhotosScope = "https://picasaweb.google.com/data/"; private const string GooglePhotosScope = "https://picasaweb.google.com/data/";
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(GooglePhotosUtils)); private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(GooglePhotosUtils));
private static readonly GooglePhotosConfiguration Config = IniConfig.GetIniSection<GooglePhotosConfiguration>(); private static readonly GooglePhotosConfiguration Config = IniConfig.GetIniSection<GooglePhotosConfiguration>();
private const string AuthUrl = "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={ClientId}&redirect_uri={RedirectUrl}&state={State}&scope=" + GooglePhotosScope;
private const string AuthUrl = "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={ClientId}&redirect_uri={RedirectUrl}&state={State}&scope=" +
GooglePhotosScope;
private const string TokenUrl = "https://www.googleapis.com/oauth2/v3/token"; private const string TokenUrl = "https://www.googleapis.com/oauth2/v3/token";
private const string UploadUrl = "https://picasaweb.google.com/data/feed/api/user/{0}/albumid/{1}"; private const string UploadUrl = "https://picasaweb.google.com/data/feed/api/user/{0}/albumid/{1}";
@ -46,7 +51,8 @@ namespace Greenshot.Plugin.GooglePhotos {
/// <param name="title">string</param> /// <param name="title">string</param>
/// <param name="filename">string</param> /// <param name="filename">string</param>
/// <returns>GooglePhotosResponse</returns> /// <returns>GooglePhotosResponse</returns>
public static string UploadToGooglePhotos(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename) { public static string UploadToGooglePhotos(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename)
{
// Fill the OAuth2Settings // Fill the OAuth2Settings
var settings = new OAuth2Settings var settings = new OAuth2Settings
{ {
@ -63,18 +69,23 @@ namespace Greenshot.Plugin.GooglePhotos {
// Copy the settings from the config, which is kept in memory and on the disk // Copy the settings from the config, which is kept in memory and on the disk
try { try
{
var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, string.Format(UploadUrl, Config.UploadUser, Config.UploadAlbum), settings); var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, string.Format(UploadUrl, Config.UploadUser, Config.UploadAlbum), settings);
if (Config.AddFilename) { if (Config.AddFilename)
{
webRequest.Headers.Add("Slug", NetworkHelper.EscapeDataString(filename)); webRequest.Headers.Add("Slug", NetworkHelper.EscapeDataString(filename));
} }
SurfaceContainer container = new SurfaceContainer(surfaceToUpload, outputSettings, filename); SurfaceContainer container = new SurfaceContainer(surfaceToUpload, outputSettings, filename);
container.Upload(webRequest); container.Upload(webRequest);
string response = NetworkHelper.GetResponseAsString(webRequest); string response = NetworkHelper.GetResponseAsString(webRequest);
return ParseResponse(response); return ParseResponse(response);
} finally { }
finally
{
// Copy the settings back to the config, so they are stored. // Copy the settings back to the config, so they are stored.
Config.RefreshToken = settings.RefreshToken; Config.RefreshToken = settings.RefreshToken;
Config.AccessToken = settings.AccessToken; Config.AccessToken = settings.AccessToken;
@ -89,31 +100,43 @@ namespace Greenshot.Plugin.GooglePhotos {
/// </summary> /// </summary>
/// <param name="response"></param> /// <param name="response"></param>
/// <returns></returns> /// <returns></returns>
public static string ParseResponse(string response) { public static string ParseResponse(string response)
if (response == null) { {
if (response == null)
{
return null; return null;
} }
try {
try
{
XmlDocument doc = new XmlDocument(); XmlDocument doc = new XmlDocument();
doc.LoadXml(response); doc.LoadXml(response);
XmlNodeList nodes = doc.GetElementsByTagName("link", "*"); XmlNodeList nodes = doc.GetElementsByTagName("link", "*");
if(nodes.Count > 0) { if (nodes.Count > 0)
{
string url = null; string url = null;
foreach(XmlNode node in nodes) { foreach (XmlNode node in nodes)
if (node.Attributes != null) { {
if (node.Attributes != null)
{
url = node.Attributes["href"].Value; url = node.Attributes["href"].Value;
string rel = node.Attributes["rel"].Value; string rel = node.Attributes["rel"].Value;
// Pictures with rel="http://schemas.google.com/photos/2007#canonical" are the direct link // Pictures with rel="http://schemas.google.com/photos/2007#canonical" are the direct link
if (rel != null && rel.EndsWith("canonical")) { if (rel != null && rel.EndsWith("canonical"))
{
break; break;
} }
} }
} }
return url; return url;
} }
} catch(Exception e) { }
catch (Exception e)
{
Log.ErrorFormat("Could not parse GooglePhotos response due to error {0}, response was: {1}", e.Message, response); Log.ErrorFormat("Could not parse GooglePhotos response due to error {0}, response was: {1}", e.Message, response);
} }
return null; return null;
} }
} }

View file

@ -18,7 +18,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace Greenshot.Plugin.GooglePhotos { namespace Greenshot.Plugin.GooglePhotos
{
public enum LangKey public enum LangKey
{ {
upload_menu_item, upload_menu_item,

View file

@ -21,10 +21,12 @@
using GreenshotPlugin.Controls; using GreenshotPlugin.Controls;
namespace Greenshot.Plugin.Imgur.Forms { namespace Greenshot.Plugin.Imgur.Forms
{
/// <summary> /// <summary>
/// This class is needed for design-time resolving of the language files /// This class is needed for design-time resolving of the language files
/// </summary> /// </summary>
public class ImgurForm : GreenshotForm { public class ImgurForm : GreenshotForm
{
} }
} }

View file

@ -27,18 +27,21 @@ using GreenshotPlugin.Controls;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.Imgur.Forms { namespace Greenshot.Plugin.Imgur.Forms
{
/// <summary> /// <summary>
/// Imgur history form /// Imgur history form
/// </summary> /// </summary>
public sealed partial class ImgurHistory : ImgurForm { public sealed partial class ImgurHistory : ImgurForm
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurHistory)); private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurHistory));
private readonly GreenshotColumnSorter _columnSorter; private readonly GreenshotColumnSorter _columnSorter;
private static readonly object Lock = new object(); private static readonly object Lock = new object();
private static readonly ImgurConfiguration Config = IniConfig.GetIniSection<ImgurConfiguration>(); private static readonly ImgurConfiguration Config = IniConfig.GetIniSection<ImgurConfiguration>();
private static ImgurHistory _instance; private static ImgurHistory _instance;
public static void ShowHistory() { public static void ShowHistory()
{
lock (Lock) lock (Lock)
{ {
if (ImgurUtils.IsHistoryLoadingNeeded()) if (ImgurUtils.IsHistoryLoadingNeeded())
@ -54,15 +57,18 @@ namespace Greenshot.Plugin.Imgur.Forms {
{ {
_instance = new ImgurHistory(); _instance = new ImgurHistory();
} }
if (!_instance.Visible) if (!_instance.Visible)
{ {
_instance.Show(); _instance.Show();
} }
_instance.Redraw(); _instance.Redraw();
} }
} }
private ImgurHistory() { private ImgurHistory()
{
ManualLanguageApply = true; ManualLanguageApply = true;
// //
// The InitializeComponent() call is required for Windows Forms designer support. // The InitializeComponent() call is required for Windows Forms designer support.
@ -76,26 +82,36 @@ namespace Greenshot.Plugin.Imgur.Forms {
_columnSorter.SortColumn = 3; _columnSorter.SortColumn = 3;
_columnSorter.Order = SortOrder.Descending; _columnSorter.Order = SortOrder.Descending;
Redraw(); Redraw();
if (listview_imgur_uploads.Items.Count > 0) { if (listview_imgur_uploads.Items.Count > 0)
{
listview_imgur_uploads.Items[0].Selected = true; listview_imgur_uploads.Items[0].Selected = true;
} }
ApplyLanguage(); ApplyLanguage();
if (Config.Credits > 0) { if (Config.Credits > 0)
{
Text = Text + " (" + Config.Credits + " credits)"; Text = Text + " (" + Config.Credits + " credits)";
} }
} }
private void Redraw() { private void Redraw()
{
// Should fix Bug #3378699 // Should fix Bug #3378699
pictureBox1.Image = pictureBox1.ErrorImage; pictureBox1.Image = pictureBox1.ErrorImage;
listview_imgur_uploads.BeginUpdate(); listview_imgur_uploads.BeginUpdate();
listview_imgur_uploads.Items.Clear(); listview_imgur_uploads.Items.Clear();
listview_imgur_uploads.Columns.Clear(); listview_imgur_uploads.Columns.Clear();
string[] columns = { "hash", "title", "deleteHash", "Date"}; string[] columns =
foreach (string column in columns) { {
"hash", "title", "deleteHash", "Date"
};
foreach (string column in columns)
{
listview_imgur_uploads.Columns.Add(column); listview_imgur_uploads.Columns.Add(column);
} }
foreach (ImgurInfo imgurInfo in Config.runtimeImgurHistory.Values) {
foreach (ImgurInfo imgurInfo in Config.runtimeImgurHistory.Values)
{
var item = new ListViewItem(imgurInfo.Hash) var item = new ListViewItem(imgurInfo.Hash)
{ {
Tag = imgurInfo Tag = imgurInfo
@ -105,7 +121,9 @@ namespace Greenshot.Plugin.Imgur.Forms {
item.SubItems.Add(imgurInfo.Timestamp.ToString("yyyy-MM-dd HH:mm:ss", DateTimeFormatInfo.InvariantInfo)); item.SubItems.Add(imgurInfo.Timestamp.ToString("yyyy-MM-dd HH:mm:ss", DateTimeFormatInfo.InvariantInfo));
listview_imgur_uploads.Items.Add(item); listview_imgur_uploads.Items.Add(item);
} }
for (int i = 0; i < columns.Length; i++) {
for (int i = 0; i < columns.Length; i++)
{
listview_imgur_uploads.AutoResizeColumn(i, ColumnHeaderAutoResizeStyle.ColumnContent); listview_imgur_uploads.AutoResizeColumn(i, ColumnHeaderAutoResizeStyle.ColumnContent);
} }
@ -116,17 +134,22 @@ namespace Greenshot.Plugin.Imgur.Forms {
clipboardButton.Enabled = false; clipboardButton.Enabled = false;
} }
private void Listview_imgur_uploadsSelectedIndexChanged(object sender, EventArgs e) { private void Listview_imgur_uploadsSelectedIndexChanged(object sender, EventArgs e)
{
pictureBox1.Image = pictureBox1.ErrorImage; pictureBox1.Image = pictureBox1.ErrorImage;
if (listview_imgur_uploads.SelectedItems.Count > 0) { if (listview_imgur_uploads.SelectedItems.Count > 0)
{
deleteButton.Enabled = true; deleteButton.Enabled = true;
openButton.Enabled = true; openButton.Enabled = true;
clipboardButton.Enabled = true; clipboardButton.Enabled = true;
if (listview_imgur_uploads.SelectedItems.Count == 1) { if (listview_imgur_uploads.SelectedItems.Count == 1)
{
ImgurInfo imgurInfo = (ImgurInfo) listview_imgur_uploads.SelectedItems[0].Tag; ImgurInfo imgurInfo = (ImgurInfo) listview_imgur_uploads.SelectedItems[0].Tag;
pictureBox1.Image = imgurInfo.Image; pictureBox1.Image = imgurInfo.Image;
} }
} else { }
else
{
pictureBox1.Image = pictureBox1.ErrorImage; pictureBox1.Image = pictureBox1.ErrorImage;
deleteButton.Enabled = false; deleteButton.Enabled = false;
openButton.Enabled = false; openButton.Enabled = false;
@ -134,48 +157,60 @@ namespace Greenshot.Plugin.Imgur.Forms {
} }
} }
private void DeleteButtonClick(object sender, EventArgs e) { private void DeleteButtonClick(object sender, EventArgs e)
if (listview_imgur_uploads.SelectedItems.Count > 0) { {
for (int i = 0; i < listview_imgur_uploads.SelectedItems.Count; i++) { if (listview_imgur_uploads.SelectedItems.Count > 0)
{
for (int i = 0; i < listview_imgur_uploads.SelectedItems.Count; i++)
{
ImgurInfo imgurInfo = (ImgurInfo) listview_imgur_uploads.SelectedItems[i].Tag; ImgurInfo imgurInfo = (ImgurInfo) listview_imgur_uploads.SelectedItems[i].Tag;
DialogResult result = MessageBox.Show(Language.GetFormattedString("imgur", LangKey.delete_question, imgurInfo.Title), Language.GetFormattedString("imgur", LangKey.delete_title, imgurInfo.Hash), MessageBoxButtons.YesNo, MessageBoxIcon.Question); DialogResult result = MessageBox.Show(Language.GetFormattedString("imgur", LangKey.delete_question, imgurInfo.Title),
Language.GetFormattedString("imgur", LangKey.delete_title, imgurInfo.Hash), MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result != DialogResult.Yes) if (result != DialogResult.Yes)
{ {
continue; continue;
} }
// Should fix Bug #3378699 // Should fix Bug #3378699
pictureBox1.Image = pictureBox1.ErrorImage; pictureBox1.Image = pictureBox1.ErrorImage;
try { try
{
new PleaseWaitForm().ShowAndWait("Imgur", Language.GetString("imgur", LangKey.communication_wait), new PleaseWaitForm().ShowAndWait("Imgur", Language.GetString("imgur", LangKey.communication_wait),
delegate { delegate { ImgurUtils.DeleteImgurImage(imgurInfo); }
ImgurUtils.DeleteImgurImage(imgurInfo);
}
); );
} catch (Exception ex) { }
catch (Exception ex)
{
Log.Warn("Problem communicating with Imgur: ", ex); Log.Warn("Problem communicating with Imgur: ", ex);
} }
imgurInfo.Dispose(); imgurInfo.Dispose();
} }
} }
Redraw(); Redraw();
} }
private void ClipboardButtonClick(object sender, EventArgs e) { private void ClipboardButtonClick(object sender, EventArgs e)
{
StringBuilder links = new StringBuilder(); StringBuilder links = new StringBuilder();
if (listview_imgur_uploads.SelectedItems.Count > 0) { if (listview_imgur_uploads.SelectedItems.Count > 0)
{
for (int i = 0; i < listview_imgur_uploads.SelectedItems.Count; i++) for (int i = 0; i < listview_imgur_uploads.SelectedItems.Count; i++)
{ {
ImgurInfo imgurInfo = (ImgurInfo) listview_imgur_uploads.SelectedItems[i].Tag; ImgurInfo imgurInfo = (ImgurInfo) listview_imgur_uploads.SelectedItems[i].Tag;
links.AppendLine(Config.UsePageLink ? imgurInfo.Page : imgurInfo.Original); links.AppendLine(Config.UsePageLink ? imgurInfo.Page : imgurInfo.Original);
} }
} }
ClipboardHelper.SetClipboardData(links.ToString()); ClipboardHelper.SetClipboardData(links.ToString());
} }
private void ClearHistoryButtonClick(object sender, EventArgs e) { private void ClearHistoryButtonClick(object sender, EventArgs e)
{
DialogResult result = MessageBox.Show(Language.GetString("imgur", LangKey.clear_question), "Imgur", MessageBoxButtons.YesNo, MessageBoxIcon.Question); DialogResult result = MessageBox.Show(Language.GetString("imgur", LangKey.clear_question), "Imgur", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.Yes) { if (result == DialogResult.Yes)
{
Config.runtimeImgurHistory.Clear(); Config.runtimeImgurHistory.Clear();
Config.ImgurUploadHistory.Clear(); Config.ImgurUploadHistory.Clear();
IniConfig.Save(); IniConfig.Save();
@ -188,21 +223,28 @@ namespace Greenshot.Plugin.Imgur.Forms {
Hide(); Hide();
} }
private void OpenButtonClick(object sender, EventArgs e) { private void OpenButtonClick(object sender, EventArgs e)
if (listview_imgur_uploads.SelectedItems.Count > 0) { {
for (int i = 0; i < listview_imgur_uploads.SelectedItems.Count; i++) { if (listview_imgur_uploads.SelectedItems.Count > 0)
{
for (int i = 0; i < listview_imgur_uploads.SelectedItems.Count; i++)
{
ImgurInfo imgurInfo = (ImgurInfo) listview_imgur_uploads.SelectedItems[i].Tag; ImgurInfo imgurInfo = (ImgurInfo) listview_imgur_uploads.SelectedItems[i].Tag;
System.Diagnostics.Process.Start(imgurInfo.Page); System.Diagnostics.Process.Start(imgurInfo.Page);
} }
} }
} }
private void listview_imgur_uploads_ColumnClick(object sender, ColumnClickEventArgs e) { private void listview_imgur_uploads_ColumnClick(object sender, ColumnClickEventArgs e)
{
// Determine if clicked column is already the column that is being sorted. // Determine if clicked column is already the column that is being sorted.
if (e.Column == _columnSorter.SortColumn) { if (e.Column == _columnSorter.SortColumn)
{
// Reverse the current sort direction for this column. // Reverse the current sort direction for this column.
_columnSorter.Order = _columnSorter.Order == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending; _columnSorter.Order = _columnSorter.Order == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending;
} else { }
else
{
// Set the column number that is to be sorted; default to ascending. // Set the column number that is to be sorted; default to ascending.
_columnSorter.SortColumn = e.Column; _columnSorter.SortColumn = e.Column;
_columnSorter.Order = SortOrder.Ascending; _columnSorter.Order = SortOrder.Ascending;

View file

@ -21,11 +21,13 @@
using System; using System;
namespace Greenshot.Plugin.Imgur.Forms { namespace Greenshot.Plugin.Imgur.Forms
{
/// <summary> /// <summary>
/// Description of PasswordRequestForm. /// Description of PasswordRequestForm.
/// </summary> /// </summary>
public partial class SettingsForm : ImgurForm { public partial class SettingsForm : ImgurForm
{
public SettingsForm() public SettingsForm()
{ {
// //
@ -38,7 +40,8 @@ namespace Greenshot.Plugin.Imgur.Forms {
historyButton.Enabled = ImgurUtils.IsHistoryLoadingNeeded(); historyButton.Enabled = ImgurUtils.IsHistoryLoadingNeeded();
} }
private void ButtonHistoryClick(object sender, EventArgs e) { private void ButtonHistoryClick(object sender, EventArgs e)
{
ImgurHistory.ShowHistory(); ImgurHistory.ShowHistory();
} }
} }

View file

@ -26,25 +26,32 @@ using Greenshot.Plugin.Imgur.Forms;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.Imgur { namespace Greenshot.Plugin.Imgur
{
/// <summary> /// <summary>
/// Description of ImgurConfiguration. /// Description of ImgurConfiguration.
/// </summary> /// </summary>
[IniSection("Imgur", Description = "Greenshot Imgur Plugin configuration")] [IniSection("Imgur", Description = "Greenshot Imgur Plugin configuration")]
public class ImgurConfiguration : IniSection { public class ImgurConfiguration : IniSection
{
[IniProperty("ImgurApi3Url", Description = "Url to Imgur system.", DefaultValue = "https://api.imgur.com/3")] [IniProperty("ImgurApi3Url", Description = "Url to Imgur system.", DefaultValue = "https://api.imgur.com/3")]
public string ImgurApi3Url { get; set; } public string ImgurApi3Url { get; set; }
[IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")]
public OutputFormat UploadFormat { get; set; } public OutputFormat UploadFormat { get; set; }
[IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")]
public int UploadJpegQuality { get; set; } public int UploadJpegQuality { get; set; }
[IniProperty("UploadReduceColors", Description = "Reduce color amount of the uploaded image to 256", DefaultValue = "False")] [IniProperty("UploadReduceColors", Description = "Reduce color amount of the uploaded image to 256", DefaultValue = "False")]
public bool UploadReduceColors { get; set; } public bool UploadReduceColors { get; set; }
[IniProperty("CopyLinkToClipboard", Description = "Copy the link, which one is controlled by the UsePageLink, on the clipboard", DefaultValue = "True")] [IniProperty("CopyLinkToClipboard", Description = "Copy the link, which one is controlled by the UsePageLink, on the clipboard", DefaultValue = "True")]
public bool CopyLinkToClipboard { get; set; } public bool CopyLinkToClipboard { get; set; }
[IniProperty("UsePageLink", Description = "Use pagelink instead of direct link on the clipboard", DefaultValue = "False")] [IniProperty("UsePageLink", Description = "Use pagelink instead of direct link on the clipboard", DefaultValue = "False")]
public bool UsePageLink { get; set; } public bool UsePageLink { get; set; }
[IniProperty("AnonymousAccess", Description = "Use anonymous access to Imgur", DefaultValue = "true")] [IniProperty("AnonymousAccess", Description = "Use anonymous access to Imgur", DefaultValue = "true")]
public bool AnonymousAccess { get; set; } public bool AnonymousAccess { get; set; }
@ -63,8 +70,10 @@ namespace Greenshot.Plugin.Imgur {
[IniProperty("AddTitle", Description = "Is the title passed on to Imgur", DefaultValue = "False")] [IniProperty("AddTitle", Description = "Is the title passed on to Imgur", DefaultValue = "False")]
public bool AddTitle { get; set; } public bool AddTitle { get; set; }
[IniProperty("AddFilename", Description = "Is the filename passed on to Imgur", DefaultValue = "False")] [IniProperty("AddFilename", Description = "Is the filename passed on to Imgur", DefaultValue = "False")]
public bool AddFilename { get; set; } public bool AddFilename { get; set; }
[IniProperty("FilenamePattern", Description = "Filename for the Imgur upload", DefaultValue = "${capturetime:d\"yyyyMMdd-HHmm\"}")] [IniProperty("FilenamePattern", Description = "Filename for the Imgur upload", DefaultValue = "${capturetime:d\"yyyyMMdd-HHmm\"}")]
public string FilenamePattern { get; set; } public string FilenamePattern { get; set; }
@ -73,10 +82,7 @@ namespace Greenshot.Plugin.Imgur {
// Not stored, only run-time! // Not stored, only run-time!
public Dictionary<string, ImgurInfo> runtimeImgurHistory = new Dictionary<string, ImgurInfo>(); public Dictionary<string, ImgurInfo> runtimeImgurHistory = new Dictionary<string, ImgurInfo>();
public int Credits { public int Credits { get; set; }
get;
set;
}
/// <summary> /// <summary>
/// Supply values we can't put as defaults /// Supply values we can't put as defaults
@ -94,7 +100,8 @@ namespace Greenshot.Plugin.Imgur {
/// A form for username/password /// A form for username/password
/// </summary> /// </summary>
/// <returns>bool true if OK was pressed, false if cancel</returns> /// <returns>bool true if OK was pressed, false if cancel</returns>
public bool ShowConfigDialog() { public bool ShowConfigDialog()
{
SettingsForm settingsForm = new SettingsForm(); SettingsForm settingsForm = new SettingsForm();
DialogResult result = settingsForm.ShowDialog(); DialogResult result = settingsForm.ShowDialog();
return result == DialogResult.OK; return result == DialogResult.OK;

View file

@ -24,14 +24,17 @@ using System.Drawing;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
namespace Greenshot.Plugin.Imgur { namespace Greenshot.Plugin.Imgur
{
/// <summary> /// <summary>
/// Description of ImgurDestination. /// Description of ImgurDestination.
/// </summary> /// </summary>
public class ImgurDestination : AbstractDestination { public class ImgurDestination : AbstractDestination
{
private readonly ImgurPlugin _plugin; private readonly ImgurPlugin _plugin;
public ImgurDestination(ImgurPlugin plugin) { public ImgurDestination(ImgurPlugin plugin)
{
_plugin = plugin; _plugin = plugin;
} }
@ -39,17 +42,21 @@ namespace Greenshot.Plugin.Imgur {
public override string Description => Language.GetString("imgur", LangKey.upload_menu_item); public override string Description => Language.GetString("imgur", LangKey.upload_menu_item);
public override Image DisplayIcon { public override Image DisplayIcon
get { {
get
{
ComponentResourceManager resources = new ComponentResourceManager(typeof(ImgurPlugin)); ComponentResourceManager resources = new ComponentResourceManager(typeof(ImgurPlugin));
return (Image) resources.GetObject("Imgur"); return (Image) resources.GetObject("Imgur");
} }
} }
public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails)
{
ExportInformation exportInformation = new ExportInformation(Designation, Description) ExportInformation exportInformation = new ExportInformation(Designation, Description)
{ {
ExportMade = _plugin.Upload(captureDetails, surface, out var uploadUrl), Uri = uploadUrl ExportMade = _plugin.Upload(captureDetails, surface, out var uploadUrl),
Uri = uploadUrl
}; };
ProcessExport(exportInformation, surface); ProcessExport(exportInformation, surface);
return exportInformation; return exportInformation;

View file

@ -32,13 +32,10 @@ namespace Greenshot.Plugin.Imgur
{ {
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurInfo)); private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurInfo));
public string Hash public string Hash { get; set; }
{
get;
set;
}
private string _deleteHash; private string _deleteHash;
public string DeleteHash public string DeleteHash
{ {
get { return _deleteHash; } get { return _deleteHash; }
@ -49,55 +46,24 @@ namespace Greenshot.Plugin.Imgur
} }
} }
public string Title public string Title { get; set; }
{
get;
set;
}
public string ImageType public string ImageType { get; set; }
{
get;
set;
}
public DateTime Timestamp public DateTime Timestamp { get; set; }
{
get;
set;
}
public string Original public string Original { get; set; }
{
get;
set;
}
public string Page public string Page { get; set; }
{
get;
set;
}
public string SmallSquare public string SmallSquare { get; set; }
{
get;
set;
}
public string LargeThumbnail public string LargeThumbnail { get; set; }
{
get;
set;
}
public string DeletePage public string DeletePage { get; set; }
{
get;
set;
}
private Image _image; private Image _image;
public Image Image public Image Image
{ {
get { return _image; } get { return _image; }
@ -129,8 +95,10 @@ namespace Greenshot.Plugin.Imgur
{ {
_image?.Dispose(); _image?.Dispose();
} }
_image = null; _image = null;
} }
public static ImgurInfo ParseResponse(string response) public static ImgurInfo ParseResponse(string response)
{ {
Log.Debug(response); Log.Debug(response);
@ -154,26 +122,31 @@ namespace Greenshot.Plugin.Imgur
{ {
imgurInfo.Hash = nodes.Item(0)?.InnerText; imgurInfo.Hash = nodes.Item(0)?.InnerText;
} }
nodes = doc.GetElementsByTagName("hash"); nodes = doc.GetElementsByTagName("hash");
if (nodes.Count > 0) if (nodes.Count > 0)
{ {
imgurInfo.Hash = nodes.Item(0)?.InnerText; imgurInfo.Hash = nodes.Item(0)?.InnerText;
} }
nodes = doc.GetElementsByTagName("deletehash"); nodes = doc.GetElementsByTagName("deletehash");
if (nodes.Count > 0) if (nodes.Count > 0)
{ {
imgurInfo.DeleteHash = nodes.Item(0)?.InnerText; imgurInfo.DeleteHash = nodes.Item(0)?.InnerText;
} }
nodes = doc.GetElementsByTagName("type"); nodes = doc.GetElementsByTagName("type");
if (nodes.Count > 0) if (nodes.Count > 0)
{ {
imgurInfo.ImageType = nodes.Item(0)?.InnerText; imgurInfo.ImageType = nodes.Item(0)?.InnerText;
} }
nodes = doc.GetElementsByTagName("title"); nodes = doc.GetElementsByTagName("title");
if (nodes.Count > 0) if (nodes.Count > 0)
{ {
imgurInfo.Title = nodes.Item(0)?.InnerText; imgurInfo.Title = nodes.Item(0)?.InnerText;
} }
nodes = doc.GetElementsByTagName("datetime"); nodes = doc.GetElementsByTagName("datetime");
if (nodes.Count > 0) if (nodes.Count > 0)
{ {
@ -184,17 +157,20 @@ namespace Greenshot.Plugin.Imgur
imgurInfo.Timestamp = epoch.AddSeconds(secondsSince).DateTime; imgurInfo.Timestamp = epoch.AddSeconds(secondsSince).DateTime;
} }
} }
nodes = doc.GetElementsByTagName("original"); nodes = doc.GetElementsByTagName("original");
if (nodes.Count > 0) if (nodes.Count > 0)
{ {
imgurInfo.Original = nodes.Item(0)?.InnerText.Replace("http:", "https:"); imgurInfo.Original = nodes.Item(0)?.InnerText.Replace("http:", "https:");
} }
// Version 3 API only has Link // Version 3 API only has Link
nodes = doc.GetElementsByTagName("link"); nodes = doc.GetElementsByTagName("link");
if (nodes.Count > 0) if (nodes.Count > 0)
{ {
imgurInfo.Original = nodes.Item(0)?.InnerText.Replace("http:", "https:"); imgurInfo.Original = nodes.Item(0)?.InnerText.Replace("http:", "https:");
} }
nodes = doc.GetElementsByTagName("imgur_page"); nodes = doc.GetElementsByTagName("imgur_page");
if (nodes.Count > 0) if (nodes.Count > 0)
{ {
@ -205,6 +181,7 @@ namespace Greenshot.Plugin.Imgur
// Version 3 doesn't have a page link in the response // Version 3 doesn't have a page link in the response
imgurInfo.Page = $"https://imgur.com/{imgurInfo.Hash}"; imgurInfo.Page = $"https://imgur.com/{imgurInfo.Hash}";
} }
nodes = doc.GetElementsByTagName("small_square"); nodes = doc.GetElementsByTagName("small_square");
imgurInfo.SmallSquare = nodes.Count > 0 ? nodes.Item(0)?.InnerText : $"http://i.imgur.com/{imgurInfo.Hash}s.png"; imgurInfo.SmallSquare = nodes.Count > 0 ? nodes.Item(0)?.InnerText : $"http://i.imgur.com/{imgurInfo.Hash}s.png";
} }
@ -212,6 +189,7 @@ namespace Greenshot.Plugin.Imgur
{ {
Log.ErrorFormat("Could not parse Imgur response due to error {0}, response was: {1}", e.Message, response); Log.ErrorFormat("Could not parse Imgur response due to error {0}, response was: {1}", e.Message, response);
} }
return imgurInfo; return imgurInfo;
} }
} }

View file

@ -32,37 +32,46 @@ using GreenshotPlugin.IniFile;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin; using GreenshotPlugin.Interfaces.Plugin;
namespace Greenshot.Plugin.Imgur { namespace Greenshot.Plugin.Imgur
{
/// <summary> /// <summary>
/// This is the ImgurPlugin code /// This is the ImgurPlugin code
/// </summary> /// </summary>
[Plugin("Imgur", true)] [Plugin("Imgur", true)]
public class ImgurPlugin : IGreenshotPlugin { public class ImgurPlugin : IGreenshotPlugin
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurPlugin)); private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurPlugin));
private static ImgurConfiguration _config; private static ImgurConfiguration _config;
private ComponentResourceManager _resources; private ComponentResourceManager _resources;
private ToolStripMenuItem _historyMenuItem; private ToolStripMenuItem _historyMenuItem;
private ToolStripMenuItem _itemPlugInConfig; private ToolStripMenuItem _itemPlugInConfig;
public void Dispose() { public void Dispose()
{
Dispose(true); Dispose(true);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
protected virtual void Dispose(bool disposing) { protected virtual void Dispose(bool disposing)
if (disposing) { {
if (_historyMenuItem != null) { if (disposing)
{
if (_historyMenuItem != null)
{
_historyMenuItem.Dispose(); _historyMenuItem.Dispose();
_historyMenuItem = null; _historyMenuItem = null;
} }
if (_itemPlugInConfig != null) {
if (_itemPlugInConfig != null)
{
_itemPlugInConfig.Dispose(); _itemPlugInConfig.Dispose();
_itemPlugInConfig = null; _itemPlugInConfig = null;
} }
} }
} }
private IEnumerable<IDestination> Destinations() { private IEnumerable<IDestination> Destinations()
{
yield return new ImgurDestination(this); yield return new ImgurDestination(this);
} }
@ -70,7 +79,8 @@ namespace Greenshot.Plugin.Imgur {
/// Implementation of the IGreenshotPlugin.Initialize /// Implementation of the IGreenshotPlugin.Initialize
/// </summary> /// </summary>
/// <returns>true if plugin is initialized, false if not (doesn't show)</returns> /// <returns>true if plugin is initialized, false if not (doesn't show)</returns>
public bool Initialize() { public bool Initialize()
{
// Get configuration // Get configuration
_config = IniConfig.GetIniSection<ImgurConfiguration>(); _config = IniConfig.GetIniSection<ImgurConfiguration>();
_resources = new ComponentResourceManager(typeof(ImgurPlugin)); _resources = new ComponentResourceManager(typeof(ImgurPlugin));
@ -83,15 +93,11 @@ namespace Greenshot.Plugin.Imgur {
// Provide the IDestination // Provide the IDestination
SimpleServiceProvider.Current.AddService(Destinations()); SimpleServiceProvider.Current.AddService(Destinations());
_historyMenuItem = new ToolStripMenuItem(Language.GetString("imgur", LangKey.history)); _historyMenuItem = new ToolStripMenuItem(Language.GetString("imgur", LangKey.history));
_historyMenuItem.Click += delegate { _historyMenuItem.Click += delegate { ImgurHistory.ShowHistory(); };
ImgurHistory.ShowHistory();
};
itemPlugInRoot.DropDownItems.Add(_historyMenuItem); itemPlugInRoot.DropDownItems.Add(_historyMenuItem);
_itemPlugInConfig = new ToolStripMenuItem(Language.GetString("imgur", LangKey.configure)); _itemPlugInConfig = new ToolStripMenuItem(Language.GetString("imgur", LangKey.configure));
_itemPlugInConfig.Click += delegate { _itemPlugInConfig.Click += delegate { _config.ShowConfigDialog(); };
_config.ShowConfigDialog();
};
itemPlugInRoot.DropDownItems.Add(_itemPlugInConfig); itemPlugInRoot.DropDownItems.Add(_itemPlugInConfig);
PluginUtils.AddToContextMenu(itemPlugInRoot); PluginUtils.AddToContextMenu(itemPlugInRoot);
@ -102,20 +108,26 @@ namespace Greenshot.Plugin.Imgur {
return true; return true;
} }
public void OnLanguageChanged(object sender, EventArgs e) { public void OnLanguageChanged(object sender, EventArgs e)
if (_itemPlugInConfig != null) { {
if (_itemPlugInConfig != null)
{
_itemPlugInConfig.Text = Language.GetString("imgur", LangKey.configure); _itemPlugInConfig.Text = Language.GetString("imgur", LangKey.configure);
} }
if (_historyMenuItem != null) {
if (_historyMenuItem != null)
{
_historyMenuItem.Text = Language.GetString("imgur", LangKey.history); _historyMenuItem.Text = Language.GetString("imgur", LangKey.history);
} }
} }
private void UpdateHistoryMenuItem() { private void UpdateHistoryMenuItem()
{
if (_historyMenuItem == null) if (_historyMenuItem == null)
{ {
return; return;
} }
try try
{ {
var form = SimpleServiceProvider.Current.GetInstance<Form>(); var form = SimpleServiceProvider.Current.GetInstance<Form>();
@ -126,18 +138,25 @@ namespace Greenshot.Plugin.Imgur {
{ {
return; return;
} }
if (_config?.ImgurUploadHistory != null && _config.ImgurUploadHistory.Count > 0) {
if (_config?.ImgurUploadHistory != null && _config.ImgurUploadHistory.Count > 0)
{
historyMenuItem.Enabled = true; historyMenuItem.Enabled = true;
} else { }
else
{
historyMenuItem.Enabled = false; historyMenuItem.Enabled = false;
} }
}); });
} catch (Exception ex) { }
catch (Exception ex)
{
Log.Error("Error loading history", ex); Log.Error("Error loading history", ex);
} }
} }
public virtual void Shutdown() { public virtual void Shutdown()
{
Log.Debug("Imgur Plugin shutdown."); Log.Debug("Imgur Plugin shutdown.");
Language.LanguageChanged -= OnLanguageChanged; Language.LanguageChanged -= OnLanguageChanged;
} }
@ -145,7 +164,8 @@ namespace Greenshot.Plugin.Imgur {
/// <summary> /// <summary>
/// Implementation of the IPlugin.Configure /// Implementation of the IPlugin.Configure
/// </summary> /// </summary>
public virtual void Configure() { public virtual void Configure()
{
_config.ShowConfigDialog(); _config.ShowConfigDialog();
} }
@ -156,9 +176,11 @@ namespace Greenshot.Plugin.Imgur {
/// <param name="surfaceToUpload">ISurface</param> /// <param name="surfaceToUpload">ISurface</param>
/// <param name="uploadUrl">out string for the url</param> /// <param name="uploadUrl">out string for the url</param>
/// <returns>true if the upload succeeded</returns> /// <returns>true if the upload succeeded</returns>
public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) { public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl)
{
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, _config.UploadReduceColors); SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, _config.UploadReduceColors);
try { try
{
string filename = Path.GetFileName(FilenameHelper.GetFilenameFromPattern(_config.FilenamePattern, _config.UploadFormat, captureDetails)); string filename = Path.GetFileName(FilenameHelper.GetFilenameFromPattern(_config.FilenamePattern, _config.UploadFormat, captureDetails));
ImgurInfo imgurInfo = null; ImgurInfo imgurInfo = null;
@ -167,7 +189,8 @@ namespace Greenshot.Plugin.Imgur {
delegate delegate
{ {
imgurInfo = ImgurUtils.UploadToImgur(surfaceToUpload, outputSettings, captureDetails.Title, filename); imgurInfo = ImgurUtils.UploadToImgur(surfaceToUpload, outputSettings, captureDetails.Title, filename);
if (imgurInfo != null && _config.AnonymousAccess) { if (imgurInfo != null && _config.AnonymousAccess)
{
Log.InfoFormat("Storing imgur upload for hash {0} and delete hash {1}", imgurInfo.Hash, imgurInfo.DeleteHash); Log.InfoFormat("Storing imgur upload for hash {0} and delete hash {1}", imgurInfo.Hash, imgurInfo.DeleteHash);
_config.ImgurUploadHistory.Add(imgurInfo.Hash, imgurInfo.DeleteHash); _config.ImgurUploadHistory.Add(imgurInfo.Hash, imgurInfo.DeleteHash);
_config.runtimeImgurHistory.Add(imgurInfo.Hash, imgurInfo); _config.runtimeImgurHistory.Add(imgurInfo.Hash, imgurInfo);
@ -176,11 +199,14 @@ namespace Greenshot.Plugin.Imgur {
} }
); );
if (imgurInfo != null) { if (imgurInfo != null)
{
// TODO: Optimize a second call for export // TODO: Optimize a second call for export
using (Image tmpImage = surfaceToUpload.GetImageForExport()) { using (Image tmpImage = surfaceToUpload.GetImageForExport())
{
imgurInfo.Image = ImageHelper.CreateThumbnail(tmpImage, 90, 90); imgurInfo.Image = ImageHelper.CreateThumbnail(tmpImage, 90, 90);
} }
IniConfig.Save(); IniConfig.Save();
if (_config.UsePageLink) if (_config.UsePageLink)
@ -191,12 +217,12 @@ namespace Greenshot.Plugin.Imgur {
{ {
uploadUrl = imgurInfo.Original; uploadUrl = imgurInfo.Original;
} }
if (!string.IsNullOrEmpty(uploadUrl) && _config.CopyLinkToClipboard) if (!string.IsNullOrEmpty(uploadUrl) && _config.CopyLinkToClipboard)
{ {
try try
{ {
ClipboardHelper.SetClipboardData(uploadUrl); ClipboardHelper.SetClipboardData(uploadUrl);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -204,12 +230,16 @@ namespace Greenshot.Plugin.Imgur {
uploadUrl = null; uploadUrl = null;
} }
} }
return true; return true;
} }
} catch (Exception e) { }
catch (Exception e)
{
Log.Error("Error uploading.", e); Log.Error("Error uploading.", e);
MessageBox.Show(Language.GetString("imgur", LangKey.upload_failure) + " " + e.Message); MessageBox.Show(Language.GetString("imgur", LangKey.upload_failure) + " " + e.Message);
} }
uploadUrl = null; uploadUrl = null;
return false; return false;
} }

View file

@ -30,11 +30,13 @@ using GreenshotPlugin.IniFile;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin; using GreenshotPlugin.Interfaces.Plugin;
namespace Greenshot.Plugin.Imgur { namespace Greenshot.Plugin.Imgur
{
/// <summary> /// <summary>
/// A collection of Imgur helper methods /// A collection of Imgur helper methods
/// </summary> /// </summary>
public static class ImgurUtils { public static class ImgurUtils
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurUtils)); private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurUtils));
private const string SmallUrlPattern = "http://i.imgur.com/{0}s.jpg"; private const string SmallUrlPattern = "http://i.imgur.com/{0}s.jpg";
private static readonly ImgurConfiguration Config = IniConfig.GetIniSection<ImgurConfiguration>(); private static readonly ImgurConfiguration Config = IniConfig.GetIniSection<ImgurConfiguration>();
@ -45,14 +47,16 @@ namespace Greenshot.Plugin.Imgur {
/// <returns></returns> /// <returns></returns>
public static bool IsHistoryLoadingNeeded() public static bool IsHistoryLoadingNeeded()
{ {
Log.InfoFormat("Checking if imgur cache loading needed, configuration has {0} imgur hashes, loaded are {1} hashes.", Config.ImgurUploadHistory.Count, Config.runtimeImgurHistory.Count); Log.InfoFormat("Checking if imgur cache loading needed, configuration has {0} imgur hashes, loaded are {1} hashes.", Config.ImgurUploadHistory.Count,
Config.runtimeImgurHistory.Count);
return Config.runtimeImgurHistory.Count != Config.ImgurUploadHistory.Count; return Config.runtimeImgurHistory.Count != Config.ImgurUploadHistory.Count;
} }
/// <summary> /// <summary>
/// Load the complete history of the imgur uploads, with the corresponding information /// Load the complete history of the imgur uploads, with the corresponding information
/// </summary> /// </summary>
public static void LoadHistory() { public static void LoadHistory()
{
if (!IsHistoryLoadingNeeded()) if (!IsHistoryLoadingNeeded())
{ {
return; return;
@ -61,8 +65,10 @@ namespace Greenshot.Plugin.Imgur {
bool saveNeeded = false; bool saveNeeded = false;
// Load the ImUr history // Load the ImUr history
foreach (string hash in Config.ImgurUploadHistory.Keys.ToList()) { foreach (string hash in Config.ImgurUploadHistory.Keys.ToList())
if (Config.runtimeImgurHistory.ContainsKey(hash)) { {
if (Config.runtimeImgurHistory.ContainsKey(hash))
{
// Already loaded // Already loaded
continue; continue;
} }
@ -71,18 +77,24 @@ namespace Greenshot.Plugin.Imgur {
{ {
var deleteHash = Config.ImgurUploadHistory[hash]; var deleteHash = Config.ImgurUploadHistory[hash];
ImgurInfo imgurInfo = RetrieveImgurInfo(hash, deleteHash); ImgurInfo imgurInfo = RetrieveImgurInfo(hash, deleteHash);
if (imgurInfo != null) { if (imgurInfo != null)
{
RetrieveImgurThumbnail(imgurInfo); RetrieveImgurThumbnail(imgurInfo);
Config.runtimeImgurHistory[hash] = imgurInfo; Config.runtimeImgurHistory[hash] = imgurInfo;
} else { }
else
{
Log.InfoFormat("Deleting unknown ImgUr {0} from config, delete hash was {1}.", hash, deleteHash); Log.InfoFormat("Deleting unknown ImgUr {0} from config, delete hash was {1}.", hash, deleteHash);
Config.ImgurUploadHistory.Remove(hash); Config.ImgurUploadHistory.Remove(hash);
Config.runtimeImgurHistory.Remove(hash); Config.runtimeImgurHistory.Remove(hash);
saveNeeded = true; saveNeeded = true;
} }
} catch (WebException wE) { }
catch (WebException wE)
{
bool redirected = false; bool redirected = false;
if (wE.Status == WebExceptionStatus.ProtocolError) { if (wE.Status == WebExceptionStatus.ProtocolError)
{
HttpWebResponse response = (HttpWebResponse) wE.Response; HttpWebResponse response = (HttpWebResponse) wE.Response;
if (response.StatusCode == HttpStatusCode.Forbidden) if (response.StatusCode == HttpStatusCode.Forbidden)
@ -90,22 +102,30 @@ namespace Greenshot.Plugin.Imgur {
Log.Error("Imgur loading forbidden", wE); Log.Error("Imgur loading forbidden", wE);
break; break;
} }
// Image no longer available? // Image no longer available?
if (response.StatusCode == HttpStatusCode.Redirect) { if (response.StatusCode == HttpStatusCode.Redirect)
{
Log.InfoFormat("ImgUr image for hash {0} is no longer available, removing it from the history", hash); Log.InfoFormat("ImgUr image for hash {0} is no longer available, removing it from the history", hash);
Config.ImgurUploadHistory.Remove(hash); Config.ImgurUploadHistory.Remove(hash);
Config.runtimeImgurHistory.Remove(hash); Config.runtimeImgurHistory.Remove(hash);
redirected = true; redirected = true;
} }
} }
if (!redirected) {
if (!redirected)
{
Log.Error("Problem loading ImgUr history for hash " + hash, wE); Log.Error("Problem loading ImgUr history for hash " + hash, wE);
} }
} catch (Exception e) { }
catch (Exception e)
{
Log.Error("Problem loading ImgUr history for hash " + hash, e); Log.Error("Problem loading ImgUr history for hash " + hash, e);
} }
} }
if (saveNeeded) {
if (saveNeeded)
{
// Save needed changes // Save needed changes
IniConfig.Save(); IniConfig.Save();
} }
@ -115,7 +135,8 @@ namespace Greenshot.Plugin.Imgur {
/// Use this to make sure Imgur knows from where the upload comes. /// Use this to make sure Imgur knows from where the upload comes.
/// </summary> /// </summary>
/// <param name="webRequest"></param> /// <param name="webRequest"></param>
private static void SetClientId(HttpWebRequest webRequest) { private static void SetClientId(HttpWebRequest webRequest)
{
webRequest.Headers.Add("Authorization", "Client-ID " + ImgurCredentials.CONSUMER_KEY); webRequest.Headers.Add("Authorization", "Client-ID " + ImgurCredentials.CONSUMER_KEY);
} }
@ -128,27 +149,36 @@ namespace Greenshot.Plugin.Imgur {
/// <param name="title">Title</param> /// <param name="title">Title</param>
/// <param name="filename">Filename</param> /// <param name="filename">Filename</param>
/// <returns>ImgurInfo with details</returns> /// <returns>ImgurInfo with details</returns>
public static ImgurInfo UploadToImgur(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename) { public static ImgurInfo UploadToImgur(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename)
{
IDictionary<string, object> otherParameters = new Dictionary<string, object>(); IDictionary<string, object> otherParameters = new Dictionary<string, object>();
// add title // add title
if (title != null && Config.AddTitle) { if (title != null && Config.AddTitle)
{
otherParameters["title"] = title; otherParameters["title"] = title;
} }
// add filename // add filename
if (filename != null && Config.AddFilename) { if (filename != null && Config.AddFilename)
{
otherParameters["name"] = filename; otherParameters["name"] = filename;
} }
string responseString = null; string responseString = null;
if (Config.AnonymousAccess) { if (Config.AnonymousAccess)
{
// add key, we only use the other parameters for the AnonymousAccess // add key, we only use the other parameters for the AnonymousAccess
//otherParameters.Add("key", IMGUR_ANONYMOUS_API_KEY); //otherParameters.Add("key", IMGUR_ANONYMOUS_API_KEY);
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(Config.ImgurApi3Url + "/upload.xml?" + NetworkHelper.GenerateQueryParameters(otherParameters), HTTPMethod.POST); HttpWebRequest webRequest =
NetworkHelper.CreateWebRequest(Config.ImgurApi3Url + "/upload.xml?" + NetworkHelper.GenerateQueryParameters(otherParameters), HTTPMethod.POST);
webRequest.ContentType = "image/" + outputSettings.Format; webRequest.ContentType = "image/" + outputSettings.Format;
webRequest.ServicePoint.Expect100Continue = false; webRequest.ServicePoint.Expect100Continue = false;
SetClientId(webRequest); SetClientId(webRequest);
try { try
using (var requestStream = webRequest.GetRequestStream()) { {
using (var requestStream = webRequest.GetRequestStream())
{
ImageOutput.SaveToStream(surfaceToUpload, requestStream, outputSettings); ImageOutput.SaveToStream(surfaceToUpload, requestStream, outputSettings);
} }
@ -160,12 +190,15 @@ namespace Greenshot.Plugin.Imgur {
using StreamReader reader = new StreamReader(responseStream, true); using StreamReader reader = new StreamReader(responseStream, true);
responseString = reader.ReadToEnd(); responseString = reader.ReadToEnd();
} }
} catch (Exception ex) { }
catch (Exception ex)
{
Log.Error("Upload to imgur gave an exception: ", ex); Log.Error("Upload to imgur gave an exception: ", ex);
throw; throw;
} }
} else { }
else
{
var oauth2Settings = new OAuth2Settings var oauth2Settings = new OAuth2Settings
{ {
AuthUrlPattern = "https://api.imgur.com/oauth2/authorize?response_type=token&client_id={ClientId}&state={State}", AuthUrlPattern = "https://api.imgur.com/oauth2/authorize?response_type=token&client_id={ClientId}&state={State}",
@ -201,10 +234,12 @@ namespace Greenshot.Plugin.Imgur {
IniConfig.Save(); IniConfig.Save();
} }
} }
if (string.IsNullOrEmpty(responseString)) if (string.IsNullOrEmpty(responseString))
{ {
return null; return null;
} }
return ImgurInfo.ParseResponse(responseString); return ImgurInfo.ParseResponse(responseString);
} }
@ -212,11 +247,14 @@ namespace Greenshot.Plugin.Imgur {
/// Retrieve the thumbnail of an imgur image /// Retrieve the thumbnail of an imgur image
/// </summary> /// </summary>
/// <param name="imgurInfo"></param> /// <param name="imgurInfo"></param>
public static void RetrieveImgurThumbnail(ImgurInfo imgurInfo) { public static void RetrieveImgurThumbnail(ImgurInfo imgurInfo)
if (imgurInfo.SmallSquare == null) { {
if (imgurInfo.SmallSquare == null)
{
Log.Warn("Imgur URL was null, not retrieving thumbnail."); Log.Warn("Imgur URL was null, not retrieving thumbnail.");
return; return;
} }
Log.InfoFormat("Retrieving Imgur image for {0} with url {1}", imgurInfo.Hash, imgurInfo.SmallSquare); Log.InfoFormat("Retrieving Imgur image for {0} with url {1}", imgurInfo.Hash, imgurInfo.SmallSquare);
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(string.Format(SmallUrlPattern, imgurInfo.Hash), HTTPMethod.GET); HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(string.Format(SmallUrlPattern, imgurInfo.Hash), HTTPMethod.GET);
webRequest.ServicePoint.Expect100Continue = false; webRequest.ServicePoint.Expect100Continue = false;
@ -237,7 +275,8 @@ namespace Greenshot.Plugin.Imgur {
/// <param name="hash"></param> /// <param name="hash"></param>
/// <param name="deleteHash"></param> /// <param name="deleteHash"></param>
/// <returns>ImgurInfo</returns> /// <returns>ImgurInfo</returns>
public static ImgurInfo RetrieveImgurInfo(string hash, string deleteHash) { public static ImgurInfo RetrieveImgurInfo(string hash, string deleteHash)
{
string url = Config.ImgurApi3Url + "/image/" + hash + ".xml"; string url = Config.ImgurApi3Url + "/image/" + hash + ".xml";
Log.InfoFormat("Retrieving Imgur info for {0} with url {1}", hash, url); Log.InfoFormat("Retrieving Imgur info for {0} with url {1}", hash, url);
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.GET); HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.GET);
@ -254,14 +293,20 @@ namespace Greenshot.Plugin.Imgur {
using StreamReader reader = new StreamReader(responseStream, true); using StreamReader reader = new StreamReader(responseStream, true);
responseString = reader.ReadToEnd(); responseString = reader.ReadToEnd();
} }
} catch (WebException wE) { }
if (wE.Status == WebExceptionStatus.ProtocolError) { catch (WebException wE)
if (((HttpWebResponse)wE.Response).StatusCode == HttpStatusCode.NotFound) { {
if (wE.Status == WebExceptionStatus.ProtocolError)
{
if (((HttpWebResponse) wE.Response).StatusCode == HttpStatusCode.NotFound)
{
return null; return null;
} }
} }
throw; throw;
} }
ImgurInfo imgurInfo = null; ImgurInfo imgurInfo = null;
if (responseString != null) if (responseString != null)
{ {
@ -269,6 +314,7 @@ namespace Greenshot.Plugin.Imgur {
imgurInfo = ImgurInfo.ParseResponse(responseString); imgurInfo = ImgurInfo.ParseResponse(responseString);
imgurInfo.DeleteHash = deleteHash; imgurInfo.DeleteHash = deleteHash;
} }
return imgurInfo; return imgurInfo;
} }
@ -276,16 +322,19 @@ namespace Greenshot.Plugin.Imgur {
/// Delete an imgur image, this is done by specifying the delete hash /// Delete an imgur image, this is done by specifying the delete hash
/// </summary> /// </summary>
/// <param name="imgurInfo"></param> /// <param name="imgurInfo"></param>
public static void DeleteImgurImage(ImgurInfo imgurInfo) { public static void DeleteImgurImage(ImgurInfo imgurInfo)
{
Log.InfoFormat("Deleting Imgur image for {0}", imgurInfo.DeleteHash); Log.InfoFormat("Deleting Imgur image for {0}", imgurInfo.DeleteHash);
try { try
{
string url = Config.ImgurApi3Url + "/image/" + imgurInfo.DeleteHash + ".xml"; string url = Config.ImgurApi3Url + "/image/" + imgurInfo.DeleteHash + ".xml";
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.DELETE); HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.DELETE);
webRequest.ServicePoint.Expect100Continue = false; webRequest.ServicePoint.Expect100Continue = false;
SetClientId(webRequest); SetClientId(webRequest);
string responseString = null; string responseString = null;
using (WebResponse response = webRequest.GetResponse()) { using (WebResponse response = webRequest.GetResponse())
{
LogRateLimitInfo(response); LogRateLimitInfo(response);
var responseStream = response.GetResponseStream(); var responseStream = response.GetResponseStream();
if (responseStream != null) if (responseStream != null)
@ -294,15 +343,21 @@ namespace Greenshot.Plugin.Imgur {
responseString = reader.ReadToEnd(); responseString = reader.ReadToEnd();
} }
} }
Log.InfoFormat("Delete result: {0}", responseString); Log.InfoFormat("Delete result: {0}", responseString);
} catch (WebException wE) { }
catch (WebException wE)
{
// Allow "Bad request" this means we already deleted it // Allow "Bad request" this means we already deleted it
if (wE.Status == WebExceptionStatus.ProtocolError) { if (wE.Status == WebExceptionStatus.ProtocolError)
if (((HttpWebResponse)wE.Response).StatusCode != HttpStatusCode.BadRequest) { {
if (((HttpWebResponse) wE.Response).StatusCode != HttpStatusCode.BadRequest)
{
throw; throw;
} }
} }
} }
// Make sure we remove it from the history, if no error occurred // Make sure we remove it from the history, if no error occurred
Config.runtimeImgurHistory.Remove(imgurInfo.Hash); Config.runtimeImgurHistory.Remove(imgurInfo.Hash);
Config.ImgurUploadHistory.Remove(imgurInfo.Hash); Config.ImgurUploadHistory.Remove(imgurInfo.Hash);
@ -314,8 +369,10 @@ namespace Greenshot.Plugin.Imgur {
/// </summary> /// </summary>
/// <param name="nameValues"></param> /// <param name="nameValues"></param>
/// <param name="key"></param> /// <param name="key"></param>
private static void LogHeader(IDictionary<string, string> nameValues, string key) { private static void LogHeader(IDictionary<string, string> nameValues, string key)
if (nameValues.ContainsKey(key)) { {
if (nameValues.ContainsKey(key))
{
Log.InfoFormat("{0}={1}", key, nameValues[key]); Log.InfoFormat("{0}={1}", key, nameValues[key]);
} }
} }
@ -324,13 +381,17 @@ namespace Greenshot.Plugin.Imgur {
/// Log the current rate-limit information /// Log the current rate-limit information
/// </summary> /// </summary>
/// <param name="response"></param> /// <param name="response"></param>
private static void LogRateLimitInfo(WebResponse response) { private static void LogRateLimitInfo(WebResponse response)
{
IDictionary<string, string> nameValues = new Dictionary<string, string>(); IDictionary<string, string> nameValues = new Dictionary<string, string>();
foreach (string key in response.Headers.AllKeys) { foreach (string key in response.Headers.AllKeys)
if (!nameValues.ContainsKey(key)) { {
if (!nameValues.ContainsKey(key))
{
nameValues.Add(key, response.Headers[key]); nameValues.Add(key, response.Headers[key]);
} }
} }
LogHeader(nameValues, "X-RateLimit-Limit"); LogHeader(nameValues, "X-RateLimit-Limit");
LogHeader(nameValues, "X-RateLimit-Remaining"); LogHeader(nameValues, "X-RateLimit-Remaining");
LogHeader(nameValues, "X-RateLimit-UserLimit"); LogHeader(nameValues, "X-RateLimit-UserLimit");
@ -340,7 +401,8 @@ namespace Greenshot.Plugin.Imgur {
LogHeader(nameValues, "X-RateLimit-ClientRemaining"); LogHeader(nameValues, "X-RateLimit-ClientRemaining");
// Update the credits in the config, this is shown in a form // Update the credits in the config, this is shown in a form
if (nameValues.ContainsKey("X-RateLimit-Remaining") && int.TryParse(nameValues["X-RateLimit-Remaining"], out var credits)) { if (nameValues.ContainsKey("X-RateLimit-Remaining") && int.TryParse(nameValues["X-RateLimit-Remaining"], out var credits))
{
Config.Credits = credits; Config.Credits = credits;
} }
} }

View file

@ -19,8 +19,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace Greenshot.Plugin.Imgur { namespace Greenshot.Plugin.Imgur
public enum LangKey { {
public enum LangKey
{
upload_menu_item, upload_menu_item,
upload_failure, upload_failure,
communication_wait, communication_wait,

View file

@ -114,6 +114,7 @@ namespace Greenshot.Plugin.Jira
{ {
cacheItemPolicy.UpdateCallback = UpdateCallback; cacheItemPolicy.UpdateCallback = UpdateCallback;
} }
if (ActivateRemovedCallback) if (ActivateRemovedCallback)
{ {
cacheItemPolicy.RemovedCallback = RemovedCallback; cacheItemPolicy.RemovedCallback = RemovedCallback;

View file

@ -30,15 +30,18 @@ using GreenshotPlugin.Controls;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.Jira.Forms { namespace Greenshot.Plugin.Jira.Forms
public partial class JiraForm : Form { {
public partial class JiraForm : Form
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(JiraForm)); private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(JiraForm));
private readonly JiraConnector _jiraConnector; private readonly JiraConnector _jiraConnector;
private Issue _selectedIssue; private Issue _selectedIssue;
private readonly GreenshotColumnSorter _columnSorter; private readonly GreenshotColumnSorter _columnSorter;
private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>(); private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>();
public JiraForm(JiraConnector jiraConnector) { public JiraForm(JiraConnector jiraConnector)
{
InitializeComponent(); InitializeComponent();
Icon = GreenshotResources.GetGreenshotIcon(); Icon = GreenshotResources.GetGreenshotIcon();
AcceptButton = uploadButton; AcceptButton = uploadButton;
@ -70,6 +73,7 @@ namespace Greenshot.Plugin.Jira.Forms {
{ {
MessageBox.Show(Language.GetFormattedString("jira", LangKey.login_error, e.Message)); MessageBox.Show(Language.GetFormattedString("jira", LangKey.login_error, e.Message));
} }
if (_jiraConnector.IsLoggedIn) if (_jiraConnector.IsLoggedIn)
{ {
var filters = await _jiraConnector.GetFavoriteFiltersAsync(); var filters = await _jiraConnector.GetFavoriteFiltersAsync();
@ -79,8 +83,10 @@ namespace Greenshot.Plugin.Jira.Forms {
{ {
jiraFilterBox.Items.Add(filter); jiraFilterBox.Items.Add(filter);
} }
jiraFilterBox.SelectedIndex = 0; jiraFilterBox.SelectedIndex = 0;
} }
ChangeModus(true); ChangeModus(true);
if (_jiraConnector.Monitor.RecentJiras.Any()) if (_jiraConnector.Monitor.RecentJiras.Any())
{ {
@ -91,44 +97,53 @@ namespace Greenshot.Plugin.Jira.Forms {
} }
} }
private void InitializeComponentText() { private void InitializeComponentText()
{
label_jirafilter.Text = Language.GetString("jira", LangKey.label_jirafilter); label_jirafilter.Text = Language.GetString("jira", LangKey.label_jirafilter);
label_comment.Text = Language.GetString("jira", LangKey.label_comment); label_comment.Text = Language.GetString("jira", LangKey.label_comment);
label_filename.Text = Language.GetString("jira", LangKey.label_filename); label_filename.Text = Language.GetString("jira", LangKey.label_filename);
} }
private void ChangeModus(bool enabled) { private void ChangeModus(bool enabled)
{
jiraFilterBox.Enabled = enabled; jiraFilterBox.Enabled = enabled;
jiraListView.Enabled = enabled; jiraListView.Enabled = enabled;
jiraFilenameBox.Enabled = enabled; jiraFilenameBox.Enabled = enabled;
jiraCommentBox.Enabled = enabled; jiraCommentBox.Enabled = enabled;
} }
public void SetFilename(string filename) { public void SetFilename(string filename)
{
jiraFilenameBox.Text = filename; jiraFilenameBox.Text = filename;
} }
public Issue GetJiraIssue() { public Issue GetJiraIssue()
{
return _selectedIssue; return _selectedIssue;
} }
public async Task UploadAsync(IBinaryContainer attachment) { public async Task UploadAsync(IBinaryContainer attachment)
{
attachment.Filename = jiraFilenameBox.Text; attachment.Filename = jiraFilenameBox.Text;
await _jiraConnector.AttachAsync(_selectedIssue.Key, attachment); await _jiraConnector.AttachAsync(_selectedIssue.Key, attachment);
if (!string.IsNullOrEmpty(jiraCommentBox.Text)) { if (!string.IsNullOrEmpty(jiraCommentBox.Text))
{
await _jiraConnector.AddCommentAsync(_selectedIssue.Key, jiraCommentBox.Text); await _jiraConnector.AddCommentAsync(_selectedIssue.Key, jiraCommentBox.Text);
} }
} }
private async void JiraFilterBox_SelectedIndexChanged(object sender, EventArgs e) { private async void JiraFilterBox_SelectedIndexChanged(object sender, EventArgs e)
if (_jiraConnector.IsLoggedIn) { {
if (_jiraConnector.IsLoggedIn)
{
uploadButton.Enabled = false; uploadButton.Enabled = false;
var filter = (Filter) jiraFilterBox.SelectedItem; var filter = (Filter) jiraFilterBox.SelectedItem;
if (filter == null) { if (filter == null)
{
return; return;
} }
IList<Issue> issues = null; IList<Issue> issues = null;
try try
{ {
@ -141,25 +156,33 @@ namespace Greenshot.Plugin.Jira.Forms {
} }
jiraListView.Items.Clear(); jiraListView.Items.Clear();
if (issues?.Count > 0) { if (issues?.Count > 0)
{
jiraListView.Columns.Clear(); jiraListView.Columns.Clear();
LangKey[] columns = { LangKey.column_issueType, LangKey.column_id, LangKey.column_created, LangKey.column_assignee, LangKey.column_reporter, LangKey.column_summary }; LangKey[] columns =
{
LangKey.column_issueType, LangKey.column_id, LangKey.column_created, LangKey.column_assignee, LangKey.column_reporter, LangKey.column_summary
};
foreach (LangKey column in columns) foreach (LangKey column in columns)
{ {
if (!Language.TryGetString("jira", column, out var translation)) if (!Language.TryGetString("jira", column, out var translation))
{ {
translation = string.Empty; translation = string.Empty;
} }
jiraListView.Columns.Add(translation); jiraListView.Columns.Add(translation);
} }
var scaledIconSize = DpiHelper.ScaleWithDpi(CoreConfig.IconSize, DpiHelper.GetDpi(Handle)); var scaledIconSize = DpiHelper.ScaleWithDpi(CoreConfig.IconSize, DpiHelper.GetDpi(Handle));
var imageList = new ImageList { var imageList = new ImageList
{
ImageSize = scaledIconSize ImageSize = scaledIconSize
}; };
jiraListView.SmallImageList = imageList; jiraListView.SmallImageList = imageList;
jiraListView.LargeImageList = imageList; jiraListView.LargeImageList = imageList;
foreach (var issue in issues) { foreach (var issue in issues)
{
var item = new ListViewItem var item = new ListViewItem
{ {
Tag = issue Tag = issue
@ -187,6 +210,7 @@ namespace Greenshot.Plugin.Jira.Forms {
{ {
jiraListView.AutoResizeColumn(i, ColumnHeaderAutoResizeStyle.ColumnContent); jiraListView.AutoResizeColumn(i, ColumnHeaderAutoResizeStyle.ColumnContent);
} }
jiraListView.Invalidate(); jiraListView.Invalidate();
jiraListView.Update(); jiraListView.Update();
} }
@ -196,22 +220,30 @@ namespace Greenshot.Plugin.Jira.Forms {
} }
} }
private void JiraListView_SelectedIndexChanged(object sender, EventArgs e) { private void JiraListView_SelectedIndexChanged(object sender, EventArgs e)
if (jiraListView.SelectedItems.Count > 0) { {
if (jiraListView.SelectedItems.Count > 0)
{
_selectedIssue = (Issue) jiraListView.SelectedItems[0].Tag; _selectedIssue = (Issue) jiraListView.SelectedItems[0].Tag;
jiraKey.Text = _selectedIssue.Key; jiraKey.Text = _selectedIssue.Key;
uploadButton.Enabled = true; uploadButton.Enabled = true;
} else { }
else
{
uploadButton.Enabled = false; uploadButton.Enabled = false;
} }
} }
private void JiraListView_ColumnClick(object sender, ColumnClickEventArgs e) { private void JiraListView_ColumnClick(object sender, ColumnClickEventArgs e)
{
// Determine if clicked column is already the column that is being sorted. // Determine if clicked column is already the column that is being sorted.
if (e.Column == _columnSorter.SortColumn) { if (e.Column == _columnSorter.SortColumn)
{
// Reverse the current sort direction for this column. // Reverse the current sort direction for this column.
_columnSorter.Order = _columnSorter.Order == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending; _columnSorter.Order = _columnSorter.Order == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending;
} else { }
else
{
// Set the column number that is to be sorted; default to ascending. // Set the column number that is to be sorted; default to ascending.
_columnSorter.SortColumn = e.Column; _columnSorter.SortColumn = e.Column;
_columnSorter.Order = SortOrder.Ascending; _columnSorter.Order = SortOrder.Ascending;
@ -221,13 +253,16 @@ namespace Greenshot.Plugin.Jira.Forms {
jiraListView.Sort(); jiraListView.Sort();
} }
private async void JiraKeyTextChanged(object sender, EventArgs e) { private async void JiraKeyTextChanged(object sender, EventArgs e)
{
string jiranumber = jiraKey.Text; string jiranumber = jiraKey.Text;
uploadButton.Enabled = false; uploadButton.Enabled = false;
int dashIndex = jiranumber.IndexOf('-'); int dashIndex = jiranumber.IndexOf('-');
if (dashIndex > 0 && jiranumber.Length > dashIndex+1) { if (dashIndex > 0 && jiranumber.Length > dashIndex + 1)
{
_selectedIssue = await _jiraConnector.GetIssueAsync(jiraKey.Text); _selectedIssue = await _jiraConnector.GetIssueAsync(jiraKey.Text);
if (_selectedIssue != null) { if (_selectedIssue != null)
{
uploadButton.Enabled = true; uploadButton.Enabled = true;
} }
} }

View file

@ -21,7 +21,9 @@
using GreenshotPlugin.Controls; using GreenshotPlugin.Controls;
namespace Greenshot.Plugin.Jira.Forms { namespace Greenshot.Plugin.Jira.Forms
public class JiraFormBase : GreenshotForm { {
public class JiraFormBase : GreenshotForm
{
} }
} }

View file

@ -19,11 +19,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace Greenshot.Plugin.Jira.Forms { namespace Greenshot.Plugin.Jira.Forms
{
/// <summary> /// <summary>
/// Description of PasswordRequestForm. /// Description of PasswordRequestForm.
/// </summary> /// </summary>
public partial class SettingsForm : JiraFormBase { public partial class SettingsForm : JiraFormBase
{
public SettingsForm() public SettingsForm()
{ {
// //

View file

@ -22,12 +22,14 @@
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.Jira { namespace Greenshot.Plugin.Jira
{
/// <summary> /// <summary>
/// Description of JiraConfiguration. /// Description of JiraConfiguration.
/// </summary> /// </summary>
[IniSection("Jira", Description = "Greenshot Jira Plugin configuration")] [IniSection("Jira", Description = "Greenshot Jira Plugin configuration")]
public class JiraConfiguration : IniSection { public class JiraConfiguration : IniSection
{
public const string DefaultPrefix = "http://"; public const string DefaultPrefix = "http://";
private const string DefaultUrl = DefaultPrefix + "jira"; private const string DefaultUrl = DefaultPrefix + "jira";

View file

@ -34,14 +34,18 @@ using Dapplo.Jira.SvgWinForms.Converters;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.Jira { namespace Greenshot.Plugin.Jira
{
/// <summary> /// <summary>
/// This encapsulates the JiraClient to make it possible to change as less old Greenshot code as needed /// This encapsulates the JiraClient to make it possible to change as less old Greenshot code as needed
/// </summary> /// </summary>
public sealed class JiraConnector : IDisposable { public sealed class JiraConnector : IDisposable
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(JiraConnector)); private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(JiraConnector));
private static readonly JiraConfiguration JiraConfig = IniConfig.GetIniSection<JiraConfiguration>(); private static readonly JiraConfiguration JiraConfig = IniConfig.GetIniSection<JiraConfiguration>();
private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>(); private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>();
// Used to remove the wsdl information from the old SOAP Uri // Used to remove the wsdl information from the old SOAP Uri
public const string DefaultPostfix = "/rpc/soap/jirasoapservice-v2?wsdl"; public const string DefaultPostfix = "/rpc/soap/jirasoapservice-v2?wsdl";
private IJiraClient _jiraClient; private IJiraClient _jiraClient;
@ -57,20 +61,25 @@ namespace Greenshot.Plugin.Jira {
if (args.PropertyName == nameof(CoreConfig.IconSize)) if (args.PropertyName == nameof(CoreConfig.IconSize))
{ {
var jiraConnector = SimpleServiceProvider.Current.GetInstance<JiraConnector>(); var jiraConnector = SimpleServiceProvider.Current.GetInstance<JiraConnector>();
jiraConnector._jiraClient?.Behaviour.SetConfig(new SvgConfiguration { Width = CoreConfig.ScaledIconSize.Width, Height = CoreConfig.ScaledIconSize.Height }); jiraConnector._jiraClient?.Behaviour.SetConfig(new SvgConfiguration
{
Width = CoreConfig.ScaledIconSize.Width,
Height = CoreConfig.ScaledIconSize.Height
});
} }
}; };
} }
/// <summary> /// <summary>
/// Dispose, logout the users /// Dispose, logout the users
/// </summary> /// </summary>
public void Dispose() { public void Dispose()
{
if (_jiraClient != null) if (_jiraClient != null)
{ {
Logout(); Logout();
} }
FavIcon?.Dispose(); FavIcon?.Dispose();
} }
@ -99,8 +108,13 @@ namespace Greenshot.Plugin.Jira {
{ {
return false; return false;
} }
_jiraClient = JiraClient.Create(new Uri(JiraConfig.Url)); _jiraClient = JiraClient.Create(new Uri(JiraConfig.Url));
_jiraClient.Behaviour.SetConfig(new SvgConfiguration { Width = CoreConfig.ScaledIconSize.Width, Height = CoreConfig.ScaledIconSize.Height }); _jiraClient.Behaviour.SetConfig(new SvgConfiguration
{
Width = CoreConfig.ScaledIconSize.Width,
Height = CoreConfig.ScaledIconSize.Height
});
_jiraClient.SetBasicAuthentication(user, password); _jiraClient.SetBasicAuthentication(user, password);
_issueTypeBitmapCache = new IssueTypeBitmapCache(_jiraClient); _issueTypeBitmapCache = new IssueTypeBitmapCache(_jiraClient);
@ -126,6 +140,7 @@ namespace Greenshot.Plugin.Jira {
Log.Warn("Exception details: ", ex2); Log.Warn("Exception details: ", ex2);
return false; return false;
} }
return true; return true;
} }
@ -134,45 +149,58 @@ namespace Greenshot.Plugin.Jira {
/// If there are credentials, call the real login. /// If there are credentials, call the real login.
/// </summary> /// </summary>
/// <returns>Task</returns> /// <returns>Task</returns>
public async Task LoginAsync(CancellationToken cancellationToken = default) { public async Task LoginAsync(CancellationToken cancellationToken = default)
{
Logout(); Logout();
try { try
{
// Get the system name, so the user knows where to login to // Get the system name, so the user knows where to login to
var credentialsDialog = new CredentialsDialog(JiraConfig.Url) var credentialsDialog = new CredentialsDialog(JiraConfig.Url)
{ {
Name = null Name = null
}; };
while (credentialsDialog.Show(credentialsDialog.Name) == DialogResult.OK) { while (credentialsDialog.Show(credentialsDialog.Name) == DialogResult.OK)
if (await DoLoginAsync(credentialsDialog.Name, credentialsDialog.Password, cancellationToken)) { {
if (credentialsDialog.SaveChecked) { if (await DoLoginAsync(credentialsDialog.Name, credentialsDialog.Password, cancellationToken))
{
if (credentialsDialog.SaveChecked)
{
credentialsDialog.Confirm(true); credentialsDialog.Confirm(true);
} }
IsLoggedIn = true; IsLoggedIn = true;
return; return;
} }
// Login failed, confirm this // Login failed, confirm this
try { try
{
credentialsDialog.Confirm(false); credentialsDialog.Confirm(false);
} catch (ApplicationException e) { }
catch (ApplicationException e)
{
// exception handling ... // exception handling ...
Log.Error("Problem using the credentials dialog", e); Log.Error("Problem using the credentials dialog", e);
} }
// For every windows version after XP show an incorrect password baloon // For every windows version after XP show an incorrect password baloon
credentialsDialog.IncorrectPassword = true; credentialsDialog.IncorrectPassword = true;
// Make sure the dialog is display, the password was false! // Make sure the dialog is display, the password was false!
credentialsDialog.AlwaysDisplay = true; credentialsDialog.AlwaysDisplay = true;
} }
} catch (ApplicationException e) { }
catch (ApplicationException e)
{
// exception handling ... // exception handling ...
Log.Error("Problem using the credentials dialog", e); Log.Error("Problem using the credentials dialog", e);
} }
} }
/// <summary> /// <summary>
/// End the session, if there was one /// End the session, if there was one
/// </summary> /// </summary>
public void Logout() { public void Logout()
{
if (_jiraClient == null || !IsLoggedIn) return; if (_jiraClient == null || !IsLoggedIn) return;
Monitor.Dispose(); Monitor.Dispose();
IsLoggedIn = false; IsLoggedIn = false;
@ -183,8 +211,10 @@ namespace Greenshot.Plugin.Jira {
/// Do not use ConfigureAwait to call this, as it will move await from the UI thread. /// Do not use ConfigureAwait to call this, as it will move await from the UI thread.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
private async Task CheckCredentialsAsync(CancellationToken cancellationToken = default) { private async Task CheckCredentialsAsync(CancellationToken cancellationToken = default)
if (!IsLoggedIn) { {
if (!IsLoggedIn)
{
await LoginAsync(cancellationToken); await LoginAsync(cancellationToken);
} }
} }
@ -256,7 +286,10 @@ namespace Greenshot.Plugin.Jira {
public async Task<IList<Issue>> SearchAsync(Filter filter, CancellationToken cancellationToken = default) public async Task<IList<Issue>> SearchAsync(Filter filter, CancellationToken cancellationToken = default)
{ {
await CheckCredentialsAsync(cancellationToken); await CheckCredentialsAsync(cancellationToken);
var searchResult = await _jiraClient.Issue.SearchAsync(filter.Jql, null, new[] { "summary", "reporter", "assignee", "created", "issuetype" }, null, cancellationToken).ConfigureAwait(false); var searchResult = await _jiraClient.Issue.SearchAsync(filter.Jql, null, new[]
{
"summary", "reporter", "assignee", "created", "issuetype"
}, null, cancellationToken).ConfigureAwait(false);
return searchResult.Issues; return searchResult.Issues;
} }

View file

@ -34,27 +34,33 @@ using GreenshotPlugin.IniFile;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin; using GreenshotPlugin.Interfaces.Plugin;
namespace Greenshot.Plugin.Jira { namespace Greenshot.Plugin.Jira
{
/// <summary> /// <summary>
/// Description of JiraDestination. /// Description of JiraDestination.
/// </summary> /// </summary>
public class JiraDestination : AbstractDestination { public class JiraDestination : AbstractDestination
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(JiraDestination)); private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(JiraDestination));
private static readonly JiraConfiguration Config = IniConfig.GetIniSection<JiraConfiguration>(); private static readonly JiraConfiguration Config = IniConfig.GetIniSection<JiraConfiguration>();
private readonly Issue _jiraIssue; private readonly Issue _jiraIssue;
public JiraDestination(Issue jiraIssue = null) { public JiraDestination(Issue jiraIssue = null)
{
_jiraIssue = jiraIssue; _jiraIssue = jiraIssue;
} }
public override string Designation => "Jira"; public override string Designation => "Jira";
public override string Description { public override string Description
{
get get
{ {
if (_jiraIssue?.Fields?.Summary == null) { if (_jiraIssue?.Fields?.Summary == null)
{
return Language.GetString("jira", LangKey.upload_menu_item); return Language.GetString("jira", LangKey.upload_menu_item);
} }
// Format the title of this destination // Format the title of this destination
return _jiraIssue.Key + ": " + _jiraIssue.Fields.Summary.Substring(0, Math.Min(20, _jiraIssue.Fields.Summary.Length)); return _jiraIssue.Key + ": " + _jiraIssue.Fields.Summary.Substring(0, Math.Min(20, _jiraIssue.Fields.Summary.Length));
} }
@ -64,7 +70,8 @@ namespace Greenshot.Plugin.Jira {
public override bool IsDynamic => true; public override bool IsDynamic => true;
public override Image DisplayIcon { public override Image DisplayIcon
{
get get
{ {
Image displayIcon = null; Image displayIcon = null;
@ -83,16 +90,19 @@ namespace Greenshot.Plugin.Jira {
Log.Warn($"Problem loading issue type for {_jiraIssue.Key}, ignoring", ex); Log.Warn($"Problem loading issue type for {_jiraIssue.Key}, ignoring", ex);
} }
} }
if (displayIcon == null) if (displayIcon == null)
{ {
displayIcon = jiraConnector.FavIcon; displayIcon = jiraConnector.FavIcon;
} }
} }
if (displayIcon == null) if (displayIcon == null)
{ {
var resources = new ComponentResourceManager(typeof(JiraPlugin)); var resources = new ComponentResourceManager(typeof(JiraPlugin));
displayIcon = (Image) resources.GetObject("Jira"); displayIcon = (Image) resources.GetObject("Jira");
} }
return displayIcon; return displayIcon;
} }
} }
@ -100,22 +110,27 @@ namespace Greenshot.Plugin.Jira {
public override IEnumerable<IDestination> DynamicDestinations() public override IEnumerable<IDestination> DynamicDestinations()
{ {
var jiraConnector = SimpleServiceProvider.Current.GetInstance<JiraConnector>(); var jiraConnector = SimpleServiceProvider.Current.GetInstance<JiraConnector>();
if (jiraConnector == null || !jiraConnector.IsLoggedIn) { if (jiraConnector == null || !jiraConnector.IsLoggedIn)
{
yield break; yield break;
} }
foreach (var jiraDetails in jiraConnector.Monitor.RecentJiras) foreach (var jiraDetails in jiraConnector.Monitor.RecentJiras)
{ {
yield return new JiraDestination(jiraDetails.JiraIssue); yield return new JiraDestination(jiraDetails.JiraIssue);
} }
} }
public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surfaceToUpload, ICaptureDetails captureDetails) { public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surfaceToUpload, ICaptureDetails captureDetails)
{
ExportInformation exportInformation = new ExportInformation(Designation, Description); ExportInformation exportInformation = new ExportInformation(Designation, Description);
string filename = Path.GetFileName(FilenameHelper.GetFilename(Config.UploadFormat, captureDetails)); string filename = Path.GetFileName(FilenameHelper.GetFilename(Config.UploadFormat, captureDetails));
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(Config.UploadFormat, Config.UploadJpegQuality, Config.UploadReduceColors); SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(Config.UploadFormat, Config.UploadJpegQuality, Config.UploadReduceColors);
var jiraConnector = SimpleServiceProvider.Current.GetInstance<JiraConnector>(); var jiraConnector = SimpleServiceProvider.Current.GetInstance<JiraConnector>();
if (_jiraIssue != null) { if (_jiraIssue != null)
try { {
try
{
// Run upload in the background // Run upload in the background
new PleaseWaitForm().ShowAndWait(Description, Language.GetString("jira", LangKey.communication_wait), new PleaseWaitForm().ShowAndWait(Description, Language.GetString("jira", LangKey.communication_wait),
async () => async () =>
@ -128,31 +143,37 @@ namespace Greenshot.Plugin.Jira {
Log.DebugFormat("Uploaded to Jira {0}", _jiraIssue.Key); Log.DebugFormat("Uploaded to Jira {0}", _jiraIssue.Key);
exportInformation.ExportMade = true; exportInformation.ExportMade = true;
exportInformation.Uri = surfaceToUpload.UploadUrl; exportInformation.Uri = surfaceToUpload.UploadUrl;
} catch (Exception e) { }
catch (Exception e)
{
MessageBox.Show(Language.GetString("jira", LangKey.upload_failure) + " " + e.Message); MessageBox.Show(Language.GetString("jira", LangKey.upload_failure) + " " + e.Message);
} }
} else { }
else
{
var jiraForm = new JiraForm(jiraConnector); var jiraForm = new JiraForm(jiraConnector);
jiraForm.SetFilename(filename); jiraForm.SetFilename(filename);
var dialogResult = jiraForm.ShowDialog(); var dialogResult = jiraForm.ShowDialog();
if (dialogResult == DialogResult.OK) { if (dialogResult == DialogResult.OK)
try { {
try
{
surfaceToUpload.UploadUrl = jiraConnector.JiraBaseUri.AppendSegments("browse", jiraForm.GetJiraIssue().Key).AbsoluteUri; surfaceToUpload.UploadUrl = jiraConnector.JiraBaseUri.AppendSegments("browse", jiraForm.GetJiraIssue().Key).AbsoluteUri;
// Run upload in the background // Run upload in the background
new PleaseWaitForm().ShowAndWait(Description, Language.GetString("jira", LangKey.communication_wait), new PleaseWaitForm().ShowAndWait(Description, Language.GetString("jira", LangKey.communication_wait),
async () => async () => { await jiraForm.UploadAsync(new SurfaceContainer(surfaceToUpload, outputSettings, filename)); }
{
await jiraForm.UploadAsync(new SurfaceContainer(surfaceToUpload, outputSettings, filename));
}
); );
Log.DebugFormat("Uploaded to Jira {0}", jiraForm.GetJiraIssue().Key); Log.DebugFormat("Uploaded to Jira {0}", jiraForm.GetJiraIssue().Key);
exportInformation.ExportMade = true; exportInformation.ExportMade = true;
exportInformation.Uri = surfaceToUpload.UploadUrl; exportInformation.Uri = surfaceToUpload.UploadUrl;
} catch(Exception e) { }
catch (Exception e)
{
MessageBox.Show(Language.GetString("jira", LangKey.upload_failure) + " " + e.Message); MessageBox.Show(Language.GetString("jira", LangKey.upload_failure) + " " + e.Message);
} }
} }
} }
ProcessExport(exportInformation, surfaceToUpload); ProcessExport(exportInformation, surfaceToUpload);
return exportInformation; return exportInformation;
} }

View file

@ -31,37 +31,17 @@ namespace Greenshot.Plugin.Jira
FirstSeenAt = SeenAt = DateTimeOffset.Now; FirstSeenAt = SeenAt = DateTimeOffset.Now;
} }
public string ProjectKey public string ProjectKey { get; set; }
{
get;
set;
}
public string Id public string Id { get; set; }
{
get;
set;
}
public string JiraKey => ProjectKey + "-" + Id; public string JiraKey => ProjectKey + "-" + Id;
public Issue JiraIssue public Issue JiraIssue { get; set; }
{
get;
set;
}
public DateTimeOffset FirstSeenAt public DateTimeOffset FirstSeenAt { get; private set; }
{
get;
private set;
}
public DateTimeOffset SeenAt public DateTimeOffset SeenAt { get; set; }
{
get;
set;
}
public int CompareTo(JiraDetails other) public int CompareTo(JiraDetails other)
{ {

View file

@ -25,16 +25,8 @@ namespace Greenshot.Plugin.Jira
{ {
public class JiraEventArgs : EventArgs public class JiraEventArgs : EventArgs
{ {
public JiraEventTypes EventType public JiraEventTypes EventType { get; set; }
{
get;
set;
}
public JiraDetails Details public JiraDetails Details { get; set; }
{
get;
set;
}
} }
} }

View file

@ -31,7 +31,6 @@ using GreenshotPlugin.Hooking;
namespace Greenshot.Plugin.Jira namespace Greenshot.Plugin.Jira
{ {
/// <summary> /// <summary>
/// This class will monitor all _jira activity by registering for title changes /// This class will monitor all _jira activity by registering for title changes
/// It keeps a list of the last "accessed" jiras, and makes it easy to upload to one. /// It keeps a list of the last "accessed" jiras, and makes it easy to upload to one.
@ -44,7 +43,9 @@ namespace Greenshot.Plugin.Jira
private readonly WindowsTitleMonitor _monitor; private readonly WindowsTitleMonitor _monitor;
private readonly IList<IJiraClient> _jiraInstances = new List<IJiraClient>(); private readonly IList<IJiraClient> _jiraInstances = new List<IJiraClient>();
private readonly IDictionary<string, IJiraClient> _projectJiraClientMap = new Dictionary<string, IJiraClient>(); private readonly IDictionary<string, IJiraClient> _projectJiraClientMap = new Dictionary<string, IJiraClient>();
private readonly int _maxEntries; private readonly int _maxEntries;
// TODO: Add issues from issueHistory (JQL -> Where.IssueKey.InIssueHistory()) // TODO: Add issues from issueHistory (JQL -> Where.IssueKey.InIssueHistory())
private IDictionary<string, JiraDetails> _recentJiras = new Dictionary<string, JiraDetails>(); private IDictionary<string, JiraDetails> _recentJiras = new Dictionary<string, JiraDetails>();
@ -79,6 +80,7 @@ namespace Greenshot.Plugin.Jira
{ {
return; return;
} }
// free managed resources // free managed resources
_monitor.TitleChangeEvent -= MonitorTitleChangeEvent; _monitor.TitleChangeEvent -= MonitorTitleChangeEvent;
_monitor.Dispose(); _monitor.Dispose();
@ -143,8 +145,13 @@ namespace Greenshot.Plugin.Jira
var issue = await jiraClient.Issue.GetAsync(jiraDetails.JiraKey).ConfigureAwait(false); var issue = await jiraClient.Issue.GetAsync(jiraDetails.JiraKey).ConfigureAwait(false);
jiraDetails.JiraIssue = issue; jiraDetails.JiraIssue = issue;
} }
// Send event // Send event
JiraEvent?.Invoke(this, new JiraEventArgs { Details = jiraDetails, EventType = JiraEventTypes.DetectedNewJiraIssue }); JiraEvent?.Invoke(this, new JiraEventArgs
{
Details = jiraDetails,
EventType = JiraEventTypes.DetectedNewJiraIssue
});
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -163,11 +170,13 @@ namespace Greenshot.Plugin.Jira
{ {
return; return;
} }
var jiraKeyMatch = _jiraKeyPattern.Match(windowTitle); var jiraKeyMatch = _jiraKeyPattern.Match(windowTitle);
if (!jiraKeyMatch.Success) if (!jiraKeyMatch.Success)
{ {
return; return;
} }
// Found a possible JIRA title // Found a possible JIRA title
var jiraKey = jiraKeyMatch.Value; var jiraKey = jiraKeyMatch.Value;
var jiraKeyParts = jiraKey.Split('-'); var jiraKeyParts = jiraKey.Split('-');
@ -184,11 +193,16 @@ namespace Greenshot.Plugin.Jira
currentJiraDetails.SeenAt = DateTimeOffset.Now; currentJiraDetails.SeenAt = DateTimeOffset.Now;
// Notify the order change // Notify the order change
JiraEvent?.Invoke(this, new JiraEventArgs { Details = currentJiraDetails, EventType = JiraEventTypes.OrderChanged }); JiraEvent?.Invoke(this, new JiraEventArgs
{
Details = currentJiraDetails,
EventType = JiraEventTypes.OrderChanged
});
// Nothing else to do // Nothing else to do
return; return;
} }
// We detected an unknown JIRA, so add it to our list // We detected an unknown JIRA, so add it to our list
currentJiraDetails = new JiraDetails currentJiraDetails = new JiraDetails
{ {
@ -205,6 +219,7 @@ namespace Greenshot.Plugin.Jira
orderby jiraDetails.SeenAt descending orderby jiraDetails.SeenAt descending
select jiraDetails).Take(_maxEntries).ToDictionary(jd => jd.JiraKey, jd => jd); select jiraDetails).Take(_maxEntries).ToDictionary(jd => jd.JiraKey, jd => jd);
} }
// Now we can get the title from JIRA itself // Now we can get the title from JIRA itself
// ReSharper disable once UnusedVariable // ReSharper disable once UnusedVariable
var updateTitleTask = DetectedNewJiraIssueAsync(currentJiraDetails); var updateTitleTask = DetectedNewJiraIssueAsync(currentJiraDetails);

View file

@ -30,21 +30,25 @@ using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin; using GreenshotPlugin.Interfaces.Plugin;
using log4net; using log4net;
namespace Greenshot.Plugin.Jira { namespace Greenshot.Plugin.Jira
{
/// <summary> /// <summary>
/// This is the JiraPlugin base code /// This is the JiraPlugin base code
/// </summary> /// </summary>
[Plugin("Jira", true)] [Plugin("Jira", true)]
public class JiraPlugin : IGreenshotPlugin { public class JiraPlugin : IGreenshotPlugin
{
private static readonly ILog Log = LogManager.GetLogger(typeof(JiraPlugin)); private static readonly ILog Log = LogManager.GetLogger(typeof(JiraPlugin));
private JiraConfiguration _config; private JiraConfiguration _config;
public void Dispose() { public void Dispose()
{
Dispose(true); Dispose(true);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
protected void Dispose(bool disposing) { protected void Dispose(bool disposing)
{
if (disposing) if (disposing)
{ {
var jiraConnector = SimpleServiceProvider.Current.GetInstance<JiraConnector>(); var jiraConnector = SimpleServiceProvider.Current.GetInstance<JiraConnector>();
@ -56,7 +60,8 @@ namespace Greenshot.Plugin.Jira {
/// Implementation of the IGreenshotPlugin.Initialize /// Implementation of the IGreenshotPlugin.Initialize
/// </summary> /// </summary>
/// <returns>true if plugin is initialized, false if not (doesn't show)</returns> /// <returns>true if plugin is initialized, false if not (doesn't show)</returns>
public bool Initialize() { public bool Initialize()
{
// Register configuration (don't need the configuration itself) // Register configuration (don't need the configuration itself)
_config = IniConfig.GetIniSection<JiraConfiguration>(); _config = IniConfig.GetIniSection<JiraConfiguration>();
@ -94,7 +99,8 @@ namespace Greenshot.Plugin.Jira {
return true; return true;
} }
public void Shutdown() { public void Shutdown()
{
Log.Debug("Jira Plugin shutdown."); Log.Debug("Jira Plugin shutdown.");
var jiraConnector = SimpleServiceProvider.Current.GetInstance<JiraConnector>(); var jiraConnector = SimpleServiceProvider.Current.GetInstance<JiraConnector>();
jiraConnector?.Logout(); jiraConnector?.Logout();
@ -103,18 +109,19 @@ namespace Greenshot.Plugin.Jira {
/// <summary> /// <summary>
/// Implementation of the IPlugin.Configure /// Implementation of the IPlugin.Configure
/// </summary> /// </summary>
public void Configure() { public void Configure()
{
string url = _config.Url; string url = _config.Url;
if (ShowConfigDialog()) { if (ShowConfigDialog())
{
// check for re-login // check for re-login
var jiraConnector = SimpleServiceProvider.Current.GetInstance<JiraConnector>(); var jiraConnector = SimpleServiceProvider.Current.GetInstance<JiraConnector>();
if (jiraConnector != null && jiraConnector.IsLoggedIn && !string.IsNullOrEmpty(url)) { if (jiraConnector != null && jiraConnector.IsLoggedIn && !string.IsNullOrEmpty(url))
if (!url.Equals(_config.Url)) {
jiraConnector.Logout();
Task.Run(async () =>
{ {
await jiraConnector.LoginAsync(); if (!url.Equals(_config.Url))
}); {
jiraConnector.Logout();
Task.Run(async () => { await jiraConnector.LoginAsync(); });
} }
} }
} }
@ -132,6 +139,7 @@ namespace Greenshot.Plugin.Jira {
{ {
return true; return true;
} }
return false; return false;
} }
} }

View file

@ -19,8 +19,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace Greenshot.Plugin.Jira { namespace Greenshot.Plugin.Jira
public enum LangKey { {
public enum LangKey
{
upload_menu_item, upload_menu_item,
column_assignee, column_assignee,
column_created, column_created,

View file

@ -114,6 +114,7 @@ namespace Greenshot.Plugin.Jira
case LogLevels.Warn: case LogLevels.Warn:
return log.IsWarnEnabled; return log.IsWarnEnabled;
} }
return false; return false;
} }
} }

View file

@ -1,5 +1,6 @@
// Copyright (c) Dapplo and contributors. All rights reserved. // Copyright (c) Dapplo and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Greenshot.Plugin.Office.Com namespace Greenshot.Plugin.Office.Com
{ {
/// <summary> /// <summary>

View file

@ -38,6 +38,7 @@ namespace Greenshot.Plugin.Office.Com
{ {
return; return;
} }
// Do not catch an exception from this. // Do not catch an exception from this.
// You may want to remove these guards depending on // You may want to remove these guards depending on
// what you think the semantics should be. // what you think the semantics should be.
@ -45,6 +46,7 @@ namespace Greenshot.Plugin.Office.Com
{ {
Marshal.ReleaseComObject(ComObject); Marshal.ReleaseComObject(ComObject);
} }
ComObject = default; ComObject = default;
} }
} }

View file

@ -24,6 +24,7 @@ namespace Greenshot.Plugin.Office.Com
{ {
return clsId; return clsId;
} }
return clsId; return clsId;
} }

View file

@ -28,29 +28,37 @@ using GreenshotPlugin.Core;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin; using GreenshotPlugin.Interfaces.Plugin;
namespace Greenshot.Plugin.Office.Destinations { namespace Greenshot.Plugin.Office.Destinations
{
/// <summary> /// <summary>
/// Description of PowerpointDestination. /// Description of PowerpointDestination.
/// </summary> /// </summary>
public class ExcelDestination : AbstractDestination { public class ExcelDestination : AbstractDestination
{
private const int IconApplication = 0; private const int IconApplication = 0;
private const int IconWorkbook = 1; private const int IconWorkbook = 1;
private static readonly string ExePath; private static readonly string ExePath;
private readonly string _workbookName; private readonly string _workbookName;
static ExcelDestination() { static ExcelDestination()
{
ExePath = PluginUtils.GetExePath("EXCEL.EXE"); ExePath = PluginUtils.GetExePath("EXCEL.EXE");
if (ExePath != null && File.Exists(ExePath)) { if (ExePath != null && File.Exists(ExePath))
{
WindowDetails.AddProcessToExcludeFromFreeze("excel"); WindowDetails.AddProcessToExcludeFromFreeze("excel");
} else { }
else
{
ExePath = null; ExePath = null;
} }
} }
public ExcelDestination() { public ExcelDestination()
{
} }
public ExcelDestination(string workbookName) { public ExcelDestination(string workbookName)
{
_workbookName = workbookName; _workbookName = workbookName;
} }
@ -66,31 +74,42 @@ namespace Greenshot.Plugin.Office.Destinations {
public override Image DisplayIcon => PluginUtils.GetCachedExeIcon(ExePath, !string.IsNullOrEmpty(_workbookName) ? IconWorkbook : IconApplication); public override Image DisplayIcon => PluginUtils.GetCachedExeIcon(ExePath, !string.IsNullOrEmpty(_workbookName) ? IconWorkbook : IconApplication);
public override IEnumerable<IDestination> DynamicDestinations() { public override IEnumerable<IDestination> DynamicDestinations()
foreach (string workbookName in ExcelExporter.GetWorkbooks()) { {
foreach (string workbookName in ExcelExporter.GetWorkbooks())
{
yield return new ExcelDestination(workbookName); yield return new ExcelDestination(workbookName);
} }
} }
public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails)
{
ExportInformation exportInformation = new ExportInformation(Designation, Description); ExportInformation exportInformation = new ExportInformation(Designation, Description);
bool createdFile = false; bool createdFile = false;
string imageFile = captureDetails.Filename; string imageFile = captureDetails.Filename;
if (imageFile == null || surface.Modified || !Regex.IsMatch(imageFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) { if (imageFile == null || surface.Modified || !Regex.IsMatch(imageFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$"))
{
imageFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); imageFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat());
createdFile = true; createdFile = true;
} }
if (_workbookName != null) {
if (_workbookName != null)
{
ExcelExporter.InsertIntoExistingWorkbook(_workbookName, imageFile, surface.Image.Size); ExcelExporter.InsertIntoExistingWorkbook(_workbookName, imageFile, surface.Image.Size);
} else { }
else
{
ExcelExporter.InsertIntoNewWorkbook(imageFile, surface.Image.Size); ExcelExporter.InsertIntoNewWorkbook(imageFile, surface.Image.Size);
} }
exportInformation.ExportMade = true; exportInformation.ExportMade = true;
ProcessExport(exportInformation, surface); ProcessExport(exportInformation, surface);
// Cleanup imageFile if we created it here, so less tmp-files are generated and left // Cleanup imageFile if we created it here, so less tmp-files are generated and left
if (createdFile) { if (createdFile)
{
ImageOutput.DeleteNamedTmpFile(imageFile); ImageOutput.DeleteNamedTmpFile(imageFile);
} }
return exportInformation; return exportInformation;
} }
} }

View file

@ -28,8 +28,10 @@ using Greenshot.Plugin.Office.OfficeExport.Entities;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
namespace Greenshot.Plugin.Office.Destinations { namespace Greenshot.Plugin.Office.Destinations
public class OneNoteDestination : AbstractDestination { {
public class OneNoteDestination : AbstractDestination
{
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(WordDestination)); private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(WordDestination));
private const int ICON_APPLICATION = 0; private const int ICON_APPLICATION = 0;
public const string DESIGNATION = "OneNote"; public const string DESIGNATION = "OneNote";
@ -37,87 +39,105 @@ namespace Greenshot.Plugin.Office.Destinations {
private readonly OneNotePage page; private readonly OneNotePage page;
private readonly OneNoteExporter _oneNoteExporter = new OneNoteExporter(); private readonly OneNoteExporter _oneNoteExporter = new OneNoteExporter();
static OneNoteDestination() { static OneNoteDestination()
{
exePath = PluginUtils.GetExePath("ONENOTE.EXE"); exePath = PluginUtils.GetExePath("ONENOTE.EXE");
if (exePath != null && File.Exists(exePath)) { if (exePath != null && File.Exists(exePath))
{
WindowDetails.AddProcessToExcludeFromFreeze("onenote"); WindowDetails.AddProcessToExcludeFromFreeze("onenote");
} else { }
else
{
exePath = null; exePath = null;
} }
} }
public OneNoteDestination() { public OneNoteDestination()
{
} }
public OneNoteDestination(OneNotePage page) { public OneNoteDestination(OneNotePage page)
{
this.page = page; this.page = page;
} }
public override string Designation { public override string Designation
get { {
return DESIGNATION; get { return DESIGNATION; }
}
} }
public override string Description { public override string Description
get { {
if (page == null) { get
{
if (page == null)
{
return "Microsoft OneNote"; return "Microsoft OneNote";
} else { }
else
{
return page.DisplayName; return page.DisplayName;
} }
} }
} }
public override int Priority { public override int Priority
get { {
return 4; get { return 4; }
}
} }
public override bool IsDynamic { public override bool IsDynamic
get { {
return true; get { return true; }
}
} }
public override bool IsActive { public override bool IsActive
get { {
return base.IsActive && exePath != null; get { return base.IsActive && exePath != null; }
}
} }
public override Image DisplayIcon { public override Image DisplayIcon
get { {
return PluginUtils.GetCachedExeIcon(exePath, ICON_APPLICATION); get { return PluginUtils.GetCachedExeIcon(exePath, ICON_APPLICATION); }
}
} }
public override IEnumerable<IDestination> DynamicDestinations() { public override IEnumerable<IDestination> DynamicDestinations()
foreach (OneNotePage page in _oneNoteExporter.GetPages()) { {
foreach (OneNotePage page in _oneNoteExporter.GetPages())
{
yield return new OneNoteDestination(page); yield return new OneNoteDestination(page);
} }
} }
public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails)
{
ExportInformation exportInformation = new ExportInformation(Designation, Description); ExportInformation exportInformation = new ExportInformation(Designation, Description);
if (page == null) { if (page == null)
try { {
try
{
exportInformation.ExportMade = _oneNoteExporter.ExportToNewPage(surface); exportInformation.ExportMade = _oneNoteExporter.ExportToNewPage(surface);
} catch(Exception ex) { }
catch (Exception ex)
{
exportInformation.ErrorMessage = ex.Message; exportInformation.ErrorMessage = ex.Message;
LOG.Error(ex); LOG.Error(ex);
} }
} else { }
try { else
{
try
{
exportInformation.ExportMade = _oneNoteExporter.ExportToPage(surface, page); exportInformation.ExportMade = _oneNoteExporter.ExportToPage(surface, page);
} catch(Exception ex) { }
catch (Exception ex)
{
exportInformation.ErrorMessage = ex.Message; exportInformation.ErrorMessage = ex.Message;
LOG.Error(ex); LOG.Error(ex);
} }
} }
return exportInformation; return exportInformation;
} }
} }

View file

@ -32,11 +32,13 @@ using GreenshotPlugin.Interfaces.Plugin;
using Microsoft.Office.Interop.Outlook; using Microsoft.Office.Interop.Outlook;
using Microsoft.Win32; using Microsoft.Win32;
namespace Greenshot.Plugin.Office.Destinations { namespace Greenshot.Plugin.Office.Destinations
{
/// <summary> /// <summary>
/// Description of OutlookDestination. /// Description of OutlookDestination.
/// </summary> /// </summary>
public class OutlookDestination : AbstractDestination { public class OutlookDestination : AbstractDestination
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(OutlookDestination)); private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(OutlookDestination));
private const int IconApplication = 0; private const int IconApplication = 0;
private const int IconMeeting = 2; private const int IconMeeting = 2;
@ -50,17 +52,25 @@ namespace Greenshot.Plugin.Office.Destinations {
private readonly OlObjectClass _outlookInspectorType; private readonly OlObjectClass _outlookInspectorType;
private readonly OutlookEmailExporter _outlookEmailExporter = new(); private readonly OutlookEmailExporter _outlookEmailExporter = new();
static OutlookDestination() { static OutlookDestination()
if (HasOutlook()) { {
if (HasOutlook())
{
IsActiveFlag = true; IsActiveFlag = true;
} }
ExePath = PluginUtils.GetExePath("OUTLOOK.EXE"); ExePath = PluginUtils.GetExePath("OUTLOOK.EXE");
if (ExePath != null && File.Exists(ExePath)) { if (ExePath != null && File.Exists(ExePath))
{
WindowDetails.AddProcessToExcludeFromFreeze("outlook"); WindowDetails.AddProcessToExcludeFromFreeze("outlook");
} else { }
else
{
ExePath = GetOutlookExePath(); ExePath = GetOutlookExePath();
} }
if (ExePath == null) {
if (ExePath == null)
{
IsActiveFlag = false; IsActiveFlag = false;
} }
} }
@ -79,13 +89,16 @@ namespace Greenshot.Plugin.Office.Destinations {
{ {
return false; return false;
} }
return File.Exists(outlookPath); return File.Exists(outlookPath);
} }
public OutlookDestination() { public OutlookDestination()
{
} }
public OutlookDestination(string outlookInspectorCaption, OlObjectClass outlookInspectorType) { public OutlookDestination(string outlookInspectorCaption, OlObjectClass outlookInspectorType)
{
_outlookInspectorCaption = outlookInspectorCaption; _outlookInspectorCaption = outlookInspectorCaption;
_outlookInspectorType = outlookInspectorType; _outlookInspectorType = outlookInspectorType;
} }
@ -102,25 +115,32 @@ namespace Greenshot.Plugin.Office.Destinations {
public override Keys EditorShortcutKeys => Keys.Control | Keys.E; public override Keys EditorShortcutKeys => Keys.Control | Keys.E;
public override Image DisplayIcon { public override Image DisplayIcon
{
get get
{ {
if (_outlookInspectorCaption == null) if (_outlookInspectorCaption == null)
{ {
return PluginUtils.GetCachedExeIcon(ExePath, IconApplication); return PluginUtils.GetCachedExeIcon(ExePath, IconApplication);
} }
if (OlObjectClass.olAppointment.Equals(_outlookInspectorType)) {
if (OlObjectClass.olAppointment.Equals(_outlookInspectorType))
{
// Make sure we loaded the icon, maybe the configuration has been changed! // Make sure we loaded the icon, maybe the configuration has been changed!
return PluginUtils.GetCachedExeIcon(ExePath, IconMeeting); return PluginUtils.GetCachedExeIcon(ExePath, IconMeeting);
} }
return MailIcon; return MailIcon;
} }
} }
public override IEnumerable<IDestination> DynamicDestinations() { public override IEnumerable<IDestination> DynamicDestinations()
{
IDictionary<string, OlObjectClass> inspectorCaptions = _outlookEmailExporter.RetrievePossibleTargets(); IDictionary<string, OlObjectClass> inspectorCaptions = _outlookEmailExporter.RetrievePossibleTargets();
if (inspectorCaptions != null) { if (inspectorCaptions != null)
foreach (string inspectorCaption in inspectorCaptions.Keys) { {
foreach (string inspectorCaption in inspectorCaptions.Keys)
{
yield return new OutlookDestination(inspectorCaption, inspectorCaptions[inspectorCaption]); yield return new OutlookDestination(inspectorCaption, inspectorCaptions[inspectorCaption]);
} }
} }
@ -133,49 +153,69 @@ namespace Greenshot.Plugin.Office.Destinations {
/// <param name="surface"></param> /// <param name="surface"></param>
/// <param name="captureDetails"></param> /// <param name="captureDetails"></param>
/// <returns></returns> /// <returns></returns>
public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails)
{
ExportInformation exportInformation = new ExportInformation(Designation, Description); ExportInformation exportInformation = new ExportInformation(Designation, Description);
// Outlook logic // Outlook logic
string tmpFile = captureDetails.Filename; string tmpFile = captureDetails.Filename;
if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) { if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$"))
{
tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat());
} else { }
else
{
Log.InfoFormat("Using already available file: {0}", tmpFile); Log.InfoFormat("Using already available file: {0}", tmpFile);
} }
// Create a attachment name for the image // Create a attachment name for the image
string attachmentName = captureDetails.Title; string attachmentName = captureDetails.Title;
if (!string.IsNullOrEmpty(attachmentName)) { if (!string.IsNullOrEmpty(attachmentName))
{
attachmentName = attachmentName.Trim(); attachmentName = attachmentName.Trim();
} }
// Set default if non is set // Set default if non is set
if (string.IsNullOrEmpty(attachmentName)) { if (string.IsNullOrEmpty(attachmentName))
{
attachmentName = "Greenshot Capture"; attachmentName = "Greenshot Capture";
} }
// Make sure it's "clean" so it doesn't corrupt the header // Make sure it's "clean" so it doesn't corrupt the header
attachmentName = Regex.Replace(attachmentName, @"[^\x20\d\w]", string.Empty); attachmentName = Regex.Replace(attachmentName, @"[^\x20\d\w]", string.Empty);
if (_outlookInspectorCaption != null) { if (_outlookInspectorCaption != null)
{
_outlookEmailExporter.ExportToInspector(_outlookInspectorCaption, tmpFile, attachmentName); _outlookEmailExporter.ExportToInspector(_outlookInspectorCaption, tmpFile, attachmentName);
exportInformation.ExportMade = true; exportInformation.ExportMade = true;
} else { }
if (!manuallyInitiated) { else
{
if (!manuallyInitiated)
{
var inspectorCaptions = _outlookEmailExporter.RetrievePossibleTargets(); var inspectorCaptions = _outlookEmailExporter.RetrievePossibleTargets();
if (inspectorCaptions != null && inspectorCaptions.Count > 0) { if (inspectorCaptions != null && inspectorCaptions.Count > 0)
{
var destinations = new List<IDestination> var destinations = new List<IDestination>
{ {
new OutlookDestination() new OutlookDestination()
}; };
foreach (string inspectorCaption in inspectorCaptions.Keys) { foreach (string inspectorCaption in inspectorCaptions.Keys)
{
destinations.Add(new OutlookDestination(inspectorCaption, inspectorCaptions[inspectorCaption])); destinations.Add(new OutlookDestination(inspectorCaption, inspectorCaptions[inspectorCaption]));
} }
// Return the ExportInformation from the picker without processing, as this indirectly comes from us self // Return the ExportInformation from the picker without processing, as this indirectly comes from us self
return ShowPickerMenu(false, surface, captureDetails, destinations); return ShowPickerMenu(false, surface, captureDetails, destinations);
} }
} else { }
exportInformation.ExportMade = _outlookEmailExporter.ExportToOutlook(OfficeConfig.OutlookEmailFormat, tmpFile, FilenameHelper.FillPattern(OfficeConfig.EmailSubjectPattern, captureDetails, false), attachmentName, OfficeConfig.EmailTo, OfficeConfig.EmailCC, OfficeConfig.EmailBCC, null); else
{
exportInformation.ExportMade = _outlookEmailExporter.ExportToOutlook(OfficeConfig.OutlookEmailFormat, tmpFile,
FilenameHelper.FillPattern(OfficeConfig.EmailSubjectPattern, captureDetails, false), attachmentName, OfficeConfig.EmailTo, OfficeConfig.EmailCC,
OfficeConfig.EmailBCC, null);
} }
} }
ProcessExport(exportInformation, surface); ProcessExport(exportInformation, surface);
return exportInformation; return exportInformation;
} }

View file

@ -29,11 +29,13 @@ using GreenshotPlugin.Core;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin; using GreenshotPlugin.Interfaces.Plugin;
namespace Greenshot.Plugin.Office.Destinations { namespace Greenshot.Plugin.Office.Destinations
{
/// <summary> /// <summary>
/// Description of PowerpointDestination. /// Description of PowerpointDestination.
/// </summary> /// </summary>
public class PowerpointDestination : AbstractDestination { public class PowerpointDestination : AbstractDestination
{
private const int IconApplication = 0; private const int IconApplication = 0;
private const int IconPresentation = 1; private const int IconPresentation = 1;
@ -41,30 +43,39 @@ namespace Greenshot.Plugin.Office.Destinations {
private readonly string _presentationName; private readonly string _presentationName;
private readonly PowerpointExporter _powerpointExporter = new PowerpointExporter(); private readonly PowerpointExporter _powerpointExporter = new PowerpointExporter();
static PowerpointDestination() { static PowerpointDestination()
{
ExePath = PluginUtils.GetExePath("POWERPNT.EXE"); ExePath = PluginUtils.GetExePath("POWERPNT.EXE");
if (ExePath != null && File.Exists(ExePath)) { if (ExePath != null && File.Exists(ExePath))
{
WindowDetails.AddProcessToExcludeFromFreeze("powerpnt"); WindowDetails.AddProcessToExcludeFromFreeze("powerpnt");
} else { }
else
{
ExePath = null; ExePath = null;
} }
} }
public PowerpointDestination() { public PowerpointDestination()
{
} }
public PowerpointDestination(string presentationName) { public PowerpointDestination(string presentationName)
{
_presentationName = presentationName; _presentationName = presentationName;
} }
public override string Designation => "Powerpoint"; public override string Designation => "Powerpoint";
public override string Description { public override string Description
{
get get
{ {
if (_presentationName == null) { if (_presentationName == null)
{
return "Microsoft Powerpoint"; return "Microsoft Powerpoint";
} }
return _presentationName; return _presentationName;
} }
} }
@ -75,9 +86,12 @@ namespace Greenshot.Plugin.Office.Destinations {
public override bool IsActive => base.IsActive && ExePath != null; public override bool IsActive => base.IsActive && ExePath != null;
public override Image DisplayIcon { public override Image DisplayIcon
get { {
if (!string.IsNullOrEmpty(_presentationName)) { get
{
if (!string.IsNullOrEmpty(_presentationName))
{
return PluginUtils.GetCachedExeIcon(ExePath, IconPresentation); return PluginUtils.GetCachedExeIcon(ExePath, IconPresentation);
} }
@ -85,37 +99,55 @@ namespace Greenshot.Plugin.Office.Destinations {
} }
} }
public override IEnumerable<IDestination> DynamicDestinations() { public override IEnumerable<IDestination> DynamicDestinations()
foreach (string presentationName in _powerpointExporter.GetPowerpointPresentations()) { {
foreach (string presentationName in _powerpointExporter.GetPowerpointPresentations())
{
yield return new PowerpointDestination(presentationName); yield return new PowerpointDestination(presentationName);
} }
} }
public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails)
{
ExportInformation exportInformation = new ExportInformation(Designation, Description); ExportInformation exportInformation = new ExportInformation(Designation, Description);
string tmpFile = captureDetails.Filename; string tmpFile = captureDetails.Filename;
Size imageSize = Size.Empty; Size imageSize = Size.Empty;
if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) { if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$"))
{
tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat());
imageSize = surface.Image.Size; imageSize = surface.Image.Size;
} }
if (_presentationName != null) {
if (_presentationName != null)
{
exportInformation.ExportMade = _powerpointExporter.ExportToPresentation(_presentationName, tmpFile, imageSize, captureDetails.Title); exportInformation.ExportMade = _powerpointExporter.ExportToPresentation(_presentationName, tmpFile, imageSize, captureDetails.Title);
} else { }
if (!manuallyInitiated) { else
{
if (!manuallyInitiated)
{
var presentations = _powerpointExporter.GetPowerpointPresentations().ToList(); var presentations = _powerpointExporter.GetPowerpointPresentations().ToList();
if (presentations != null && presentations.Count > 0) { if (presentations != null && presentations.Count > 0)
var destinations = new List<IDestination> {new PowerpointDestination()}; {
foreach (string presentation in presentations) { var destinations = new List<IDestination>
{
new PowerpointDestination()
};
foreach (string presentation in presentations)
{
destinations.Add(new PowerpointDestination(presentation)); destinations.Add(new PowerpointDestination(presentation));
} }
// Return the ExportInformation from the picker without processing, as this indirectly comes from us self // Return the ExportInformation from the picker without processing, as this indirectly comes from us self
return ShowPickerMenu(false, surface, captureDetails, destinations); return ShowPickerMenu(false, surface, captureDetails, destinations);
} }
} else if (!exportInformation.ExportMade) { }
else if (!exportInformation.ExportMade)
{
exportInformation.ExportMade = _powerpointExporter.InsertIntoNewPresentation(tmpFile, imageSize, captureDetails.Title); exportInformation.ExportMade = _powerpointExporter.InsertIntoNewPresentation(tmpFile, imageSize, captureDetails.Title);
} }
} }
ProcessExport(exportInformation, surface); ProcessExport(exportInformation, surface);
return exportInformation; return exportInformation;
} }

View file

@ -30,29 +30,35 @@ using GreenshotPlugin.Core;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin; using GreenshotPlugin.Interfaces.Plugin;
namespace Greenshot.Plugin.Office.Destinations { namespace Greenshot.Plugin.Office.Destinations
{
/// <summary> /// <summary>
/// Description of EmailDestination. /// Description of EmailDestination.
/// </summary> /// </summary>
public class WordDestination : AbstractDestination { public class WordDestination : AbstractDestination
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(WordDestination)); private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(WordDestination));
private const int IconApplication = 0; private const int IconApplication = 0;
private const int IconDocument = 1; private const int IconDocument = 1;
private static readonly string ExePath; private static readonly string ExePath;
private readonly string _documentCaption; private readonly string _documentCaption;
private readonly WordExporter _wordExporter = new WordExporter(); private readonly WordExporter _wordExporter = new WordExporter();
static WordDestination() {
static WordDestination()
{
ExePath = PluginUtils.GetExePath("WINWORD.EXE"); ExePath = PluginUtils.GetExePath("WINWORD.EXE");
if (ExePath != null && !File.Exists(ExePath)) { if (ExePath != null && !File.Exists(ExePath))
{
ExePath = null; ExePath = null;
} }
} }
public WordDestination() { public WordDestination()
{
} }
public WordDestination(string wordCaption) { public WordDestination(string wordCaption)
{
_documentCaption = wordCaption; _documentCaption = wordCaption;
} }
@ -68,62 +74,88 @@ namespace Greenshot.Plugin.Office.Destinations {
public override Image DisplayIcon => PluginUtils.GetCachedExeIcon(ExePath, !string.IsNullOrEmpty(_documentCaption) ? IconDocument : IconApplication); public override Image DisplayIcon => PluginUtils.GetCachedExeIcon(ExePath, !string.IsNullOrEmpty(_documentCaption) ? IconDocument : IconApplication);
public override IEnumerable<IDestination> DynamicDestinations() { public override IEnumerable<IDestination> DynamicDestinations()
foreach (string wordCaption in _wordExporter.GetWordDocuments()) { {
foreach (string wordCaption in _wordExporter.GetWordDocuments())
{
yield return new WordDestination(wordCaption); yield return new WordDestination(wordCaption);
} }
} }
public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails)
{
ExportInformation exportInformation = new ExportInformation(Designation, Description); ExportInformation exportInformation = new ExportInformation(Designation, Description);
string tmpFile = captureDetails.Filename; string tmpFile = captureDetails.Filename;
if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) { if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$"))
{
tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat());
} }
if (_documentCaption != null) {
try { if (_documentCaption != null)
{
try
{
_wordExporter.InsertIntoExistingDocument(_documentCaption, tmpFile); _wordExporter.InsertIntoExistingDocument(_documentCaption, tmpFile);
exportInformation.ExportMade = true; exportInformation.ExportMade = true;
} catch (Exception) { }
try { catch (Exception)
{
try
{
_wordExporter.InsertIntoExistingDocument(_documentCaption, tmpFile); _wordExporter.InsertIntoExistingDocument(_documentCaption, tmpFile);
exportInformation.ExportMade = true; exportInformation.ExportMade = true;
} catch (Exception ex) { }
catch (Exception ex)
{
Log.Error(ex); Log.Error(ex);
// TODO: Change to general logic in ProcessExport // TODO: Change to general logic in ProcessExport
surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetFormattedString("destination_exportfailed", Description)); surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetFormattedString("destination_exportfailed", Description));
} }
} }
} else { }
if (!manuallyInitiated) { else
{
if (!manuallyInitiated)
{
var documents = _wordExporter.GetWordDocuments().ToList(); var documents = _wordExporter.GetWordDocuments().ToList();
if (documents != null && documents.Count > 0) { if (documents != null && documents.Count > 0)
{
var destinations = new List<IDestination> var destinations = new List<IDestination>
{ {
new WordDestination() new WordDestination()
}; };
foreach (string document in documents) { foreach (string document in documents)
{
destinations.Add(new WordDestination(document)); destinations.Add(new WordDestination(document));
} }
// Return the ExportInformation from the picker without processing, as this indirectly comes from us self // Return the ExportInformation from the picker without processing, as this indirectly comes from us self
return ShowPickerMenu(false, surface, captureDetails, destinations); return ShowPickerMenu(false, surface, captureDetails, destinations);
} }
} }
try {
try
{
_wordExporter.InsertIntoNewDocument(tmpFile, null, null); _wordExporter.InsertIntoNewDocument(tmpFile, null, null);
exportInformation.ExportMade = true; exportInformation.ExportMade = true;
} catch(Exception) { }
catch (Exception)
{
// Retry once, just in case // Retry once, just in case
try { try
{
_wordExporter.InsertIntoNewDocument(tmpFile, null, null); _wordExporter.InsertIntoNewDocument(tmpFile, null, null);
exportInformation.ExportMade = true; exportInformation.ExportMade = true;
} catch (Exception ex) { }
catch (Exception ex)
{
Log.Error(ex); Log.Error(ex);
// TODO: Change to general logic in ProcessExport // TODO: Change to general logic in ProcessExport
surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetFormattedString("destination_exportfailed", Description)); surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetFormattedString("destination_exportfailed", Description));
} }
} }
} }
ProcessExport(exportInformation, surface); ProcessExport(exportInformation, surface);
return exportInformation; return exportInformation;
} }

View file

@ -23,32 +23,40 @@ using Greenshot.Plugin.Office.OfficeInterop;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
using Microsoft.Office.Interop.PowerPoint; using Microsoft.Office.Interop.PowerPoint;
namespace Greenshot.Plugin.Office { namespace Greenshot.Plugin.Office
{
/// <summary> /// <summary>
/// Description of CoreConfiguration. /// Description of CoreConfiguration.
/// </summary> /// </summary>
[IniSection("Office", Description = "Greenshot Office configuration")] [IniSection("Office", Description = "Greenshot Office configuration")]
public class OfficeConfiguration : IniSection { public class OfficeConfiguration : IniSection
{
[IniProperty("OutlookEmailFormat", Description = "Default type for emails. (Text, HTML)", DefaultValue = "HTML")] [IniProperty("OutlookEmailFormat", Description = "Default type for emails. (Text, HTML)", DefaultValue = "HTML")]
public EmailFormat OutlookEmailFormat { get; set; } public EmailFormat OutlookEmailFormat { get; set; }
[IniProperty("EmailSubjectPattern", Description = "Email subject pattern, works like the OutputFileFilenamePattern", DefaultValue = "${title}")] [IniProperty("EmailSubjectPattern", Description = "Email subject pattern, works like the OutputFileFilenamePattern", DefaultValue = "${title}")]
public string EmailSubjectPattern { get; set; } public string EmailSubjectPattern { get; set; }
[IniProperty("EmailTo", Description = "Default value for the to in emails that are created", DefaultValue = "")] [IniProperty("EmailTo", Description = "Default value for the to in emails that are created", DefaultValue = "")]
public string EmailTo { get; set; } public string EmailTo { get; set; }
[IniProperty("EmailCC", Description = "Default value for the CC in emails that are created", DefaultValue = "")] [IniProperty("EmailCC", Description = "Default value for the CC in emails that are created", DefaultValue = "")]
public string EmailCC { get; set; } public string EmailCC { get; set; }
[IniProperty("EmailBCC", Description = "Default value for the BCC in emails that are created", DefaultValue = "")] [IniProperty("EmailBCC", Description = "Default value for the BCC in emails that are created", DefaultValue = "")]
public string EmailBCC { get; set; } public string EmailBCC { get; set; }
[IniProperty("OutlookAllowExportInMeetings", Description = "For Outlook: Allow export in meeting items", DefaultValue = "False")] [IniProperty("OutlookAllowExportInMeetings", Description = "For Outlook: Allow export in meeting items", DefaultValue = "False")]
public bool OutlookAllowExportInMeetings { get; set; } public bool OutlookAllowExportInMeetings { get; set; }
[IniProperty("WordLockAspectRatio", Description = "For Word: Lock the aspect ratio of the image", DefaultValue = "True")] [IniProperty("WordLockAspectRatio", Description = "For Word: Lock the aspect ratio of the image", DefaultValue = "True")]
public bool WordLockAspectRatio { get; set; } public bool WordLockAspectRatio { get; set; }
[IniProperty("PowerpointLockAspectRatio", Description = "For Powerpoint: Lock the aspect ratio of the image", DefaultValue = "True")] [IniProperty("PowerpointLockAspectRatio", Description = "For Powerpoint: Lock the aspect ratio of the image", DefaultValue = "True")]
public bool PowerpointLockAspectRatio { get; set; } public bool PowerpointLockAspectRatio { get; set; }
[IniProperty("PowerpointSlideLayout", Description = "For Powerpoint: Slide layout, changing this to a wrong value will fallback on ppLayoutBlank!!", DefaultValue = "ppLayoutPictureWithCaption")]
public PpSlideLayout PowerpointSlideLayout { get; set; }
[IniProperty("PowerpointSlideLayout", Description = "For Powerpoint: Slide layout, changing this to a wrong value will fallback on ppLayoutBlank!!",
DefaultValue = "ppLayoutPictureWithCaption")]
public PpSlideLayout PowerpointSlideLayout { get; set; }
} }
} }

View file

@ -34,6 +34,7 @@ namespace Greenshot.Plugin.Office.OfficeExport.Entities
{ {
return string.Format("{0} / {1}", Parent.Name, Name); return string.Format("{0} / {1}", Parent.Name, Name);
} }
return string.Format("{0} / {1} / {2}", Parent.Parent.Name, Parent.Name, Name); return string.Format("{0} / {1} / {2}", Parent.Parent.Name, Parent.Name, Name);
} }
} }

View file

@ -53,10 +53,12 @@ namespace Greenshot.Plugin.Office.OfficeExport
// Ignore, probably no excel running // Ignore, probably no excel running
return null; return null;
} }
if (excelApplication?.ComObject != null) if (excelApplication?.ComObject != null)
{ {
InitializeVariables(excelApplication); InitializeVariables(excelApplication);
} }
return excelApplication; return excelApplication;
} }
@ -71,6 +73,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
excelApplication = DisposableCom.Create(new Application()); excelApplication = DisposableCom.Create(new Application());
} }
InitializeVariables(excelApplication); InitializeVariables(excelApplication);
return excelApplication; return excelApplication;
} }
@ -108,6 +111,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
return; return;
} }
if (!Version.TryParse(excelApplication.ComObject.Version, out _excelVersion)) if (!Version.TryParse(excelApplication.ComObject.Version, out _excelVersion))
{ {
LOG.Warn("Assuming Excel version 1997."); LOG.Warn("Assuming Excel version 1997.");
@ -195,5 +199,4 @@ namespace Greenshot.Plugin.Office.OfficeExport
InsertIntoExistingWorkbook(workbook, tmpFile, imageSize); InsertIntoExistingWorkbook(workbook, tmpFile, imageSize);
} }
} }
} }

View file

@ -38,7 +38,10 @@ namespace Greenshot.Plugin.Office.OfficeExport
public class OneNoteExporter public class OneNoteExporter
{ {
private const string XmlImageContent = "<one:Image format=\"png\"><one:Size width=\"{1}.0\" height=\"{2}.0\" isSetByUser=\"true\" /><one:Data>{0}</one:Data></one:Image>"; private const string XmlImageContent = "<one:Image format=\"png\"><one:Size width=\"{1}.0\" height=\"{2}.0\" isSetByUser=\"true\" /><one:Data>{0}</one:Data></one:Image>";
private const string XmlOutline = "<?xml version=\"1.0\"?><one:Page xmlns:one=\"{2}\" ID=\"{1}\"><one:Title><one:OE><one:T><![CDATA[{3}]]></one:T></one:OE></one:Title>{0}</one:Page>";
private const string XmlOutline =
"<?xml version=\"1.0\"?><one:Page xmlns:one=\"{2}\" ID=\"{1}\"><one:Title><one:OE><one:T><![CDATA[{3}]]></one:T></one:OE></one:Title>{0}</one:Page>";
private const string OnenoteNamespace2010 = "http://schemas.microsoft.com/office/onenote/2010/onenote"; private const string OnenoteNamespace2010 = "http://schemas.microsoft.com/office/onenote/2010/onenote";
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OneNoteExporter)); private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OneNoteExporter));
@ -107,6 +110,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
LOG.Warn("Unable to navigate to the target page", ex); LOG.Warn("Unable to navigate to the target page", ex);
} }
return true; return true;
} }
@ -126,6 +130,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
// Ignore, probably no OneNote running // Ignore, probably no OneNote running
return null; return null;
} }
return oneNoteApplication; return oneNoteApplication;
} }
@ -140,6 +145,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
oneNoteApplication = DisposableCom.Create(new Application()); oneNoteApplication = DisposableCom.Create(new Application());
} }
return oneNoteApplication; return oneNoteApplication;
} }
@ -183,6 +189,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
}; };
} }
} }
if ("one:Section".Equals(xmlReader.Name)) if ("one:Section".Equals(xmlReader.Name))
{ {
string id = xmlReader.GetAttribute("ID"); string id = xmlReader.GetAttribute("ID");
@ -196,6 +203,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
}; };
} }
} }
if ("one:Page".Equals(xmlReader.Name)) if ("one:Page".Equals(xmlReader.Name))
{ {
// Skip deleted items // Skip deleted items
@ -214,6 +222,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
continue; continue;
} }
page.IsCurrentlyViewed = "true".Equals(xmlReader.GetAttribute("isCurrentlyViewed")); page.IsCurrentlyViewed = "true".Equals(xmlReader.GetAttribute("isCurrentlyViewed"));
pages.Add(page); pages.Add(page);
} }
@ -233,20 +242,24 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
if (cEx.ErrorCode == unchecked((int) 0x8002801D)) if (cEx.ErrorCode == unchecked((int) 0x8002801D))
{ {
LOG.Warn("Wrong registry keys, to solve this remove the OneNote key as described here: http://microsoftmercenary.com/wp/outlook-excel-interop-calls-breaking-solved/"); LOG.Warn(
"Wrong registry keys, to solve this remove the OneNote key as described here: http://microsoftmercenary.com/wp/outlook-excel-interop-calls-breaking-solved/");
} }
LOG.Warn("Problem retrieving onenote destinations, ignoring: ", cEx); LOG.Warn("Problem retrieving onenote destinations, ignoring: ", cEx);
} }
catch (Exception ex) catch (Exception ex)
{ {
LOG.Warn("Problem retrieving onenote destinations, ignoring: ", ex); LOG.Warn("Problem retrieving onenote destinations, ignoring: ", ex);
} }
pages.Sort((page1, page2) => pages.Sort((page1, page2) =>
{ {
if (page1.IsCurrentlyViewed || page2.IsCurrentlyViewed) if (page1.IsCurrentlyViewed || page2.IsCurrentlyViewed)
{ {
return page2.IsCurrentlyViewed.CompareTo(page1.IsCurrentlyViewed); return page2.IsCurrentlyViewed.CompareTo(page1.IsCurrentlyViewed);
} }
return string.Compare(page1.DisplayName, page2.DisplayName, StringComparison.Ordinal); return string.Compare(page1.DisplayName, page2.DisplayName, StringComparison.Ordinal);
}); });
return pages; return pages;
@ -264,6 +277,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
return null; return null;
} }
// ReSharper disable once RedundantAssignment // ReSharper disable once RedundantAssignment
string unfiledNotesPath = ""; string unfiledNotesPath = "";
oneNoteApplication.ComObject.GetSpecialLocation(specialLocation, out unfiledNotesPath); oneNoteApplication.ComObject.GetSpecialLocation(specialLocation, out unfiledNotesPath);
@ -285,6 +299,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
continue; continue;
} }
string id = xmlReader.GetAttribute("ID"); string id = xmlReader.GetAttribute("ID");
string path = xmlReader.GetAttribute("path"); string path = xmlReader.GetAttribute("path");
if (unfiledNotesPath.Equals(path)) if (unfiledNotesPath.Equals(path))
@ -301,6 +316,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
} }
} }
} }
return null; return null;
} }
} }

View file

@ -47,7 +47,9 @@ namespace Greenshot.Plugin.Office.OfficeExport
private const string ProfilesKey = @"Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\"; private const string ProfilesKey = @"Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\";
private const string AccountKey = "9375CFF0413111d3B88A00104B2A6676"; private const string AccountKey = "9375CFF0413111d3B88A00104B2A6676";
private const string NewSignatureValue = "New Signature"; private const string NewSignatureValue = "New Signature";
private const string DefaultProfileValue = "DefaultProfile"; private const string DefaultProfileValue = "DefaultProfile";
// Schema definitions for the MAPI properties, see: http://msdn.microsoft.com/en-us/library/aa454438.aspx and: http://msdn.microsoft.com/en-us/library/bb446117.aspx // Schema definitions for the MAPI properties, see: http://msdn.microsoft.com/en-us/library/aa454438.aspx and: http://msdn.microsoft.com/en-us/library/bb446117.aspx
private const string AttachmentContentId = @"http://schemas.microsoft.com/mapi/proptag/0x3712001E"; private const string AttachmentContentId = @"http://schemas.microsoft.com/mapi/proptag/0x3712001E";
@ -90,6 +92,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
return ExportToInspector(null, activeExplorer, mailItem.Class, mailItem, tmpFile, attachmentName); return ExportToInspector(null, activeExplorer, mailItem.Class, mailItem, tmpFile, attachmentName);
} }
break; break;
case AppointmentItem appointmentItem: case AppointmentItem appointmentItem:
if ((_outlookVersion.Major >= (int) OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings) if ((_outlookVersion.Major >= (int) OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings)
@ -99,6 +102,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
return ExportToInspector(null, activeExplorer, appointmentItem.Class, null, tmpFile, attachmentName); return ExportToInspector(null, activeExplorer, appointmentItem.Class, null, tmpFile, attachmentName);
} }
} }
break; break;
} }
} }
@ -110,6 +114,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
return false; return false;
} }
LOG.DebugFormat("Got {0} inspectors to check", inspectors.ComObject.Count); LOG.DebugFormat("Got {0} inspectors to check", inspectors.ComObject.Count);
for (int i = 1; i <= inspectors.ComObject.Count; i++) for (int i = 1; i <= inspectors.ComObject.Count; i++)
{ {
@ -130,6 +135,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
continue; continue;
} }
try try
{ {
return ExportToInspector(inspector, null, mailItem.Class, mailItem, tmpFile, attachmentName); return ExportToInspector(inspector, null, mailItem.Class, mailItem, tmpFile, attachmentName);
@ -138,6 +144,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
LOG.Error($"Export to {currentCaption} failed.", exExport); LOG.Error($"Export to {currentCaption} failed.", exExport);
} }
break; break;
case AppointmentItem appointmentItem: case AppointmentItem appointmentItem:
if ((_outlookVersion.Major >= (int) OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings) if ((_outlookVersion.Major >= (int) OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings)
@ -153,6 +160,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
// skip, can't export to olAppointment // skip, can't export to olAppointment
continue; continue;
} }
try try
{ {
return ExportToInspector(inspector, null, appointmentItem.Class, null, tmpFile, attachmentName); return ExportToInspector(inspector, null, appointmentItem.Class, null, tmpFile, attachmentName);
@ -161,6 +169,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
LOG.Error($"Export to {currentCaption} failed.", exExport); LOG.Error($"Export to {currentCaption} failed.", exExport);
} }
break; break;
default: default:
continue; continue;
@ -168,6 +177,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
} }
} }
} }
return false; return false;
} }
@ -181,7 +191,8 @@ namespace Greenshot.Plugin.Office.OfficeExport
/// <param name="explorer"></param> /// <param name="explorer"></param>
/// <param name="itemClass"></param> /// <param name="itemClass"></param>
/// <returns></returns> /// <returns></returns>
private bool ExportToInspector(IDisposableCom<_Inspector> inspector, IDisposableCom<_Explorer> explorer, OlObjectClass itemClass, MailItem mailItem, string tmpFile, string attachmentName) private bool ExportToInspector(IDisposableCom<_Inspector> inspector, IDisposableCom<_Explorer> explorer, OlObjectClass itemClass, MailItem mailItem, string tmpFile,
string attachmentName)
{ {
bool isMail = OlObjectClass.olMail.Equals(itemClass); bool isMail = OlObjectClass.olMail.Equals(itemClass);
bool isAppointment = OlObjectClass.olAppointment.Equals(itemClass); bool isAppointment = OlObjectClass.olAppointment.Equals(itemClass);
@ -190,6 +201,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
LOG.Warn("Item is no mail or appointment."); LOG.Warn("Item is no mail or appointment.");
return false; return false;
} }
try try
{ {
// Make sure the inspector is activated, only this way the word editor is active! // Make sure the inspector is activated, only this way the word editor is active!
@ -200,6 +212,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
isTextFormat = OlBodyFormat.olFormatPlain.Equals(mailItem.BodyFormat); isTextFormat = OlBodyFormat.olFormatPlain.Equals(mailItem.BodyFormat);
} }
if (isAppointment || !isTextFormat) if (isAppointment || !isTextFormat)
{ {
// Check for wordmail, if so use the wordexporter // Check for wordmail, if so use the wordexporter
@ -219,6 +232,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
wordDocument = DisposableCom.Create(tmpWordDocument); wordDocument = DisposableCom.Create(tmpWordDocument);
} }
} }
if (wordDocument != null) if (wordDocument != null)
{ {
using (wordDocument) using (wordDocument)
@ -248,6 +262,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
LOG.Info("Trying export for outlook < 2007."); LOG.Info("Trying export for outlook < 2007.");
} }
} }
// Only use mailitem as it should be filled!! // Only use mailitem as it should be filled!!
if (mailItem != null) if (mailItem != null)
{ {
@ -341,9 +356,11 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
caption = explorer.ComObject.Caption; caption = explorer.ComObject.Caption;
} }
LOG.Warn($"Problem while trying to add attachment to Item '{caption}'", ex); LOG.Warn($"Problem while trying to add attachment to Item '{caption}'", ex);
return false; return false;
} }
try try
{ {
if (inspector != null) if (inspector != null)
@ -360,6 +377,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
LOG.Warn("Problem activating inspector/explorer: ", ex); LOG.Warn("Problem activating inspector/explorer: ", ex);
return false; return false;
} }
LOG.Debug("Finished!"); LOG.Debug("Finished!");
return true; return true;
} }
@ -376,27 +394,32 @@ namespace Greenshot.Plugin.Office.OfficeExport
/// <param name="cc"></param> /// <param name="cc"></param>
/// <param name="bcc"></param> /// <param name="bcc"></param>
/// <param name="url"></param> /// <param name="url"></param>
private void ExportToNewEmail(IDisposableCom<Application> outlookApplication, EmailFormat format, string tmpFile, string subject, string attachmentName, string to, string cc, string bcc, string url) private void ExportToNewEmail(IDisposableCom<Application> outlookApplication, EmailFormat format, string tmpFile, string subject, string attachmentName, string to,
string cc, string bcc, string url)
{ {
using var newItem = DisposableCom.Create((MailItem) outlookApplication.ComObject.CreateItem(OlItemType.olMailItem)); using var newItem = DisposableCom.Create((MailItem) outlookApplication.ComObject.CreateItem(OlItemType.olMailItem));
if (newItem == null) if (newItem == null)
{ {
return; return;
} }
var newMail = newItem.ComObject; var newMail = newItem.ComObject;
newMail.Subject = subject; newMail.Subject = subject;
if (!string.IsNullOrEmpty(to)) if (!string.IsNullOrEmpty(to))
{ {
newMail.To = to; newMail.To = to;
} }
if (!string.IsNullOrEmpty(cc)) if (!string.IsNullOrEmpty(cc))
{ {
newMail.CC = cc; newMail.CC = cc;
} }
if (!string.IsNullOrEmpty(bcc)) if (!string.IsNullOrEmpty(bcc))
{ {
newMail.BCC = bcc; newMail.BCC = bcc;
} }
newMail.BodyFormat = OlBodyFormat.olFormatHTML; newMail.BodyFormat = OlBodyFormat.olFormatHTML;
string bodyString = null; string bodyString = null;
// Read the default signature, if nothing found use empty email // Read the default signature, if nothing found use empty email
@ -408,6 +431,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
LOG.Error("Problem reading signature!", e); LOG.Error("Problem reading signature!", e);
} }
switch (format) switch (format)
{ {
case EmailFormat.Text: case EmailFormat.Text:
@ -421,9 +445,11 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
bodyString = ""; bodyString = "";
} }
newMail.Body = bodyString; newMail.Body = bodyString;
} }
} }
break; break;
default: default:
string contentId = Path.GetFileName(tmpFile); string contentId = Path.GetFileName(tmpFile);
@ -456,6 +482,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
href = $"<A HREF=\"{url}\">"; href = $"<A HREF=\"{url}\">";
hrefEnd = "</A>"; hrefEnd = "</A>";
} }
string htmlImgEmbedded = $"<BR/>{href}<IMG border=0 hspace=0 alt=\"{attachmentName}\" align=baseline src=\"cid:{contentId}\">{hrefEnd}<BR/>"; string htmlImgEmbedded = $"<BR/>{href}<IMG border=0 hspace=0 alt=\"{attachmentName}\" align=baseline src=\"cid:{contentId}\">{hrefEnd}<BR/>";
string fallbackBody = $"<HTML><BODY>{htmlImgEmbedded}</BODY></HTML>"; string fallbackBody = $"<HTML><BODY>{htmlImgEmbedded}</BODY></HTML>";
if (bodyString == null) if (bodyString == null)
@ -482,9 +509,11 @@ namespace Greenshot.Plugin.Office.OfficeExport
bodyString = fallbackBody; bodyString = fallbackBody;
} }
} }
newMail.HTMLBody = bodyString; newMail.HTMLBody = bodyString;
break; break;
} }
// So not save, otherwise the email is always stored in Draft folder.. (newMail.Save();) // So not save, otherwise the email is always stored in Draft folder.. (newMail.Save();)
newMail.Display(false); newMail.Display(false);
@ -528,12 +557,14 @@ namespace Greenshot.Plugin.Office.OfficeExport
exported = true; exported = true;
} }
} }
return exported; return exported;
} }
catch (Exception e) catch (Exception e)
{ {
LOG.Error("Error while creating an outlook mail item: ", e); LOG.Error("Error while creating an outlook mail item: ", e);
} }
return exported; return exported;
} }
@ -548,6 +579,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
outlookApplication = DisposableCom.Create(new Application()); outlookApplication = DisposableCom.Create(new Application());
} }
InitializeVariables(outlookApplication); InitializeVariables(outlookApplication);
return outlookApplication; return outlookApplication;
} }
@ -568,10 +600,12 @@ namespace Greenshot.Plugin.Office.OfficeExport
// Ignore, probably no outlook running // Ignore, probably no outlook running
return null; return null;
} }
if ((outlookApplication != null) && (outlookApplication.ComObject != null)) if ((outlookApplication != null) && (outlookApplication.ComObject != null))
{ {
InitializeVariables(outlookApplication); InitializeVariables(outlookApplication);
} }
return outlookApplication; return outlookApplication;
} }
@ -587,6 +621,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
return null; return null;
} }
string defaultProfile = (string) profilesKey.GetValue(DefaultProfileValue); string defaultProfile = (string) profilesKey.GetValue(DefaultProfileValue);
LOG.DebugFormat("defaultProfile={0}", defaultProfile); LOG.DebugFormat("defaultProfile={0}", defaultProfile);
using var profileKey = profilesKey.OpenSubKey(defaultProfile + @"\" + AccountKey, false); using var profileKey = profilesKey.OpenSubKey(defaultProfile + @"\" + AccountKey, false);
@ -604,6 +639,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
continue; continue;
} }
string signatureName = ""; string signatureName = "";
foreach (byte b in val) foreach (byte b in val)
{ {
@ -612,6 +648,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
signatureName += (char) b; signatureName += (char) b;
} }
} }
LOG.DebugFormat("Found email signature: {0}", signatureName); LOG.DebugFormat("Found email signature: {0}", signatureName);
var extension = format switch var extension = format switch
{ {
@ -628,6 +665,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
} }
} }
} }
return null; return null;
} }
@ -642,11 +680,13 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
return; return;
} }
if (!Version.TryParse(outlookApplication.ComObject.Version, out _outlookVersion)) if (!Version.TryParse(outlookApplication.ComObject.Version, out _outlookVersion))
{ {
LOG.Warn("Assuming outlook version 1997."); LOG.Warn("Assuming outlook version 1997.");
_outlookVersion = new Version((int) OfficeVersions.Office97, 0, 0, 0); _outlookVersion = new Version((int) OfficeVersions.Office97, 0, 0, 0);
} }
// Preventing retrieval of currentUser if Outlook is older than 2007 // Preventing retrieval of currentUser if Outlook is older than 2007
if (_outlookVersion.Major >= (int) OfficeVersions.Office2007) if (_outlookVersion.Major >= (int) OfficeVersions.Office2007)
{ {
@ -657,6 +697,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
using var currentUser = DisposableCom.Create(mapiNamespace.ComObject.CurrentUser); using var currentUser = DisposableCom.Create(mapiNamespace.ComObject.CurrentUser);
_currentUser = currentUser.ComObject.Name; _currentUser = currentUser.ComObject.Name;
} }
LOG.InfoFormat("Current user: {0}", _currentUser); LOG.InfoFormat("Current user: {0}", _currentUser);
} }
catch (Exception exNs) catch (Exception exNs)
@ -701,6 +742,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
inspectorCaptions.Add(caption, mailItem.Class); inspectorCaptions.Add(caption, mailItem.Class);
} }
break; break;
case AppointmentItem appointmentItem: case AppointmentItem appointmentItem:
if ((_outlookVersion.Major >= (int) OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings) if ((_outlookVersion.Major >= (int) OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings)
@ -710,6 +752,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
inspectorCaptions.Add(caption, appointmentItem.Class); inspectorCaptions.Add(caption, appointmentItem.Class);
} }
} }
break; break;
} }
} }
@ -740,6 +783,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
continue; continue;
} }
inspectorCaptions.Add(caption, mailItem.Class); inspectorCaptions.Add(caption, mailItem.Class);
break; break;
case AppointmentItem appointmentItem: case AppointmentItem appointmentItem:
@ -756,6 +800,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
// skip, can't export to olAppointment // skip, can't export to olAppointment
continue; continue;
} }
inspectorCaptions.Add(caption, appointmentItem.Class); inspectorCaptions.Add(caption, appointmentItem.Class);
break; break;
default: default:
@ -769,6 +814,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
LOG.Warn("Problem retrieving word destinations, ignoring: ", ex); LOG.Warn("Problem retrieving word destinations, ignoring: ", ex);
} }
return inspectorCaptions; return inspectorCaptions;
} }
} }

View file

@ -60,6 +60,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
left = pageSetup.ComObject.SlideWidth / 2 - imageSize.Width / 2f; left = pageSetup.ComObject.SlideWidth / 2 - imageSize.Width / 2f;
top = pageSetup.ComObject.SlideHeight / 2 - imageSize.Height / 2f; top = pageSetup.ComObject.SlideHeight / 2 - imageSize.Height / 2f;
} }
float width = imageSize.Width; float width = imageSize.Width;
float height = imageSize.Height; float height = imageSize.Height;
IDisposableCom<Shape> shapeForCaption = null; IDisposableCom<Shape> shapeForCaption = null;
@ -86,6 +87,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
shapeForLocation.ComObject.Left = left; shapeForLocation.ComObject.Left = left;
} }
shapeForLocation.ComObject.Width = imageSize.Width; shapeForLocation.ComObject.Width = imageSize.Width;
if (height > shapeForLocation.ComObject.Height) if (height > shapeForLocation.ComObject.Height)
@ -98,6 +100,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
top = shapeForLocation.ComObject.Top + shapeForLocation.ComObject.Height / 2 - imageSize.Height / 2f; top = shapeForLocation.ComObject.Top + shapeForLocation.ComObject.Height / 2 - imageSize.Height / 2f;
} }
shapeForLocation.ComObject.Height = imageSize.Height; shapeForLocation.ComObject.Height = imageSize.Height;
} }
catch (Exception e) catch (Exception e)
@ -106,6 +109,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
using var slides = DisposableCom.Create(presentation.ComObject.Slides); using var slides = DisposableCom.Create(presentation.ComObject.Slides);
slide = DisposableCom.Create(slides.ComObject.Add(slides.ComObject.Count + 1, PpSlideLayout.ppLayoutBlank)); slide = DisposableCom.Create(slides.ComObject.Add(slides.ComObject.Count + 1, PpSlideLayout.ppLayoutBlank));
} }
using (var shapes = DisposableCom.Create(slide.ComObject.Shapes)) using (var shapes = DisposableCom.Create(slide.ComObject.Shapes))
{ {
using var shape = DisposableCom.Create(shapes.ComObject.AddPicture(tmpFile, MsoTriState.msoFalse, MsoTriState.msoTrue, 0, 0, width, height)); using var shape = DisposableCom.Create(shapes.ComObject.AddPicture(tmpFile, MsoTriState.msoFalse, MsoTriState.msoTrue, 0, 0, width, height));
@ -117,20 +121,24 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
shape.ComObject.LockAspectRatio = MsoTriState.msoFalse; shape.ComObject.LockAspectRatio = MsoTriState.msoFalse;
} }
shape.ComObject.ScaleHeight(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromMiddle); shape.ComObject.ScaleHeight(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromMiddle);
shape.ComObject.ScaleWidth(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromMiddle); shape.ComObject.ScaleWidth(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromMiddle);
if (hasScaledWidth) if (hasScaledWidth)
{ {
shape.ComObject.Width = width; shape.ComObject.Width = width;
} }
if (hasScaledHeight) if (hasScaledHeight)
{ {
shape.ComObject.Height = height; shape.ComObject.Height = height;
} }
shape.ComObject.Left = left; shape.ComObject.Left = left;
shape.ComObject.Top = top; shape.ComObject.Top = top;
shape.ComObject.AlternativeText = title; shape.ComObject.AlternativeText = title;
} }
if (shapeForCaption != null) if (shapeForCaption != null)
{ {
try try
@ -148,6 +156,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
LOG.Warn("Problem setting the title to a text-range", ex); LOG.Warn("Problem setting the title to a text-range", ex);
} }
} }
// Activate/Goto the slide // Activate/Goto the slide
try try
{ {
@ -194,10 +203,12 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
continue; continue;
} }
if (!presentation.ComObject.Name.StartsWith(presentationName)) if (!presentation.ComObject.Name.StartsWith(presentationName))
{ {
continue; continue;
} }
try try
{ {
AddPictureToPresentation(presentation, tmpFile, imageSize, title); AddPictureToPresentation(presentation, tmpFile, imageSize, title);
@ -209,6 +220,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
} }
} }
} }
return false; return false;
} }
@ -223,6 +235,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
powerPointApplication = DisposableCom.Create(new Application()); powerPointApplication = DisposableCom.Create(new Application());
} }
InitializeVariables(powerPointApplication); InitializeVariables(powerPointApplication);
return powerPointApplication; return powerPointApplication;
} }
@ -243,10 +256,12 @@ namespace Greenshot.Plugin.Office.OfficeExport
// Ignore, probably no PowerPoint running // Ignore, probably no PowerPoint running
return null; return null;
} }
if (powerPointApplication?.ComObject != null) if (powerPointApplication?.ComObject != null)
{ {
InitializeVariables(powerPointApplication); InitializeVariables(powerPointApplication);
} }
return powerPointApplication; return powerPointApplication;
} }
@ -271,10 +286,12 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
continue; continue;
} }
if (presentation.ComObject.ReadOnly == MsoTriState.msoTrue) if (presentation.ComObject.ReadOnly == MsoTriState.msoTrue)
{ {
continue; continue;
} }
if (IsAfter2003()) if (IsAfter2003())
{ {
if (presentation.ComObject.Final) if (presentation.ComObject.Final)
@ -282,6 +299,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
continue; continue;
} }
} }
yield return presentation.ComObject.Name; yield return presentation.ComObject.Name;
} }
} }
@ -296,6 +314,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
return; return;
} }
if (!Version.TryParse(powerpointApplication.ComObject.Version, out _powerpointVersion)) if (!Version.TryParse(powerpointApplication.ComObject.Version, out _powerpointVersion))
{ {
LOG.Warn("Assuming Powerpoint version 1997."); LOG.Warn("Assuming Powerpoint version 1997.");
@ -332,6 +351,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
} }
} }
} }
return isPictureAdded; return isPictureAdded;
} }
@ -340,5 +360,4 @@ namespace Greenshot.Plugin.Office.OfficeExport
return _powerpointVersion.Major > (int) OfficeVersions.Office2003; return _powerpointVersion.Major > (int) OfficeVersions.Office2003;
} }
} }
} }

View file

@ -53,6 +53,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
shape.ComObject.LockAspectRatio = MsoTriState.msoTrue; shape.ComObject.LockAspectRatio = MsoTriState.msoTrue;
} }
selection.ComObject.InsertAfter("\r\n"); selection.ComObject.InsertAfter("\r\n");
selection.ComObject.MoveDown(WdUnits.wdLine, 1, Type.Missing); selection.ComObject.MoveDown(WdUnits.wdLine, 1, Type.Missing);
return shape; return shape;
@ -69,6 +70,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
wordApplication = DisposableCom.Create(new Application()); wordApplication = DisposableCom.Create(new Application());
} }
InitializeVariables(wordApplication); InitializeVariables(wordApplication);
return wordApplication; return wordApplication;
} }
@ -89,10 +91,12 @@ namespace Greenshot.Plugin.Office.OfficeExport
// Ignore, probably no word running // Ignore, probably no word running
return null; return null;
} }
if ((wordApplication != null) && (wordApplication.ComObject != null)) if ((wordApplication != null) && (wordApplication.ComObject != null))
{ {
InitializeVariables(wordApplication); InitializeVariables(wordApplication);
} }
return wordApplication; return wordApplication;
} }
@ -116,6 +120,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
continue; continue;
} }
if (IsAfter2003()) if (IsAfter2003())
{ {
if (document.ComObject.Final) if (document.ComObject.Final)
@ -139,6 +144,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
return; return;
} }
if (!Version.TryParse(wordApplication.ComObject.Version, out _wordVersion)) if (!Version.TryParse(wordApplication.ComObject.Version, out _wordVersion))
{ {
LOG.Warn("Assuming Word version 1997."); LOG.Warn("Assuming Word version 1997.");
@ -172,6 +178,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
} }
} }
} }
return false; return false;
} }
@ -184,7 +191,8 @@ namespace Greenshot.Plugin.Office.OfficeExport
/// <param name="address">string</param> /// <param name="address">string</param>
/// <param name="tooltip">string with the tooltip of the image</param> /// <param name="tooltip">string with the tooltip of the image</param>
/// <returns>bool</returns> /// <returns>bool</returns>
internal bool InsertIntoExistingDocument(IDisposableCom<Application> wordApplication, IDisposableCom<_Document> wordDocument, string tmpFile, string address, string tooltip) internal bool InsertIntoExistingDocument(IDisposableCom<Application> wordApplication, IDisposableCom<_Document> wordDocument, string tmpFile, string address,
string tooltip)
{ {
// Bug #1517: image will be inserted into that document, where the focus was last. It will not inserted into the chosen one. // Bug #1517: image will be inserted into that document, where the focus was last. It will not inserted into the chosen one.
// Solution: Make sure the selected document is active, otherwise the insert will be made in a different document! // Solution: Make sure the selected document is active, otherwise the insert will be made in a different document!
@ -204,6 +212,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
LOG.InfoFormat("No selection to insert {0} into found.", tmpFile); LOG.InfoFormat("No selection to insert {0} into found.", tmpFile);
return false; return false;
} }
// Add Picture // Add Picture
using (var shape = AddPictureToSelection(selection, tmpFile)) using (var shape = AddPictureToSelection(selection, tmpFile))
{ {
@ -214,6 +223,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
screentip = tooltip; screentip = tooltip;
} }
try try
{ {
using var hyperlinks = DisposableCom.Create(wordDocument.ComObject.Hyperlinks); using var hyperlinks = DisposableCom.Create(wordDocument.ComObject.Hyperlinks);
@ -225,6 +235,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
} }
} }
} }
try try
{ {
// When called for Outlook, the follow error is created: This object model command is not available in e-mail // When called for Outlook, the follow error is created: This object model command is not available in e-mail
@ -245,6 +256,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
LOG.WarnFormat("Couldn't set zoom to 100, error: {0}", e.Message); LOG.WarnFormat("Couldn't set zoom to 100, error: {0}", e.Message);
} }
} }
try try
{ {
wordApplication.ComObject.Activate(); wordApplication.ComObject.Activate();
@ -254,6 +266,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
LOG.Warn("Error activating word application", ex); LOG.Warn("Error activating word application", ex);
} }
try try
{ {
wordDocument.ComObject.Activate(); wordDocument.ComObject.Activate();
@ -263,6 +276,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
LOG.Warn("Error activating word document", ex); LOG.Warn("Error activating word document", ex);
} }
return true; return true;
} }
@ -279,6 +293,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
return; return;
} }
wordApplication.ComObject.Visible = true; wordApplication.ComObject.Visible = true;
wordApplication.ComObject.Activate(); wordApplication.ComObject.Activate();
// Create new Document // Create new Document
@ -299,6 +314,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
screentip = tooltip; screentip = tooltip;
} }
try try
{ {
using var hyperlinks = DisposableCom.Create(wordDocument.ComObject.Hyperlinks); using var hyperlinks = DisposableCom.Create(wordDocument.ComObject.Hyperlinks);
@ -313,6 +329,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
} }
} }
} }
try try
{ {
wordDocument.ComObject.Activate(); wordDocument.ComObject.Activate();
@ -322,6 +339,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{ {
LOG.Warn("Error activating word document", ex); LOG.Warn("Error activating word document", ex);
} }
try try
{ {
using var activeWindow = DisposableCom.Create(wordDocument.ComObject.ActiveWindow); using var activeWindow = DisposableCom.Create(wordDocument.ComObject.ActiveWindow);

View file

@ -28,6 +28,7 @@ namespace Greenshot.Plugin.Office.OfficeInterop
/// Use the plain text format /// Use the plain text format
/// </summary> /// </summary>
Text, Text,
/// <summary> /// <summary>
/// Use HTML format /// Use HTML format
/// </summary> /// </summary>

View file

@ -28,26 +28,32 @@ namespace Greenshot.Plugin.Office.OfficeInterop
/// Office 97 /// Office 97
/// </summary> /// </summary>
Office97 = 8, Office97 = 8,
/// <summary> /// <summary>
/// Office 2003 /// Office 2003
/// </summary> /// </summary>
Office2003 = 11, Office2003 = 11,
/// <summary> /// <summary>
/// Office 2007 /// Office 2007
/// </summary> /// </summary>
Office2007 = 12, Office2007 = 12,
/// <summary> /// <summary>
/// Office 2010 /// Office 2010
/// </summary> /// </summary>
Office2010 = 14, Office2010 = 14,
/// <summary> /// <summary>
/// Office 2013 /// Office 2013
/// </summary> /// </summary>
Office2013 = 15, Office2013 = 15,
/// <summary> /// <summary>
/// Office 2016 /// Office 2016
/// </summary> /// </summary>
Office2016 = 16, Office2016 = 16,
/// <summary> /// <summary>
/// Office 2019 /// Office 2019
/// </summary> /// </summary>

View file

@ -26,7 +26,8 @@ using GreenshotPlugin.Core;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin; using GreenshotPlugin.Interfaces.Plugin;
namespace Greenshot.Plugin.Office { namespace Greenshot.Plugin.Office
{
/// <summary> /// <summary>
/// This is the OfficePlugin base code /// This is the OfficePlugin base code
/// </summary> /// </summary>
@ -35,59 +36,87 @@ namespace Greenshot.Plugin.Office {
{ {
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OfficePlugin)); private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OfficePlugin));
public void Dispose() { public void Dispose()
{
Dispose(true); Dispose(true);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
protected void Dispose(bool disposing) { protected void Dispose(bool disposing)
{
// Do nothing // Do nothing
} }
private IEnumerable<IDestination> Destinations() { private IEnumerable<IDestination> Destinations()
{
IDestination destination; IDestination destination;
try { try
{
destination = new ExcelDestination(); destination = new ExcelDestination();
} catch { }
catch
{
destination = null; destination = null;
} }
if (destination != null) {
if (destination != null)
{
yield return destination; yield return destination;
} }
try { try
{
destination = new PowerpointDestination(); destination = new PowerpointDestination();
} catch { }
catch
{
destination = null; destination = null;
} }
if (destination != null) {
if (destination != null)
{
yield return destination; yield return destination;
} }
try { try
{
destination = new WordDestination(); destination = new WordDestination();
} catch { }
catch
{
destination = null; destination = null;
} }
if (destination != null) {
if (destination != null)
{
yield return destination; yield return destination;
} }
try { try
{
destination = new OutlookDestination(); destination = new OutlookDestination();
} catch { }
catch
{
destination = null; destination = null;
} }
if (destination != null) {
if (destination != null)
{
yield return destination; yield return destination;
} }
try { try
{
destination = new OneNoteDestination(); destination = new OneNoteDestination();
} catch { }
catch
{
destination = null; destination = null;
} }
if (destination != null) {
if (destination != null)
{
yield return destination; yield return destination;
} }
} }
@ -97,19 +126,22 @@ namespace Greenshot.Plugin.Office {
/// Implementation of the IGreenshotPlugin.Initialize /// Implementation of the IGreenshotPlugin.Initialize
/// </summary> /// </summary>
/// <returns>true if plugin is initialized, false if not (doesn't show)</returns> /// <returns>true if plugin is initialized, false if not (doesn't show)</returns>
public bool Initialize() { public bool Initialize()
{
SimpleServiceProvider.Current.AddService(Destinations()); SimpleServiceProvider.Current.AddService(Destinations());
return true; return true;
} }
public void Shutdown() { public void Shutdown()
{
LOG.Debug("Office Plugin shutdown."); LOG.Debug("Office Plugin shutdown.");
} }
/// <summary> /// <summary>
/// Implementation of the IPlugin.Configure /// Implementation of the IPlugin.Configure
/// </summary> /// </summary>
public void Configure() { public void Configure()
{
throw new NotImplementedException(); throw new NotImplementedException();
} }
} }

View file

@ -19,10 +19,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace Greenshot.Plugin.Photobucket.Forms { namespace Greenshot.Plugin.Photobucket.Forms
{
/// <summary> /// <summary>
/// This class is needed for design-time resolving of the language files /// This class is needed for design-time resolving of the language files
/// </summary> /// </summary>
public class PhotobucketForm : GreenshotPlugin.Controls.GreenshotForm { public class PhotobucketForm : GreenshotPlugin.Controls.GreenshotForm
{
} }
} }

View file

@ -19,11 +19,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace Greenshot.Plugin.Photobucket.Forms { namespace Greenshot.Plugin.Photobucket.Forms
{
/// <summary> /// <summary>
/// Description of PasswordRequestForm. /// Description of PasswordRequestForm.
/// </summary> /// </summary>
public partial class SettingsForm : PhotobucketForm { public partial class SettingsForm : PhotobucketForm
{
public SettingsForm() public SettingsForm()
{ {
// //

View file

@ -19,8 +19,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace Greenshot.Plugin.Photobucket { namespace Greenshot.Plugin.Photobucket
public enum LangKey { {
public enum LangKey
{
upload_menu_item, upload_menu_item,
upload_failure, upload_failure,
communication_wait, communication_wait,

View file

@ -25,26 +25,35 @@ using GreenshotPlugin.Controls;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile; using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.Photobucket { namespace Greenshot.Plugin.Photobucket
{
/// <summary> /// <summary>
/// Description of PhotobucketConfiguration. /// Description of PhotobucketConfiguration.
/// </summary> /// </summary>
[IniSection("Photobucket", Description = "Greenshot Photobucket Plugin configuration")] [IniSection("Photobucket", Description = "Greenshot Photobucket Plugin configuration")]
public class PhotobucketConfiguration : IniSection { public class PhotobucketConfiguration : IniSection
{
[IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")]
public OutputFormat UploadFormat { get; set; } public OutputFormat UploadFormat { get; set; }
[IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")]
public int UploadJpegQuality { get; set; } public int UploadJpegQuality { get; set; }
[IniProperty("UploadReduceColors", Description = "Reduce color amount of the uploaded image to 256", DefaultValue = "False")] [IniProperty("UploadReduceColors", Description = "Reduce color amount of the uploaded image to 256", DefaultValue = "False")]
public bool UploadReduceColors { get; set; } public bool UploadReduceColors { get; set; }
[IniProperty("UsePageLink", Description = "Use pagelink instead of direct link on the clipboard", DefaultValue = "False")] [IniProperty("UsePageLink", Description = "Use pagelink instead of direct link on the clipboard", DefaultValue = "False")]
public bool UsePageLink { get; set; } public bool UsePageLink { get; set; }
[IniProperty("Token", Description = "The Photobucket token", Encrypted = true, ExcludeIfNull = true)] [IniProperty("Token", Description = "The Photobucket token", Encrypted = true, ExcludeIfNull = true)]
public string Token { get; set; } public string Token { get; set; }
[IniProperty("TokenSecret", Description = "The Photobucket token secret", Encrypted = true, ExcludeIfNull = true)] [IniProperty("TokenSecret", Description = "The Photobucket token secret", Encrypted = true, ExcludeIfNull = true)]
public string TokenSecret { get; set; } public string TokenSecret { get; set; }
[IniProperty("SubDomain", Description = "The Photobucket api subdomain", Encrypted = true, ExcludeIfNull = true)] [IniProperty("SubDomain", Description = "The Photobucket api subdomain", Encrypted = true, ExcludeIfNull = true)]
public string SubDomain { get; set; } public string SubDomain { get; set; }
[IniProperty("Username", Description = "The Photobucket api username", ExcludeIfNull = true)] [IniProperty("Username", Description = "The Photobucket api username", ExcludeIfNull = true)]
public string Username { get; set; } public string Username { get; set; }
@ -52,18 +61,19 @@ namespace Greenshot.Plugin.Photobucket {
/// A form for username/password /// A form for username/password
/// </summary> /// </summary>
/// <returns>bool true if OK was pressed, false if cancel</returns> /// <returns>bool true if OK was pressed, false if cancel</returns>
public bool ShowConfigDialog() { public bool ShowConfigDialog()
{
SettingsForm settingsForm = null; SettingsForm settingsForm = null;
new PleaseWaitForm().ShowAndWait("Photobucket", Language.GetString("photobucket", LangKey.communication_wait), new PleaseWaitForm().ShowAndWait("Photobucket", Language.GetString("photobucket", LangKey.communication_wait),
delegate { delegate { settingsForm = new SettingsForm(); }
settingsForm = new SettingsForm();
}
); );
DialogResult result = settingsForm.ShowDialog(); DialogResult result = settingsForm.ShowDialog();
if (result == DialogResult.OK) { if (result == DialogResult.OK)
{
return true; return true;
} }
return false; return false;
} }
} }

View file

@ -25,11 +25,13 @@ using System.Drawing;
using GreenshotPlugin.Core; using GreenshotPlugin.Core;
using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces;
namespace Greenshot.Plugin.Photobucket { namespace Greenshot.Plugin.Photobucket
{
/// <summary> /// <summary>
/// Description of PhotobucketDestination. /// Description of PhotobucketDestination.
/// </summary> /// </summary>
public class PhotobucketDestination : AbstractDestination { public class PhotobucketDestination : AbstractDestination
{
private readonly PhotobucketPlugin _plugin; private readonly PhotobucketPlugin _plugin;
private readonly string _albumPath; private readonly string _albumPath;
@ -38,24 +40,31 @@ namespace Greenshot.Plugin.Photobucket {
/// </summary> /// </summary>
/// <param name="plugin"></param> /// <param name="plugin"></param>
/// <param name="albumPath">path to the album, null for default</param> /// <param name="albumPath">path to the album, null for default</param>
public PhotobucketDestination(PhotobucketPlugin plugin, string albumPath = null) { public PhotobucketDestination(PhotobucketPlugin plugin, string albumPath = null)
{
_plugin = plugin; _plugin = plugin;
_albumPath = albumPath; _albumPath = albumPath;
} }
public override string Designation => "Photobucket"; public override string Designation => "Photobucket";
public override string Description { public override string Description
get { {
if (_albumPath != null) { get
{
if (_albumPath != null)
{
return _albumPath; return _albumPath;
} }
return Language.GetString("photobucket", LangKey.upload_menu_item); return Language.GetString("photobucket", LangKey.upload_menu_item);
} }
} }
public override Image DisplayIcon { public override Image DisplayIcon
get { {
get
{
ComponentResourceManager resources = new ComponentResourceManager(typeof(PhotobucketPlugin)); ComponentResourceManager resources = new ComponentResourceManager(typeof(PhotobucketPlugin));
return (Image) resources.GetObject("Photobucket"); return (Image) resources.GetObject("Photobucket");
} }
@ -63,9 +72,11 @@ namespace Greenshot.Plugin.Photobucket {
public override bool IsDynamic => true; public override bool IsDynamic => true;
public override IEnumerable<IDestination> DynamicDestinations() { public override IEnumerable<IDestination> DynamicDestinations()
{
IList<string> albums = null; IList<string> albums = null;
try { try
{
albums = PhotobucketUtils.RetrievePhotobucketAlbums(); albums = PhotobucketUtils.RetrievePhotobucketAlbums();
} }
catch catch
@ -73,10 +84,13 @@ namespace Greenshot.Plugin.Photobucket {
// ignored // ignored
} }
if (albums == null || albums.Count == 0) { if (albums == null || albums.Count == 0)
{
yield break; yield break;
} }
foreach (string album in albums) {
foreach (string album in albums)
{
yield return new PhotobucketDestination(_plugin, album); yield return new PhotobucketDestination(_plugin, album);
} }
} }
@ -88,13 +102,16 @@ namespace Greenshot.Plugin.Photobucket {
/// <param name="surface"></param> /// <param name="surface"></param>
/// <param name="captureDetails"></param> /// <param name="captureDetails"></param>
/// <returns></returns> /// <returns></returns>
public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails)
{
ExportInformation exportInformation = new ExportInformation(Designation, Description); ExportInformation exportInformation = new ExportInformation(Designation, Description);
bool uploaded = _plugin.Upload(captureDetails, surface, _albumPath, out var uploadUrl); bool uploaded = _plugin.Upload(captureDetails, surface, _albumPath, out var uploadUrl);
if (uploaded) { if (uploaded)
{
exportInformation.ExportMade = true; exportInformation.ExportMade = true;
exportInformation.Uri = uploadUrl; exportInformation.Uri = uploadUrl;
} }
ProcessExport(exportInformation, surface); ProcessExport(exportInformation, surface);
return exportInformation; return exportInformation;
} }

View file

@ -27,7 +27,8 @@ namespace Greenshot.Plugin.Photobucket
/// <summary> /// <summary>
/// Description of PhotobucketInfo. /// Description of PhotobucketInfo.
/// </summary> /// </summary>
public class PhotobucketInfo { public class PhotobucketInfo
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(PhotobucketInfo)); private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(PhotobucketInfo));
public string Original { get; set; } public string Original { get; set; }
@ -41,27 +42,37 @@ namespace Greenshot.Plugin.Photobucket
/// </summary> /// </summary>
/// <param name="response">XML</param> /// <param name="response">XML</param>
/// <returns>PhotobucketInfo object</returns> /// <returns>PhotobucketInfo object</returns>
public static PhotobucketInfo FromUploadResponse(string response) { public static PhotobucketInfo FromUploadResponse(string response)
{
Log.Debug(response); Log.Debug(response);
PhotobucketInfo photobucketInfo = new PhotobucketInfo(); PhotobucketInfo photobucketInfo = new PhotobucketInfo();
try { try
{
XmlDocument doc = new XmlDocument(); XmlDocument doc = new XmlDocument();
doc.LoadXml(response); doc.LoadXml(response);
var nodes = doc.GetElementsByTagName("url"); var nodes = doc.GetElementsByTagName("url");
if(nodes.Count > 0) { if (nodes.Count > 0)
{
photobucketInfo.Original = nodes.Item(0)?.InnerText; photobucketInfo.Original = nodes.Item(0)?.InnerText;
} }
nodes = doc.GetElementsByTagName("browseurl"); nodes = doc.GetElementsByTagName("browseurl");
if(nodes.Count > 0) { if (nodes.Count > 0)
{
photobucketInfo.Page = nodes.Item(0)?.InnerText; photobucketInfo.Page = nodes.Item(0)?.InnerText;
} }
nodes = doc.GetElementsByTagName("thumb"); nodes = doc.GetElementsByTagName("thumb");
if(nodes.Count > 0) { if (nodes.Count > 0)
{
photobucketInfo.Thumbnail = nodes.Item(0)?.InnerText; photobucketInfo.Thumbnail = nodes.Item(0)?.InnerText;
} }
} catch(Exception e) { }
catch (Exception e)
{
Log.ErrorFormat("Could not parse Photobucket response due to error {0}, response was: {1}", e.Message, response); Log.ErrorFormat("Could not parse Photobucket response due to error {0}, response was: {1}", e.Message, response);
} }
return photobucketInfo; return photobucketInfo;
} }
} }

Some files were not shown because too many files have changed in this diff Show more