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.IniFile;
namespace Greenshot.Plugin.Box {
namespace Greenshot.Plugin.Box
{
/// <summary>
/// Description of ImgurConfiguration.
/// </summary>
[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")]
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")]
public bool UseSharedLink { get; set; }
[IniProperty("FolderId", Description = "Folder ID to upload to, only change if you know what you are doing!", DefaultValue = "0")]
public string FolderId { get; set; }
@ -51,30 +54,26 @@ namespace Greenshot.Plugin.Box {
/// <summary>
/// Not stored
/// </summary>
public string AccessToken {
get;
set;
}
public string AccessToken { get; set; }
/// <summary>
/// Not stored
/// </summary>
public DateTimeOffset AccessTokenExpires {
get;
set;
}
public DateTimeOffset AccessTokenExpires { get; set; }
/// <summary>
/// A form for token
/// </summary>
/// <returns>bool true if OK was pressed, false if cancel</returns>
public bool ShowConfigDialog() {
public bool ShowConfigDialog()
{
DialogResult result = new SettingsForm().ShowDialog();
if (result == DialogResult.OK) {
if (result == DialogResult.OK)
{
return true;
}
return false;
}
}
}

View file

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

View file

@ -22,39 +22,35 @@
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace Greenshot.Plugin.Box {
namespace Greenshot.Plugin.Box
{
[DataContract]
public class Authorization {
[DataMember(Name = "access_token")]
public string AccessToken { get; set; }
[DataMember(Name = "expires_in")]
public int ExpiresIn { get; set; }
[DataMember(Name = "refresh_token")]
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; }
public class Authorization
{
[DataMember(Name = "access_token")] public string AccessToken { get; set; }
[DataMember(Name = "expires_in")] public int ExpiresIn { get; set; }
[DataMember(Name = "refresh_token")] public string RefreshToken { get; set; }
[DataMember(Name = "token_type")] public string TokenType { get; set; }
}
[DataContract]
public class FileEntry {
[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; }
public class SharedLink
{
[DataMember(Name = "url")] public string Url { get; set; }
[DataMember(Name = "download_url")] public string DownloadUrl { get; set; }
}
[DataContract]
public class Upload {
[DataMember(Name = "entries")]
public List<FileEntry> Entries { get; set; }
public class FileEntry
{
[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.Plugin;
namespace Greenshot.Plugin.Box {
namespace Greenshot.Plugin.Box
{
/// <summary>
/// This is the Box base code
/// </summary>
[Plugin("Box", true)]
public class BoxPlugin : IGreenshotPlugin {
public class BoxPlugin : IGreenshotPlugin
{
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(BoxPlugin));
private static BoxConfiguration _config;
private ComponentResourceManager _resources;
private ToolStripMenuItem _itemPlugInConfig;
public void Dispose() {
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
@ -59,13 +62,14 @@ namespace Greenshot.Plugin.Box {
/// <summary>
/// Implementation of the IGreenshotPlugin.Initialize
/// </summary>
public bool Initialize() {
public bool Initialize()
{
// Register configuration (don't need the configuration itself)
_config = IniConfig.GetIniSection<BoxConfiguration>();
_resources = new ComponentResourceManager(typeof(BoxPlugin));
SimpleServiceProvider.Current.AddService<IDestination>(new BoxDestination(this));
_itemPlugInConfig = new ToolStripMenuItem {
_itemPlugInConfig = new ToolStripMenuItem
{
Image = (Image) _resources.GetObject("Box"),
Text = Language.GetString("box", LangKey.Configure)
};
@ -76,49 +80,57 @@ namespace Greenshot.Plugin.Box {
return true;
}
public void OnLanguageChanged(object sender, EventArgs e) {
if (_itemPlugInConfig != null) {
public void OnLanguageChanged(object sender, EventArgs e)
{
if (_itemPlugInConfig != null)
{
_itemPlugInConfig.Text = Language.GetString("box", LangKey.Configure);
}
}
public void Shutdown() {
public void Shutdown()
{
LOG.Debug("Box Plugin shutdown.");
}
/// <summary>
/// Implementation of the IPlugin.Configure
/// </summary>
public void Configure() {
public void Configure()
{
_config.ShowConfigDialog();
}
public void ConfigMenuClick(object sender, EventArgs eventArgs) {
public void ConfigMenuClick(object sender, EventArgs eventArgs)
{
_config.ShowConfigDialog();
}
/// <summary>
/// This will be called when the menu item in the Editor is clicked
/// </summary>
public string Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload) {
public string Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload)
{
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, false);
try {
try
{
string url = null;
string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails));
SurfaceContainer imageToUpload = new SurfaceContainer(surfaceToUpload, outputSettings, filename);
new PleaseWaitForm().ShowAndWait("Box", Language.GetString("box", LangKey.communication_wait),
delegate {
url = BoxUtils.UploadToBox(imageToUpload, captureDetails.Title, filename);
}
delegate { url = BoxUtils.UploadToBox(imageToUpload, captureDetails.Title, filename); }
);
if (url != null && _config.AfterUploadLinkToClipBoard) {
if (url != null && _config.AfterUploadLinkToClipBoard)
{
ClipboardHelper.SetClipboardData(url);
}
return url;
} catch (Exception ex) {
}
catch (Exception ex)
{
LOG.Error("Error uploading.", ex);
MessageBox.Show(Language.GetString("box", LangKey.upload_failure) + " " + ex.Message);
return null;

View file

@ -27,12 +27,13 @@ using GreenshotPlugin.Core;
using GreenshotPlugin.Core.OAuth;
using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.Box {
namespace Greenshot.Plugin.Box
{
/// <summary>
/// Description of BoxUtils.
/// </summary>
public static class BoxUtils {
public static class BoxUtils
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(BoxUtils));
private static readonly BoxConfiguration Config = IniConfig.GetIniSection<BoxConfiguration>();
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="settings">OAuth2Settings</param>
/// <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);
byte[] data = Encoding.UTF8.GetBytes(content);
using (var requestStream = webRequest.GetRequestStream()) {
using (var requestStream = webRequest.GetRequestStream())
{
requestStream.Write(data, 0, data.Length);
}
return NetworkHelper.GetResponseAsString(webRequest);
}
@ -63,8 +67,8 @@ namespace Greenshot.Plugin.Box {
/// <param name="title">Title of box upload</param>
/// <param name="filename">Filename of box upload</param>
/// <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
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
try {
try
{
var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, UploadFileUri, settings);
IDictionary<string, object> parameters = new Dictionary<string, object>
{
{ "file", image },
{ "parent_id", Config.FolderId }
{
"file", image
},
{
"parent_id", Config.FolderId
}
};
NetworkHelper.WriteMultipartFormData(webRequest, parameters);
@ -100,13 +109,17 @@ namespace Greenshot.Plugin.Box {
var upload = JsonSerializer.Deserialize<Upload>(response);
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);
var file = JsonSerializer.Deserialize<FileEntry>(filesResponse);
return file.SharedLink.Url;
}
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.
Config.RefreshToken = settings.RefreshToken;
Config.AccessToken = settings.AccessToken;
@ -116,17 +129,20 @@ namespace Greenshot.Plugin.Box {
}
}
}
/// <summary>
/// A simple helper class for the DataContractJsonSerializer
/// </summary>
internal static class JsonSerializer {
internal static class JsonSerializer
{
/// <summary>
/// Helper method to parse JSON to object
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="jsonString"></param>
/// <returns></returns>
public static T Deserialize<T>(string jsonString) {
public static T Deserialize<T>(string jsonString)
{
var deserializer = new DataContractJsonSerializer(typeof(T));
using var stream = new MemoryStream();
byte[] content = Encoding.UTF8.GetBytes(jsonString);

View file

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

View file

@ -19,12 +19,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Greenshot.Plugin.Box.Forms {
namespace Greenshot.Plugin.Box.Forms
{
/// <summary>
/// Description of PasswordRequestForm.
/// </summary>
public partial class SettingsForm : BoxForm {
public SettingsForm() {
public partial class SettingsForm : BoxForm
{
public SettingsForm()
{
//
// 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
* 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_failure,
communication_wait,

View file

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

View file

@ -23,63 +23,45 @@ using System;
using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.Confluence {
namespace Greenshot.Plugin.Confluence
{
/// <summary>
/// Description of ConfluenceConfiguration.
/// </summary>
[Serializable]
[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_POSTFIX2 = "/rpc/soap-axis/confluenceservice-v2?wsdl";
public const string DEFAULT_PREFIX = "http://";
private const string DEFAULT_URL = DEFAULT_PREFIX + "confluence";
[IniProperty("Url", Description = "Url to Confluence system, including wsdl.", DefaultValue = DEFAULT_URL)]
public string Url {
get;
set;
}
public string Url { get; set; }
[IniProperty("Timeout", Description = "Session timeout in minutes", DefaultValue = "30")]
public int Timeout {
get;
set;
}
public int Timeout { get; set; }
[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")]
public int UploadJpegQuality {
get;
set;
}
public int UploadJpegQuality { get; set; }
[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("OpenPageAfterUpload", Description = "Open the page where the picture is uploaded after upload", DefaultValue = "True")]
public bool OpenPageAfterUpload {
get;
set;
}
public bool OpenPageAfterUpload { get; set; }
[IniProperty("CopyWikiMarkupForImageToClipboard", Description = "Copy the Wikimarkup for the recently uploaded image to the Clipboard", DefaultValue = "True")]
public bool CopyWikiMarkupForImageToClipboard {
get;
set;
}
public bool CopyWikiMarkupForImageToClipboard { get; set; }
[IniProperty("SearchSpaceKey", Description = "Key of last space that was searched for")]
public string SearchSpaceKey {
get;
set;
}
public string SearchSpaceKey { get; set; }
[IniProperty("IncludePersonSpaces", Description = "Include personal spaces in the search & browse spaces list", DefaultValue = "False")]
public bool IncludePersonSpaces {
get;
set;
}
public bool IncludePersonSpaces { get; set; }
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -25,7 +25,8 @@ using System.Linq;
using System.Windows;
using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.Confluence.Forms {
namespace Greenshot.Plugin.Confluence.Forms
{
public partial class ConfluenceSearch
{
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 ConfluenceSearch(ConfluenceUpload confluenceUpload) {
public ConfluenceSearch(ConfluenceUpload confluenceUpload)
{
_confluenceUpload = confluenceUpload;
DataContext = this;
InitializeComponent();
if (ConfluenceConfig.SearchSpaceKey == null) {
if (ConfluenceConfig.SearchSpaceKey == null)
{
SpaceComboBox.SelectedItem = Spaces.FirstOrDefault();
} else {
foreach(var space in Spaces) {
if (space.Key.Equals(ConfluenceConfig.SearchSpaceKey)) {
}
else
{
foreach (var space in Spaces)
{
if (space.Key.Equals(ConfluenceConfig.SearchSpaceKey))
{
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();
}
private void SelectionChanged() {
if (PageListView.HasItems && PageListView.SelectedItems.Count > 0) {
private void SelectionChanged()
{
if (PageListView.HasItems && PageListView.SelectedItems.Count > 0)
{
_confluenceUpload.SelectedPage = (Page) PageListView.SelectedItem;
} else {
}
else
{
_confluenceUpload.SelectedPage = null;
}
}
private void Search_Click(object sender, RoutedEventArgs e) {
private void Search_Click(object sender, RoutedEventArgs e)
{
DoSearch();
}
private void DoSearch() {
private void DoSearch()
{
string spaceKey = (string) SpaceComboBox.SelectedValue;
ConfluenceConfig.SearchSpaceKey = spaceKey;
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);
}
}
private void SearchText_KeyDown(object sender, System.Windows.Input.KeyEventArgs e) {
if (e.Key == System.Windows.Input.Key.Return && Search.IsEnabled) {
private void SearchText_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.Key == System.Windows.Input.Key.Return && Search.IsEnabled)
{
DoSearch();
e.Handled = true;
}
}
private void Page_Loaded(object sender, RoutedEventArgs e) {
private void Page_Loaded(object sender, RoutedEventArgs e)
{
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);
}
}

View file

@ -27,7 +27,8 @@ using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
namespace Greenshot.Plugin.Confluence.Forms {
namespace Greenshot.Plugin.Confluence.Forms
{
/// <summary>
/// Interaction logic for ConfluenceTreePicker.xaml
/// </summary>
@ -38,28 +39,36 @@ namespace Greenshot.Plugin.Confluence.Forms {
private readonly ConfluenceUpload _confluenceUpload;
private bool _isInitDone;
public ConfluenceTreePicker(ConfluenceUpload confluenceUpload) {
public ConfluenceTreePicker(ConfluenceUpload confluenceUpload)
{
_confluenceConnector = ConfluencePlugin.ConfluenceConnector;
_confluenceUpload = confluenceUpload;
InitializeComponent();
}
private void PageTreeViewItem_DoubleClick(object sender, MouseButtonEventArgs eventArgs) {
private void PageTreeViewItem_DoubleClick(object sender, MouseButtonEventArgs eventArgs)
{
Log.Debug("spaceTreeViewItem_MouseLeftButtonDown is called!");
TreeViewItem clickedItem = eventArgs.Source as TreeViewItem;
if (clickedItem?.Tag is not Page page) {
if (clickedItem?.Tag is not Page page)
{
return;
}
if (clickedItem.HasItems)
{
return;
}
Log.Debug("Loading pages for page: " + page.Title);
new Thread(() => {
new Thread(() =>
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart) (() => { ShowBusy.Visibility = Visibility.Visible; }));
var pages = _confluenceConnector.GetPageChildren(page).OrderBy(p => p.Title);
Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)(() => {
foreach(var childPage in pages) {
Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart) (() =>
{
foreach (var childPage in pages)
{
Log.Debug("Adding page: " + childPage.Title);
var pageTreeViewItem = new TreeViewItem
{
@ -70,32 +79,46 @@ namespace Greenshot.Plugin.Confluence.Forms {
pageTreeViewItem.PreviewMouseDoubleClick += PageTreeViewItem_DoubleClick;
pageTreeViewItem.PreviewMouseLeftButtonDown += PageTreeViewItem_Click;
}
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!");
if (eventArgs.Source is not TreeViewItem clickedItem) {
if (eventArgs.Source is not TreeViewItem clickedItem)
{
return;
}
Page page = clickedItem.Tag as Page;
_confluenceUpload.SelectedPage = page;
if (page != null) {
if (page != null)
{
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;
if (_isInitDone) {
if (_isInitDone)
{
return;
}
ShowBusy.Visibility = Visibility.Visible;
new Thread(() => {
Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)(() => {
foreach (Space space in _confluenceUpload.Spaces) {
new Thread(() =>
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart) (() =>
{
foreach (Space space in _confluenceUpload.Spaces)
{
TreeViewItem spaceTreeViewItem = new TreeViewItem
{
Header = space.Name,
@ -103,7 +126,8 @@ namespace Greenshot.Plugin.Confluence.Forms {
};
// Get homepage
try {
try
{
Page page = _confluenceConnector.GetSpaceHomepage(space);
TreeViewItem pageTreeViewItem = new TreeViewItem
{
@ -114,14 +138,20 @@ namespace Greenshot.Plugin.Confluence.Forms {
pageTreeViewItem.PreviewMouseLeftButtonDown += PageTreeViewItem_Click;
spaceTreeViewItem.Items.Add(pageTreeViewItem);
ConfluenceTreeView.Items.Add(spaceTreeViewItem);
} catch (Exception ex) {
}
catch (Exception ex)
{
Log.Error("Can't get homepage for space : " + space.Name + " (" + ex.Message + ")");
}
}
ShowBusy.Visibility = Visibility.Collapsed;
_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.Windows;
namespace Greenshot.Plugin.Confluence.Forms {
namespace Greenshot.Plugin.Confluence.Forms
{
/// <summary>
/// Interaction logic for ConfluenceUpload.xaml
/// </summary>
public partial class ConfluenceUpload : Window {
public partial class ConfluenceUpload : Window
{
private System.Windows.Controls.Page _pickerPage;
public System.Windows.Controls.Page PickerPage {
get {
if (_pickerPage == null) {
public System.Windows.Controls.Page PickerPage
{
get
{
if (_pickerPage == null)
{
List<Page> pages = ConfluenceUtils.GetCurrentPages();
if (pages != null && pages.Count > 0) {
if (pages != null && pages.Count > 0)
{
_pickerPage = new ConfluencePagePicker(this, pages);
}
}
return _pickerPage;
}
}
private System.Windows.Controls.Page _searchPage;
public System.Windows.Controls.Page SearchPage {
public System.Windows.Controls.Page SearchPage
{
get { return _searchPage ??= new ConfluenceSearch(this); }
}
private System.Windows.Controls.Page _browsePage;
public System.Windows.Controls.Page BrowsePage {
public System.Windows.Controls.Page BrowsePage
{
get { return _browsePage ??= new ConfluenceTreePicker(this); }
}
private Page _selectedPage;
public Page SelectedPage {
public Page SelectedPage
{
get => _selectedPage;
set {
set
{
_selectedPage = value;
Upload.IsEnabled = _selectedPage != null;
IsOpenPageSelected = false;
}
}
public bool IsOpenPageSelected {
get;
set;
}
public string Filename {
get;
set;
}
public bool IsOpenPageSelected { get; set; }
public string Filename { get; set; }
private static DateTime _lastLoad = DateTime.Now;
private static IList<Space> _spaces;
public IList<Space> Spaces {
get {
public IList<Space> Spaces
{
get
{
UpdateSpaces();
while (_spaces == null) {
while (_spaces == null)
{
Thread.Sleep(300);
}
return _spaces;
}
}
public ConfluenceUpload(string filename) {
public ConfluenceUpload(string filename)
{
Filename = filename;
InitializeComponent();
DataContext = this;
UpdateSpaces();
if (PickerPage == null) {
if (PickerPage == null)
{
PickerTab.Visibility = Visibility.Collapsed;
SearchTab.IsSelected = true;
}
}
private void UpdateSpaces() {
if (_spaces != null && DateTime.Now.AddMinutes(-60).CompareTo(_lastLoad) > 0) {
private void UpdateSpaces()
{
if (_spaces != null && DateTime.Now.AddMinutes(-60).CompareTo(_lastLoad) > 0)
{
// Reset
_spaces = null;
}
// Check if load is needed
if (_spaces == null) {
(new Thread(() => {
if (_spaces == null)
{
(new Thread(() =>
{
_spaces = ConfluencePlugin.ConfluenceConnector.GetSpaceSummaries().OrderBy(s => s.Name).ToList();
_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;
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -25,12 +25,14 @@ using Greenshot.Plugin.Dropbox.Forms;
using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.Dropbox {
namespace Greenshot.Plugin.Dropbox
{
/// <summary>
/// Description of ImgurConfiguration.
/// </summary>
[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")]
public OutputFormat UploadFormat { get; set; }
@ -57,11 +59,14 @@ namespace Greenshot.Plugin.Dropbox {
/// A form for token
/// </summary>
/// <returns>bool true if OK was pressed, false if cancel</returns>
public bool ShowConfigDialog() {
public bool ShowConfigDialog()
{
DialogResult result = new SettingsForm().ShowDialog();
if (result == DialogResult.OK) {
if (result == DialogResult.OK)
{
return true;
}
return false;
}
}

View file

@ -29,15 +29,18 @@ using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin;
using Newtonsoft.Json;
namespace Greenshot.Plugin.Dropbox {
namespace Greenshot.Plugin.Dropbox
{
/// <summary>
/// Description of DropboxUtils.
/// </summary>
public class DropboxUtils {
public class DropboxUtils
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DropboxUtils));
private static readonly DropboxPluginConfiguration DropboxConfig = IniConfig.GetIniSection<DropboxPluginConfiguration>();
private DropboxUtils() {
private DropboxUtils()
{
}
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>
{
{ "autorename", true },
{ "mute", true },
{ "path", "/" + filename.Replace(Path.DirectorySeparatorChar, '\\')}
{
"autorename", true
},
{
"mute", true
},
{
"path", "/" + filename.Replace(Path.DirectorySeparatorChar, '\\')
}
};
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);
@ -78,10 +89,13 @@ namespace Greenshot.Plugin.Dropbox {
var response = JsonConvert.DeserializeObject<IDictionary<string, string>>(responseString);
return response.ContainsKey("id");
}
catch (Exception ex) {
catch (Exception ex)
{
Log.Error("Upload error: ", ex);
throw;
} finally {
}
finally
{
DropboxConfig.RefreshToken = oauth2Settings.RefreshToken;
DropboxConfig.AccessToken = oauth2Settings.AccessToken;
DropboxConfig.AccessTokenExpires = oauth2Settings.AccessTokenExpires;

View file

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

View file

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

View file

@ -18,8 +18,11 @@
* You should have received a copy of the GNU General Public License
* 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_failure,
communication_wait,

View file

@ -25,31 +25,42 @@ using System.IO;
using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.ExternalCommand {
namespace Greenshot.Plugin.ExternalCommand
{
/// <summary>
/// Description of FlickrConfiguration.
/// </summary>
[IniSection("ExternalCommand", Description = "Greenshot ExternalCommand Plugin configuration")]
public class ExternalCommandConfiguration : IniSection {
public class ExternalCommandConfiguration : IniSection
{
[IniProperty("Commands", Description = "The commands that are available.")]
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; }
[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; }
[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; }
[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; }
[IniProperty("OutputToClipboard", Description = "Depends on 'RedirectStandardOutput': Place the standard output on the clipboard.", DefaultValue = "false")]
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; }
[IniProperty("Commandline", Description = "The commandline for the output command.")]
@ -71,13 +82,19 @@ namespace Greenshot.Plugin.ExternalCommand {
private const string PaintDotNet = "Paint.NET";
private static readonly string PaintDotNetPath;
private static readonly bool HasPaintDotNet;
static ExternalCommandConfiguration() {
try {
static ExternalCommandConfiguration()
{
try
{
PaintPath = PluginUtils.GetExePath("pbrush.exe");
HasPaint = !string.IsNullOrEmpty(PaintPath) && File.Exists(PaintPath);
} catch {
}
catch
{
// Ignore
}
try
{
PaintDotNetPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Paint.NET\PaintDotNet.exe");
@ -99,6 +116,7 @@ namespace Greenshot.Plugin.ExternalCommand {
{
return;
}
Commands.Remove(command);
Commandline.Remove(command);
Argument.Remove(command);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -26,52 +26,64 @@ using System.Windows.Forms;
using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.ExternalCommand {
namespace Greenshot.Plugin.ExternalCommand
{
/// <summary>
/// Description of SettingsFormDetail.
/// </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 ExternalCommandConfiguration ExternalCommandConfig = IniConfig.GetIniSection<ExternalCommandConfiguration>();
private readonly string _commando;
private readonly int _commandIndex;
public SettingsFormDetail(string commando) {
public SettingsFormDetail(string commando)
{
InitializeComponent();
AcceptButton = buttonOk;
CancelButton = buttonCancel;
_commando = commando;
if(commando != null) {
if (commando != null)
{
textBox_name.Text = commando;
textBox_commandline.Text = ExternalCommandConfig.Commandline[commando];
textBox_arguments.Text = ExternalCommandConfig.Argument[commando];
_commandIndex = ExternalCommandConfig.Commands.FindIndex(s => s == commando);
} else {
}
else
{
textBox_arguments.Text = "\"{0}\"";
}
OkButtonState();
}
private void ButtonOkClick(object sender, EventArgs e) {
private void ButtonOkClick(object sender, EventArgs e)
{
string commandName = textBox_name.Text;
string commandLine = textBox_commandline.Text;
string arguments = textBox_arguments.Text;
if(_commando != null) {
if (_commando != null)
{
ExternalCommandConfig.Commands[_commandIndex] = commandName;
ExternalCommandConfig.Commandline.Remove(_commando);
ExternalCommandConfig.Commandline.Add(commandName, commandLine);
ExternalCommandConfig.Argument.Remove(_commando);
ExternalCommandConfig.Argument.Add(commandName, arguments);
} else {
}
else
{
ExternalCommandConfig.Commands.Add(commandName);
ExternalCommandConfig.Commandline.Add(commandName, commandLine);
ExternalCommandConfig.Argument.Add(commandName, arguments);
}
}
private void Button3Click(object sender, EventArgs e) {
private void Button3Click(object sender, EventArgs e)
{
var openFileDialog = new OpenFileDialog
{
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.Warn("Exception: ", ex);
}
if(initialPath != null && Directory.Exists(initialPath)) {
if (initialPath != null && Directory.Exists(initialPath))
{
openFileDialog.InitialDirectory = initialPath;
} else {
}
else
{
initialPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
openFileDialog.InitialDirectory = initialPath;
}
Log.DebugFormat("Starting OpenFileDialog at {0}", initialPath);
if(openFileDialog.ShowDialog() == DialogResult.OK) {
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
textBox_commandline.Text = openFileDialog.FileName;
}
}
private void OkButtonState() {
private void OkButtonState()
{
// Assume OK
buttonOk.Enabled = true;
textBox_name.BackColor = Color.White;
textBox_commandline.BackColor = Color.White;
textBox_arguments.BackColor = Color.White;
// Is there a text in the name field
if(string.IsNullOrEmpty(textBox_name.Text)) {
if (string.IsNullOrEmpty(textBox_name.Text))
{
buttonOk.Enabled = false;
}
// 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;
textBox_name.BackColor = Color.Red;
}
// Is there a text in the commandline field
if(string.IsNullOrEmpty(textBox_commandline.Text)) {
if (string.IsNullOrEmpty(textBox_commandline.Text))
{
buttonOk.Enabled = false;
}
@ -134,6 +158,7 @@ namespace Greenshot.Plugin.ExternalCommand {
textBox_commandline.BackColor = Color.Red;
}
}
// Are the arguments in a valid format?
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();
}
private void textBox_commandline_TextChanged(object sender, EventArgs e) {
private void textBox_commandline_TextChanged(object sender, EventArgs e)
{
OkButtonState();
}
@ -161,6 +188,5 @@ namespace Greenshot.Plugin.ExternalCommand {
{
OkButtonState();
}
}
}

View file

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

View file

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

View file

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

View file

@ -30,21 +30,27 @@ using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin;
using log4net;
namespace Greenshot.Plugin.Flickr {
namespace Greenshot.Plugin.Flickr
{
/// <summary>
/// Description of FlickrUtils.
/// </summary>
public static class FlickrUtils {
public static class FlickrUtils
{
private static readonly ILog LOG = LogManager.GetLogger(typeof(FlickrUtils));
private static readonly FlickrConfiguration config = IniConfig.GetIniSection<FlickrConfiguration>();
private const string FLICKR_API_BASE_URL = "https://api.flickr.com/services/";
private const string FLICKR_UPLOAD_URL = FLICKR_API_BASE_URL + "upload/";
// 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_AUTHORIZE_URL = FLICKR_OAUTH_BASE_URL + "authorize";
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}";
// 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";
@ -58,7 +64,8 @@ namespace Greenshot.Plugin.Flickr {
/// <param name="title"></param>
/// <param name="filename"></param>
/// <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)
{
BrowserSize = new Size(520, 800),
@ -70,70 +77,116 @@ namespace Greenshot.Plugin.Flickr {
Token = config.FlickrToken,
TokenSecret = config.FlickrTokenSecret
};
if (string.IsNullOrEmpty(oAuth.Token)) {
if (!oAuth.Authorize()) {
if (string.IsNullOrEmpty(oAuth.Token))
{
if (!oAuth.Authorize())
{
return null;
}
if (!string.IsNullOrEmpty(oAuth.Token)) {
if (!string.IsNullOrEmpty(oAuth.Token))
{
config.FlickrToken = oAuth.Token;
}
if (!string.IsNullOrEmpty(oAuth.TokenSecret)) {
if (!string.IsNullOrEmpty(oAuth.TokenSecret))
{
config.FlickrTokenSecret = oAuth.TokenSecret;
}
IniConfig.Save();
}
try {
try
{
IDictionary<string, object> signedParameters = new Dictionary<string, object>
{
{ "content_type", "2" }, // Screenshot
{ "tags", "Greenshot" },
{ "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" }
{
"content_type", "2"
}, // Screenshot
{
"tags", "Greenshot"
},
{
"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>
{
{ "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 photoId = GetPhotoId(response);
// 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);
return GetUrl(photoInfo);
} catch (Exception ex) {
}
catch (Exception ex)
{
LOG.Error("Upload error: ", ex);
throw;
} finally {
if (!string.IsNullOrEmpty(oAuth.Token)) {
}
finally
{
if (!string.IsNullOrEmpty(oAuth.Token))
{
config.FlickrToken = oAuth.Token;
}
if (!string.IsNullOrEmpty(oAuth.TokenSecret)) {
if (!string.IsNullOrEmpty(oAuth.TokenSecret))
{
config.FlickrTokenSecret = oAuth.TokenSecret;
}
}
}
private static string GetUrl(string response) {
try {
private static string GetUrl(string response)
{
try
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(response);
if (config.UsePageLink) {
if (config.UsePageLink)
{
XmlNodeList nodes = doc.GetElementsByTagName("url");
if (nodes.Count > 0) {
if (nodes.Count > 0)
{
var xmlNode = nodes.Item(0);
if (xmlNode != null) {
if (xmlNode != null)
{
return xmlNode.InnerText;
}
}
} else {
}
else
{
XmlNodeList nodes = doc.GetElementsByTagName("photo");
if (nodes.Count > 0) {
if (nodes.Count > 0)
{
var item = nodes.Item(0);
if (item?.Attributes != null) {
if (item?.Attributes != null)
{
string farmId = item.Attributes["farm"].Value;
string serverId = item.Attributes["server"].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);
}
return null;
}
private static string GetPhotoId(string response) {
try {
private static string GetPhotoId(string response)
{
try
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(response);
XmlNodeList nodes = doc.GetElementsByTagName("photoid");
if (nodes.Count > 0) {
if (nodes.Count > 0)
{
var xmlNode = nodes.Item(0);
if (xmlNode != null) {
if (xmlNode != null)
{
return xmlNode.InnerText;
}
}
} catch (Exception ex) {
}
catch (Exception ex)
{
LOG.Error("Error parsing Flickr Response.", ex);
}
return null;
}
}

View file

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

View file

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

View file

@ -18,8 +18,11 @@
* You should have received a copy of the GNU General Public License
* 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_failure,
communication_wait,

View file

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

View file

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

View file

@ -24,12 +24,14 @@ using Greenshot.Plugin.GooglePhotos.Forms;
using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.GooglePhotos {
namespace Greenshot.Plugin.GooglePhotos
{
/// <summary>
/// Description of GooglePhotosConfiguration.
/// </summary>
[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")]
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")]
public bool AfterUploadLinkToClipBoard { get; set; }
[IniProperty("AddFilename", Description = "Is the filename passed on to GooglePhotos", DefaultValue = "False")]
public bool AddFilename {
get;
set;
}
public bool AddFilename { get; set; }
[IniProperty("UploadUser", Description = "The GooglePhotos user to upload to", DefaultValue = "default")]
public string UploadUser {
get;
set;
}
public string UploadUser { get; set; }
[IniProperty("UploadAlbum", Description = "The GooglePhotos album to upload to", DefaultValue = "default")]
public string UploadAlbum {
get;
set;
}
public string UploadAlbum { get; set; }
[IniProperty("RefreshToken", Description = "GooglePhotos authorization refresh Token", Encrypted = true)]
public string RefreshToken {
get;
set;
}
public string RefreshToken { get; set; }
/// <summary>
/// Not stored
/// </summary>
public string AccessToken {
get;
set;
}
public string AccessToken { get; set; }
/// <summary>
/// Not stored
/// </summary>
public DateTimeOffset AccessTokenExpires {
get;
set;
}
public DateTimeOffset AccessTokenExpires { get; set; }
/// <summary>
/// A form for token
/// </summary>
/// <returns>bool true if OK was pressed, false if cancel</returns>
public bool ShowConfigDialog() {
public bool ShowConfigDialog()
{
DialogResult result = new SettingsForm().ShowDialog();
if (result == DialogResult.OK) {
if (result == DialogResult.OK)
{
return true;
}
return false;
}
}
}

View file

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

View file

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

View file

@ -26,15 +26,20 @@ using GreenshotPlugin.IniFile;
using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin;
namespace Greenshot.Plugin.GooglePhotos {
namespace Greenshot.Plugin.GooglePhotos
{
/// <summary>
/// Description of GooglePhotosUtils.
/// </summary>
public static class GooglePhotosUtils {
public static class GooglePhotosUtils
{
private const string GooglePhotosScope = "https://picasaweb.google.com/data/";
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(GooglePhotosUtils));
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 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="filename">string</param>
/// <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
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
try {
try
{
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));
}
SurfaceContainer container = new SurfaceContainer(surfaceToUpload, outputSettings, filename);
container.Upload(webRequest);
string response = NetworkHelper.GetResponseAsString(webRequest);
return ParseResponse(response);
} finally {
}
finally
{
// Copy the settings back to the config, so they are stored.
Config.RefreshToken = settings.RefreshToken;
Config.AccessToken = settings.AccessToken;
@ -89,31 +100,43 @@ namespace Greenshot.Plugin.GooglePhotos {
/// </summary>
/// <param name="response"></param>
/// <returns></returns>
public static string ParseResponse(string response) {
if (response == null) {
public static string ParseResponse(string response)
{
if (response == null)
{
return null;
}
try {
try
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(response);
XmlNodeList nodes = doc.GetElementsByTagName("link", "*");
if(nodes.Count > 0) {
if (nodes.Count > 0)
{
string url = null;
foreach(XmlNode node in nodes) {
if (node.Attributes != null) {
foreach (XmlNode node in nodes)
{
if (node.Attributes != null)
{
url = node.Attributes["href"].Value;
string rel = node.Attributes["rel"].Value;
// 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;
}
}
}
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);
}
return null;
}
}

View file

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

View file

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

View file

@ -27,18 +27,21 @@ using GreenshotPlugin.Controls;
using GreenshotPlugin.Core;
using GreenshotPlugin.IniFile;
namespace Greenshot.Plugin.Imgur.Forms {
namespace Greenshot.Plugin.Imgur.Forms
{
/// <summary>
/// Imgur history form
/// </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 readonly GreenshotColumnSorter _columnSorter;
private static readonly object Lock = new object();
private static readonly ImgurConfiguration Config = IniConfig.GetIniSection<ImgurConfiguration>();
private static ImgurHistory _instance;
public static void ShowHistory() {
public static void ShowHistory()
{
lock (Lock)
{
if (ImgurUtils.IsHistoryLoadingNeeded())
@ -54,15 +57,18 @@ namespace Greenshot.Plugin.Imgur.Forms {
{
_instance = new ImgurHistory();
}
if (!_instance.Visible)
{
_instance.Show();
}
_instance.Redraw();
}
}
private ImgurHistory() {
private ImgurHistory()
{
ManualLanguageApply = true;
//
// The InitializeComponent() call is required for Windows Forms designer support.
@ -76,26 +82,36 @@ namespace Greenshot.Plugin.Imgur.Forms {
_columnSorter.SortColumn = 3;
_columnSorter.Order = SortOrder.Descending;
Redraw();
if (listview_imgur_uploads.Items.Count > 0) {
if (listview_imgur_uploads.Items.Count > 0)
{
listview_imgur_uploads.Items[0].Selected = true;
}
ApplyLanguage();
if (Config.Credits > 0) {
if (Config.Credits > 0)
{
Text = Text + " (" + Config.Credits + " credits)";
}
}
private void Redraw() {
private void Redraw()
{
// Should fix Bug #3378699
pictureBox1.Image = pictureBox1.ErrorImage;
listview_imgur_uploads.BeginUpdate();
listview_imgur_uploads.Items.Clear();
listview_imgur_uploads.Columns.Clear();
string[] columns = { "hash", "title", "deleteHash", "Date"};
foreach (string column in columns) {
string[] columns =
{
"hash", "title", "deleteHash", "Date"
};
foreach (string column in columns)
{
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)
{
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));
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);
}
@ -116,17 +134,22 @@ namespace Greenshot.Plugin.Imgur.Forms {
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;
if (listview_imgur_uploads.SelectedItems.Count > 0) {
if (listview_imgur_uploads.SelectedItems.Count > 0)
{
deleteButton.Enabled = true;
openButton.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;
pictureBox1.Image = imgurInfo.Image;
}
} else {
}
else
{
pictureBox1.Image = pictureBox1.ErrorImage;
deleteButton.Enabled = false;
openButton.Enabled = false;
@ -134,48 +157,60 @@ namespace Greenshot.Plugin.Imgur.Forms {
}
}
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++) {
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++)
{
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)
{
continue;
}
// Should fix Bug #3378699
pictureBox1.Image = pictureBox1.ErrorImage;
try {
try
{
new PleaseWaitForm().ShowAndWait("Imgur", Language.GetString("imgur", LangKey.communication_wait),
delegate {
ImgurUtils.DeleteImgurImage(imgurInfo);
}
delegate { ImgurUtils.DeleteImgurImage(imgurInfo); }
);
} catch (Exception ex) {
}
catch (Exception ex)
{
Log.Warn("Problem communicating with Imgur: ", ex);
}
imgurInfo.Dispose();
}
}
Redraw();
}
private void ClipboardButtonClick(object sender, EventArgs e) {
private void ClipboardButtonClick(object sender, EventArgs e)
{
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++)
{
ImgurInfo imgurInfo = (ImgurInfo) listview_imgur_uploads.SelectedItems[i].Tag;
links.AppendLine(Config.UsePageLink ? imgurInfo.Page : imgurInfo.Original);
}
}
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);
if (result == DialogResult.Yes) {
if (result == DialogResult.Yes)
{
Config.runtimeImgurHistory.Clear();
Config.ImgurUploadHistory.Clear();
IniConfig.Save();
@ -188,21 +223,28 @@ namespace Greenshot.Plugin.Imgur.Forms {
Hide();
}
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++) {
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++)
{
ImgurInfo imgurInfo = (ImgurInfo) listview_imgur_uploads.SelectedItems[i].Tag;
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.
if (e.Column == _columnSorter.SortColumn) {
if (e.Column == _columnSorter.SortColumn)
{
// Reverse the current sort direction for this column.
_columnSorter.Order = _columnSorter.Order == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending;
} else {
}
else
{
// Set the column number that is to be sorted; default to ascending.
_columnSorter.SortColumn = e.Column;
_columnSorter.Order = SortOrder.Ascending;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -31,7 +31,6 @@ using GreenshotPlugin.Hooking;
namespace Greenshot.Plugin.Jira
{
/// <summary>
/// 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.
@ -44,7 +43,9 @@ namespace Greenshot.Plugin.Jira
private readonly WindowsTitleMonitor _monitor;
private readonly IList<IJiraClient> _jiraInstances = new List<IJiraClient>();
private readonly IDictionary<string, IJiraClient> _projectJiraClientMap = new Dictionary<string, IJiraClient>();
private readonly int _maxEntries;
// TODO: Add issues from issueHistory (JQL -> Where.IssueKey.InIssueHistory())
private IDictionary<string, JiraDetails> _recentJiras = new Dictionary<string, JiraDetails>();
@ -79,6 +80,7 @@ namespace Greenshot.Plugin.Jira
{
return;
}
// free managed resources
_monitor.TitleChangeEvent -= MonitorTitleChangeEvent;
_monitor.Dispose();
@ -143,8 +145,13 @@ namespace Greenshot.Plugin.Jira
var issue = await jiraClient.Issue.GetAsync(jiraDetails.JiraKey).ConfigureAwait(false);
jiraDetails.JiraIssue = issue;
}
// 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)
{
@ -163,11 +170,13 @@ namespace Greenshot.Plugin.Jira
{
return;
}
var jiraKeyMatch = _jiraKeyPattern.Match(windowTitle);
if (!jiraKeyMatch.Success)
{
return;
}
// Found a possible JIRA title
var jiraKey = jiraKeyMatch.Value;
var jiraKeyParts = jiraKey.Split('-');
@ -184,11 +193,16 @@ namespace Greenshot.Plugin.Jira
currentJiraDetails.SeenAt = DateTimeOffset.Now;
// 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
return;
}
// We detected an unknown JIRA, so add it to our list
currentJiraDetails = new JiraDetails
{
@ -205,6 +219,7 @@ namespace Greenshot.Plugin.Jira
orderby jiraDetails.SeenAt descending
select jiraDetails).Take(_maxEntries).ToDictionary(jd => jd.JiraKey, jd => jd);
}
// Now we can get the title from JIRA itself
// ReSharper disable once UnusedVariable
var updateTitleTask = DetectedNewJiraIssueAsync(currentJiraDetails);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -28,29 +28,37 @@ using GreenshotPlugin.Core;
using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin;
namespace Greenshot.Plugin.Office.Destinations {
namespace Greenshot.Plugin.Office.Destinations
{
/// <summary>
/// Description of PowerpointDestination.
/// </summary>
public class ExcelDestination : AbstractDestination {
public class ExcelDestination : AbstractDestination
{
private const int IconApplication = 0;
private const int IconWorkbook = 1;
private static readonly string ExePath;
private readonly string _workbookName;
static ExcelDestination() {
static ExcelDestination()
{
ExePath = PluginUtils.GetExePath("EXCEL.EXE");
if (ExePath != null && File.Exists(ExePath)) {
if (ExePath != null && File.Exists(ExePath))
{
WindowDetails.AddProcessToExcludeFromFreeze("excel");
} else {
}
else
{
ExePath = null;
}
}
public ExcelDestination() {
public ExcelDestination()
{
}
public ExcelDestination(string workbookName) {
public ExcelDestination(string 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 IEnumerable<IDestination> DynamicDestinations() {
foreach (string workbookName in ExcelExporter.GetWorkbooks()) {
public override IEnumerable<IDestination> DynamicDestinations()
{
foreach (string workbookName in ExcelExporter.GetWorkbooks())
{
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);
bool createdFile = false;
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());
createdFile = true;
}
if (_workbookName != null) {
if (_workbookName != null)
{
ExcelExporter.InsertIntoExistingWorkbook(_workbookName, imageFile, surface.Image.Size);
} else {
}
else
{
ExcelExporter.InsertIntoNewWorkbook(imageFile, surface.Image.Size);
}
exportInformation.ExportMade = true;
ProcessExport(exportInformation, surface);
// Cleanup imageFile if we created it here, so less tmp-files are generated and left
if (createdFile) {
if (createdFile)
{
ImageOutput.DeleteNamedTmpFile(imageFile);
}
return exportInformation;
}
}

View file

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

View file

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

View file

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

View file

@ -30,29 +30,35 @@ using GreenshotPlugin.Core;
using GreenshotPlugin.Interfaces;
using GreenshotPlugin.Interfaces.Plugin;
namespace Greenshot.Plugin.Office.Destinations {
namespace Greenshot.Plugin.Office.Destinations
{
/// <summary>
/// Description of EmailDestination.
/// </summary>
public class WordDestination : AbstractDestination {
public class WordDestination : AbstractDestination
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(WordDestination));
private const int IconApplication = 0;
private const int IconDocument = 1;
private static readonly string ExePath;
private readonly string _documentCaption;
private readonly WordExporter _wordExporter = new WordExporter();
static WordDestination() {
static WordDestination()
{
ExePath = PluginUtils.GetExePath("WINWORD.EXE");
if (ExePath != null && !File.Exists(ExePath)) {
if (ExePath != null && !File.Exists(ExePath))
{
ExePath = null;
}
}
public WordDestination() {
public WordDestination()
{
}
public WordDestination(string wordCaption) {
public WordDestination(string 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 IEnumerable<IDestination> DynamicDestinations() {
foreach (string wordCaption in _wordExporter.GetWordDocuments()) {
public override IEnumerable<IDestination> DynamicDestinations()
{
foreach (string wordCaption in _wordExporter.GetWordDocuments())
{
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);
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());
}
if (_documentCaption != null) {
try {
if (_documentCaption != null)
{
try
{
_wordExporter.InsertIntoExistingDocument(_documentCaption, tmpFile);
exportInformation.ExportMade = true;
} catch (Exception) {
try {
}
catch (Exception)
{
try
{
_wordExporter.InsertIntoExistingDocument(_documentCaption, tmpFile);
exportInformation.ExportMade = true;
} catch (Exception ex) {
}
catch (Exception ex)
{
Log.Error(ex);
// TODO: Change to general logic in ProcessExport
surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetFormattedString("destination_exportfailed", Description));
}
}
} else {
if (!manuallyInitiated) {
}
else
{
if (!manuallyInitiated)
{
var documents = _wordExporter.GetWordDocuments().ToList();
if (documents != null && documents.Count > 0) {
if (documents != null && documents.Count > 0)
{
var destinations = new List<IDestination>
{
new WordDestination()
};
foreach (string document in documents) {
foreach (string document in documents)
{
destinations.Add(new WordDestination(document));
}
// Return the ExportInformation from the picker without processing, as this indirectly comes from us self
return ShowPickerMenu(false, surface, captureDetails, destinations);
}
}
try {
try
{
_wordExporter.InsertIntoNewDocument(tmpFile, null, null);
exportInformation.ExportMade = true;
} catch(Exception) {
}
catch (Exception)
{
// Retry once, just in case
try {
try
{
_wordExporter.InsertIntoNewDocument(tmpFile, null, null);
exportInformation.ExportMade = true;
} catch (Exception ex) {
}
catch (Exception ex)
{
Log.Error(ex);
// TODO: Change to general logic in ProcessExport
surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetFormattedString("destination_exportfailed", Description));
}
}
}
ProcessExport(exportInformation, surface);
return exportInformation;
}

View file

@ -23,32 +23,40 @@ using Greenshot.Plugin.Office.OfficeInterop;
using GreenshotPlugin.IniFile;
using Microsoft.Office.Interop.PowerPoint;
namespace Greenshot.Plugin.Office {
namespace Greenshot.Plugin.Office
{
/// <summary>
/// Description of CoreConfiguration.
/// </summary>
[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")]
public EmailFormat OutlookEmailFormat { get; set; }
[IniProperty("EmailSubjectPattern", Description = "Email subject pattern, works like the OutputFileFilenamePattern", DefaultValue = "${title}")]
public string EmailSubjectPattern { get; set; }
[IniProperty("EmailTo", Description = "Default value for the to in emails that are created", DefaultValue = "")]
public string EmailTo { get; set; }
[IniProperty("EmailCC", Description = "Default value for the CC in emails that are created", DefaultValue = "")]
public string EmailCC { get; set; }
[IniProperty("EmailBCC", Description = "Default value for the BCC in emails that are created", DefaultValue = "")]
public string EmailBCC { get; set; }
[IniProperty("OutlookAllowExportInMeetings", Description = "For Outlook: Allow export in meeting items", DefaultValue = "False")]
public bool OutlookAllowExportInMeetings { get; set; }
[IniProperty("WordLockAspectRatio", Description = "For Word: Lock the aspect ratio of the image", DefaultValue = "True")]
public bool WordLockAspectRatio { get; set; }
[IniProperty("PowerpointLockAspectRatio", Description = "For Powerpoint: Lock the aspect ratio of the image", DefaultValue = "True")]
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} / {2}", Parent.Parent.Name, Parent.Name, Name);
}
}

View file

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

View file

@ -38,7 +38,10 @@ namespace Greenshot.Plugin.Office.OfficeExport
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 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 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);
}
return true;
}
@ -126,6 +130,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
// Ignore, probably no OneNote running
return null;
}
return oneNoteApplication;
}
@ -140,6 +145,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
oneNoteApplication = DisposableCom.Create(new Application());
}
return oneNoteApplication;
}
@ -183,6 +189,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
};
}
}
if ("one:Section".Equals(xmlReader.Name))
{
string id = xmlReader.GetAttribute("ID");
@ -196,6 +203,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
};
}
}
if ("one:Page".Equals(xmlReader.Name))
{
// Skip deleted items
@ -214,6 +222,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
continue;
}
page.IsCurrentlyViewed = "true".Equals(xmlReader.GetAttribute("isCurrentlyViewed"));
pages.Add(page);
}
@ -233,20 +242,24 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
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);
}
catch (Exception ex)
{
LOG.Warn("Problem retrieving onenote destinations, ignoring: ", ex);
}
pages.Sort((page1, page2) =>
{
if (page1.IsCurrentlyViewed || page2.IsCurrentlyViewed)
{
return page2.IsCurrentlyViewed.CompareTo(page1.IsCurrentlyViewed);
}
return string.Compare(page1.DisplayName, page2.DisplayName, StringComparison.Ordinal);
});
return pages;
@ -264,6 +277,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
return null;
}
// ReSharper disable once RedundantAssignment
string unfiledNotesPath = "";
oneNoteApplication.ComObject.GetSpecialLocation(specialLocation, out unfiledNotesPath);
@ -285,6 +299,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
continue;
}
string id = xmlReader.GetAttribute("ID");
string path = xmlReader.GetAttribute("path");
if (unfiledNotesPath.Equals(path))
@ -301,6 +316,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
}
}
}
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 AccountKey = "9375CFF0413111d3B88A00104B2A6676";
private const string NewSignatureValue = "New Signature";
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
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);
}
break;
case AppointmentItem appointmentItem:
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);
}
}
break;
}
}
@ -110,6 +114,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
return false;
}
LOG.DebugFormat("Got {0} inspectors to check", inspectors.ComObject.Count);
for (int i = 1; i <= inspectors.ComObject.Count; i++)
{
@ -130,6 +135,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
continue;
}
try
{
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);
}
break;
case AppointmentItem appointmentItem:
if ((_outlookVersion.Major >= (int) OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings)
@ -153,6 +160,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
// skip, can't export to olAppointment
continue;
}
try
{
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);
}
break;
default:
continue;
@ -168,6 +177,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
}
}
}
return false;
}
@ -181,7 +191,8 @@ namespace Greenshot.Plugin.Office.OfficeExport
/// <param name="explorer"></param>
/// <param name="itemClass"></param>
/// <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 isAppointment = OlObjectClass.olAppointment.Equals(itemClass);
@ -190,6 +201,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
LOG.Warn("Item is no mail or appointment.");
return false;
}
try
{
// 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);
}
if (isAppointment || !isTextFormat)
{
// Check for wordmail, if so use the wordexporter
@ -219,6 +232,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
wordDocument = DisposableCom.Create(tmpWordDocument);
}
}
if (wordDocument != null)
{
using (wordDocument)
@ -248,6 +262,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
LOG.Info("Trying export for outlook < 2007.");
}
}
// Only use mailitem as it should be filled!!
if (mailItem != null)
{
@ -341,9 +356,11 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
caption = explorer.ComObject.Caption;
}
LOG.Warn($"Problem while trying to add attachment to Item '{caption}'", ex);
return false;
}
try
{
if (inspector != null)
@ -360,6 +377,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
LOG.Warn("Problem activating inspector/explorer: ", ex);
return false;
}
LOG.Debug("Finished!");
return true;
}
@ -376,27 +394,32 @@ namespace Greenshot.Plugin.Office.OfficeExport
/// <param name="cc"></param>
/// <param name="bcc"></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));
if (newItem == null)
{
return;
}
var newMail = newItem.ComObject;
newMail.Subject = subject;
if (!string.IsNullOrEmpty(to))
{
newMail.To = to;
}
if (!string.IsNullOrEmpty(cc))
{
newMail.CC = cc;
}
if (!string.IsNullOrEmpty(bcc))
{
newMail.BCC = bcc;
}
newMail.BodyFormat = OlBodyFormat.olFormatHTML;
string bodyString = null;
// 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);
}
switch (format)
{
case EmailFormat.Text:
@ -421,9 +445,11 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
bodyString = "";
}
newMail.Body = bodyString;
}
}
break;
default:
string contentId = Path.GetFileName(tmpFile);
@ -456,6 +482,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
href = $"<A HREF=\"{url}\">";
hrefEnd = "</A>";
}
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>";
if (bodyString == null)
@ -482,9 +509,11 @@ namespace Greenshot.Plugin.Office.OfficeExport
bodyString = fallbackBody;
}
}
newMail.HTMLBody = bodyString;
break;
}
// So not save, otherwise the email is always stored in Draft folder.. (newMail.Save();)
newMail.Display(false);
@ -528,12 +557,14 @@ namespace Greenshot.Plugin.Office.OfficeExport
exported = true;
}
}
return exported;
}
catch (Exception e)
{
LOG.Error("Error while creating an outlook mail item: ", e);
}
return exported;
}
@ -548,6 +579,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
outlookApplication = DisposableCom.Create(new Application());
}
InitializeVariables(outlookApplication);
return outlookApplication;
}
@ -568,10 +600,12 @@ namespace Greenshot.Plugin.Office.OfficeExport
// Ignore, probably no outlook running
return null;
}
if ((outlookApplication != null) && (outlookApplication.ComObject != null))
{
InitializeVariables(outlookApplication);
}
return outlookApplication;
}
@ -587,6 +621,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
return null;
}
string defaultProfile = (string) profilesKey.GetValue(DefaultProfileValue);
LOG.DebugFormat("defaultProfile={0}", defaultProfile);
using var profileKey = profilesKey.OpenSubKey(defaultProfile + @"\" + AccountKey, false);
@ -604,6 +639,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
continue;
}
string signatureName = "";
foreach (byte b in val)
{
@ -612,6 +648,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
signatureName += (char) b;
}
}
LOG.DebugFormat("Found email signature: {0}", signatureName);
var extension = format switch
{
@ -628,6 +665,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
}
}
}
return null;
}
@ -642,11 +680,13 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
return;
}
if (!Version.TryParse(outlookApplication.ComObject.Version, out _outlookVersion))
{
LOG.Warn("Assuming outlook version 1997.");
_outlookVersion = new Version((int) OfficeVersions.Office97, 0, 0, 0);
}
// Preventing retrieval of currentUser if Outlook is older than 2007
if (_outlookVersion.Major >= (int) OfficeVersions.Office2007)
{
@ -657,6 +697,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
using var currentUser = DisposableCom.Create(mapiNamespace.ComObject.CurrentUser);
_currentUser = currentUser.ComObject.Name;
}
LOG.InfoFormat("Current user: {0}", _currentUser);
}
catch (Exception exNs)
@ -701,6 +742,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
inspectorCaptions.Add(caption, mailItem.Class);
}
break;
case AppointmentItem appointmentItem:
if ((_outlookVersion.Major >= (int) OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings)
@ -710,6 +752,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
inspectorCaptions.Add(caption, appointmentItem.Class);
}
}
break;
}
}
@ -740,6 +783,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
continue;
}
inspectorCaptions.Add(caption, mailItem.Class);
break;
case AppointmentItem appointmentItem:
@ -756,6 +800,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
// skip, can't export to olAppointment
continue;
}
inspectorCaptions.Add(caption, appointmentItem.Class);
break;
default:
@ -769,6 +814,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
LOG.Warn("Problem retrieving word destinations, ignoring: ", ex);
}
return inspectorCaptions;
}
}

View file

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

View file

@ -53,6 +53,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
shape.ComObject.LockAspectRatio = MsoTriState.msoTrue;
}
selection.ComObject.InsertAfter("\r\n");
selection.ComObject.MoveDown(WdUnits.wdLine, 1, Type.Missing);
return shape;
@ -69,6 +70,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
wordApplication = DisposableCom.Create(new Application());
}
InitializeVariables(wordApplication);
return wordApplication;
}
@ -89,10 +91,12 @@ namespace Greenshot.Plugin.Office.OfficeExport
// Ignore, probably no word running
return null;
}
if ((wordApplication != null) && (wordApplication.ComObject != null))
{
InitializeVariables(wordApplication);
}
return wordApplication;
}
@ -116,6 +120,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
continue;
}
if (IsAfter2003())
{
if (document.ComObject.Final)
@ -139,6 +144,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
return;
}
if (!Version.TryParse(wordApplication.ComObject.Version, out _wordVersion))
{
LOG.Warn("Assuming Word version 1997.");
@ -172,6 +178,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
}
}
}
return false;
}
@ -184,7 +191,8 @@ namespace Greenshot.Plugin.Office.OfficeExport
/// <param name="address">string</param>
/// <param name="tooltip">string with the tooltip of the image</param>
/// <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.
// 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);
return false;
}
// Add Picture
using (var shape = AddPictureToSelection(selection, tmpFile))
{
@ -214,6 +223,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
screentip = tooltip;
}
try
{
using var hyperlinks = DisposableCom.Create(wordDocument.ComObject.Hyperlinks);
@ -225,6 +235,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
}
}
}
try
{
// 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);
}
}
try
{
wordApplication.ComObject.Activate();
@ -254,6 +266,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
LOG.Warn("Error activating word application", ex);
}
try
{
wordDocument.ComObject.Activate();
@ -263,6 +276,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
LOG.Warn("Error activating word document", ex);
}
return true;
}
@ -279,6 +293,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
return;
}
wordApplication.ComObject.Visible = true;
wordApplication.ComObject.Activate();
// Create new Document
@ -299,6 +314,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
screentip = tooltip;
}
try
{
using var hyperlinks = DisposableCom.Create(wordDocument.ComObject.Hyperlinks);
@ -313,6 +329,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
}
}
}
try
{
wordDocument.ComObject.Activate();
@ -322,6 +339,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
{
LOG.Warn("Error activating word document", ex);
}
try
{
using var activeWindow = DisposableCom.Create(wordDocument.ComObject.ActiveWindow);

View file

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

View file

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

View file

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

View file

@ -19,10 +19,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Greenshot.Plugin.Photobucket.Forms {
namespace Greenshot.Plugin.Photobucket.Forms
{
/// <summary>
/// This class is needed for design-time resolving of the language files
/// </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/>.
*/
namespace Greenshot.Plugin.Photobucket.Forms {
namespace Greenshot.Plugin.Photobucket.Forms
{
/// <summary>
/// Description of PasswordRequestForm.
/// </summary>
public partial class SettingsForm : PhotobucketForm {
public partial class SettingsForm : PhotobucketForm
{
public SettingsForm()
{
//

View file

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

View file

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

View file

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

View file

@ -27,7 +27,8 @@ namespace Greenshot.Plugin.Photobucket
/// <summary>
/// Description of PhotobucketInfo.
/// </summary>
public class PhotobucketInfo {
public class PhotobucketInfo
{
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(PhotobucketInfo));
public string Original { get; set; }
@ -41,27 +42,37 @@ namespace Greenshot.Plugin.Photobucket
/// </summary>
/// <param name="response">XML</param>
/// <returns>PhotobucketInfo object</returns>
public static PhotobucketInfo FromUploadResponse(string response) {
public static PhotobucketInfo FromUploadResponse(string response)
{
Log.Debug(response);
PhotobucketInfo photobucketInfo = new PhotobucketInfo();
try {
try
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(response);
var nodes = doc.GetElementsByTagName("url");
if(nodes.Count > 0) {
if (nodes.Count > 0)
{
photobucketInfo.Original = nodes.Item(0)?.InnerText;
}
nodes = doc.GetElementsByTagName("browseurl");
if(nodes.Count > 0) {
if (nodes.Count > 0)
{
photobucketInfo.Page = nodes.Item(0)?.InnerText;
}
nodes = doc.GetElementsByTagName("thumb");
if(nodes.Count > 0) {
if (nodes.Count > 0)
{
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);
}
return photobucketInfo;
}
}

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