diff --git a/Greenshot/Destinations/FileDestination.cs b/Greenshot/Destinations/FileDestination.cs
index 331ba6c89..f821e4bd6 100644
--- a/Greenshot/Destinations/FileDestination.cs
+++ b/Greenshot/Destinations/FileDestination.cs
@@ -116,6 +116,7 @@ namespace Greenshot.Destinations {
pattern = "greenshot ${capturetime}";
}
string filename = FilenameHelper.GetFilenameFromPattern(pattern, CoreConfig.OutputFileFormat, captureDetails);
+ CoreConfig.ValidateAndCorrectOutputFilePath();
string filepath = FilenameHelper.FillVariables(CoreConfig.OutputFilePath, false);
try {
fullPath = Path.Combine(filepath, filename);
diff --git a/Greenshot/Drawing/Fields/FieldAggregator.cs b/Greenshot/Drawing/Fields/FieldAggregator.cs
index cbf5377d7..3eb2f8bac 100644
--- a/Greenshot/Drawing/Fields/FieldAggregator.cs
+++ b/Greenshot/Drawing/Fields/FieldAggregator.cs
@@ -27,6 +27,7 @@ using Greenshot.Plugin.Drawing;
using GreenshotPlugin.Interfaces.Drawing;
using System.Collections.Generic;
using System.ComponentModel;
+using System.Linq;
namespace Greenshot.Drawing.Fields
{
@@ -203,7 +204,7 @@ namespace Greenshot.Drawing.Fields
{
return;
}
- foreach (var drawableContainer1 in _boundContainers)
+ foreach (var drawableContainer1 in _boundContainers.ToList())
{
var drawableContainer = (DrawableContainer) drawableContainer1;
if (!drawableContainer.HasField(field.FieldType))
diff --git a/Greenshot/Drawing/SpeechbubbleContainer.cs b/Greenshot/Drawing/SpeechbubbleContainer.cs
index f90643ae9..0cdfb91c1 100644
--- a/Greenshot/Drawing/SpeechbubbleContainer.cs
+++ b/Greenshot/Drawing/SpeechbubbleContainer.cs
@@ -56,9 +56,10 @@ namespace Greenshot.Drawing
///
/// Restore the target gripper
///
- ///
- protected override void OnDeserialized(StreamingContext context)
+ /// StreamingContext
+ protected override void OnDeserialized(StreamingContext streamingContext)
{
+ base.OnDeserialized(streamingContext);
InitAdorner(Color.Green, _storedTargetGripperLocation);
}
#endregion
@@ -303,7 +304,6 @@ namespace Greenshot.Drawing
tail.Dispose();
// Draw the text
- UpdateFormat();
DrawText(graphics, rect, lineThickness, lineColor, shadow, StringFormat, Text, Font);
}
diff --git a/Greenshot/Drawing/TextContainer.cs b/Greenshot/Drawing/TextContainer.cs
index 2761bfe9c..0c72b464b 100644
--- a/Greenshot/Drawing/TextContainer.cs
+++ b/Greenshot/Drawing/TextContainer.cs
@@ -272,8 +272,11 @@ namespace Greenshot.Drawing
_parent.Controls.Add(_textBox);
}
EnsureTextBoxContrast();
- _textBox.Show();
- _textBox.Focus();
+ if (_textBox != null)
+ {
+ _textBox.Show();
+ _textBox.Focus();
+ }
}
///
@@ -281,6 +284,10 @@ namespace Greenshot.Drawing
///
private void EnsureTextBoxContrast()
{
+ if (_textBox == null)
+ {
+ return;
+ }
Color lc = GetFieldValueAsColor(FieldType.LINE_COLOR);
if (lc.R > 203 && lc.G > 203 && lc.B > 203)
{
@@ -295,7 +302,7 @@ namespace Greenshot.Drawing
private void HideTextBox()
{
_parent.Focus();
- _textBox.Hide();
+ _textBox?.Hide();
_parent.KeysLocked = false;
_parent.Controls.Remove(_textBox);
}
@@ -424,6 +431,10 @@ namespace Greenshot.Drawing
///
private void UpdateTextBoxPosition()
{
+ if (_textBox == null)
+ {
+ return;
+ }
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
int lineWidth = (int)Math.Floor(lineThickness / 2d);
diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs
index 24ef53bc7..c5de9937e 100644
--- a/Greenshot/Forms/ImageEditorForm.cs
+++ b/Greenshot/Forms/ImageEditorForm.cs
@@ -860,13 +860,15 @@ namespace Greenshot {
case Keys.Oemcomma: // Rotate CCW Ctrl + ,
RotateCcwToolstripButtonClick(sender, e);
break;
- case Keys.OemPeriod: // Rotate CW Ctrl + .
+ case Keys.OemPeriod: // Rotate CW Ctrl + .
RotateCwToolstripButtonClick(sender, e);
break;
case Keys.Add: // Ctrl + +
+ case Keys.Oemplus: // Ctrl + +
EnlargeCanvasToolStripMenuItemClick(sender, e);
break;
case Keys.Subtract: // Ctrl + -
+ case Keys.OemMinus: // Ctrl + -
ShrinkCanvasToolStripMenuItemClick(sender, e);
break;
}
diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs
index b8164fba4..23bb8960f 100644
--- a/Greenshot/Forms/MainForm.cs
+++ b/Greenshot/Forms/MainForm.cs
@@ -1307,46 +1307,11 @@ namespace Greenshot {
private void NotifyIconClick(ClickActions clickAction) {
switch (clickAction) {
case ClickActions.OPEN_LAST_IN_EXPLORER:
- string path = _conf.OutputFileAsFullpath;
- if (!File.Exists(path)) {
- string lastFilePath = Path.GetDirectoryName(_conf.OutputFileAsFullpath);
- if (!string.IsNullOrEmpty(lastFilePath) && Directory.Exists(lastFilePath)) {
- path = lastFilePath;
- }
- }
- if (path == null) {
- string configPath = FilenameHelper.FillVariables(_conf.OutputFilePath, false);
- if (Directory.Exists(configPath)) {
- path = configPath;
- }
- }
-
- if (path != null) {
- try {
- // Check if path is a directory
- if (Directory.Exists(path))
- {
- using (Process.Start(path))
- {
- }
- }
- // Check if path is a file
- else if (File.Exists(path))
- {
- // Start the explorer process and select the file
- using (var explorer = Process.Start("explorer.exe", $"/select,\"{path}\""))
- {
- explorer?.WaitForInputIdle(500);
- }
- }
- } catch (Exception ex) {
- // Make sure we show what we tried to open in the exception
- ex.Data.Add("path", path);
- throw;
- }
- }
+ Contextmenu_OpenRecent(this, null);
break;
case ClickActions.OPEN_LAST_IN_EDITOR:
+ _conf.ValidateAndCorrectOutputFileAsFullpath();
+
if (File.Exists(_conf.OutputFileAsFullpath)) {
CaptureHelper.CaptureFile(_conf.OutputFileAsFullpath, DestinationHelper.GetDestination(EditorDestination.DESIGNATION));
}
@@ -1364,25 +1329,40 @@ namespace Greenshot {
///
/// The Contextmenu_OpenRecent currently opens the last know save location
///
- private void Contextmenu_OpenRecent(object sender, EventArgs eventArgs) {
- string path = FilenameHelper.FillVariables(_conf.OutputFilePath, false);
- // Fix for #1470, problems with a drive which is no longer available
- try {
- string lastFilePath = Path.GetDirectoryName(_conf.OutputFileAsFullpath);
+ private void Contextmenu_OpenRecent(object sender, EventArgs eventArgs)
+ {
+ _conf.ValidateAndCorrectOutputFilePath();
+ _conf.ValidateAndCorrectOutputFileAsFullpath();
+ string path = _conf.OutputFileAsFullpath;
+ if (!File.Exists(path))
+ {
+ path = FilenameHelper.FillVariables(_conf.OutputFilePath, false);
+ // Fix for #1470, problems with a drive which is no longer available
+ try
+ {
+ string lastFilePath = Path.GetDirectoryName(_conf.OutputFileAsFullpath);
- if (lastFilePath != null && Directory.Exists(lastFilePath)) {
- path = lastFilePath;
- } else if (!Directory.Exists(path)) {
- // What do I open when nothing can be found? Right, nothing...
- return;
+ if (lastFilePath != null && Directory.Exists(lastFilePath))
+ {
+ path = lastFilePath;
+ }
+ else if (!Directory.Exists(path))
+ {
+ // What do I open when nothing can be found? Right, nothing...
+ return;
+ }
+ }
+ catch (Exception ex)
+ {
+ LOG.Warn("Couldn't open the path to the last exported file, taking default.", ex);
}
- } catch (Exception ex) {
- LOG.Warn("Couldn't open the path to the last exported file, taking default.", ex);
}
- LOG.Debug("DoubleClick was called! Starting: " + path);
- try {
- Process.Start(path);
- } catch (Exception ex) {
+ try
+ {
+ ExplorerHelper.OpenInExplorer(path);
+ }
+ catch (Exception ex)
+ {
// Make sure we show what we tried to open in the exception
ex.Data.Add("path", path);
LOG.Warn("Couldn't open the path to the last exported file", ex);
diff --git a/Greenshot/Helpers/CaptureHelper.cs b/Greenshot/Helpers/CaptureHelper.cs
index e62afabe7..3351db1d8 100644
--- a/Greenshot/Helpers/CaptureHelper.cs
+++ b/Greenshot/Helpers/CaptureHelper.cs
@@ -512,22 +512,14 @@ namespace Greenshot.Helpers {
string errorMessage = null;
var path = Path.GetDirectoryName(surface.LastSaveFullPath);
try {
- if (path != null)
- {
- var processStartInfo = new ProcessStartInfo("explorer.exe")
- {
- Arguments = path,
- UseShellExecute = false
- };
- using (var process = new Process()) {
- process.StartInfo = processStartInfo;
- process.Start();
- }
- }
- } catch (Exception ex) {
+ ExplorerHelper.OpenInExplorer(path);
+ }
+ catch (Exception ex)
+ {
errorMessage = ex.Message;
}
// Added fallback for when the explorer can't be found
+ // TODO: Check if this makes sense
if (errorMessage != null) {
try {
string windowsPath = Environment.GetEnvironmentVariable("SYSTEMROOT");
@@ -852,7 +844,7 @@ namespace Greenshot.Helpers {
// Restore the window making sure it's visible!
windowToCapture.Restore();
} else {
- windowToCapture.ToForeground();
+ windowToCapture.ToForeground(false);
}
tmpCapture = windowToCapture.CaptureGdiWindow(captureForWindow);
if (tmpCapture != null) {
@@ -954,7 +946,7 @@ namespace Greenshot.Helpers {
_capture.CaptureDetails.DpiY = graphics.DpiY;
}
// Set previouslyActiveWindow as foreground window
- previouslyActiveWindow?.ToForeground();
+ previouslyActiveWindow?.ToForeground(false);
if (_capture.CaptureDetails != null) {
((Bitmap) _capture.Image)?.SetResolution(_capture.CaptureDetails.DpiX, _capture.CaptureDetails.DpiY);
}
diff --git a/Greenshot/Helpers/UpdateHelper.cs b/Greenshot/Helpers/UpdateHelper.cs
index 68d5d5d9f..28c522c18 100644
--- a/Greenshot/Helpers/UpdateHelper.cs
+++ b/Greenshot/Helpers/UpdateHelper.cs
@@ -36,8 +36,8 @@ namespace Greenshot.Experimental {
public static class UpdateHelper {
private static readonly ILog Log = LogManager.GetLogger(typeof(UpdateHelper));
private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection();
- private const string StableDownloadLink = "http://getgreenshot.org/downloads/";
- private const string VersionHistoryLink = "http://getgreenshot.org/version-history/";
+ private const string StableDownloadLink = "https://getgreenshot.org/downloads/";
+ private const string VersionHistoryLink = "https://getgreenshot.org/version-history/";
private static readonly object LockObject = new object();
private static RssFile _latestGreenshot;
private static string _downloadLink = StableDownloadLink;
diff --git a/Greenshot/releases/additional_files/readme.txt.template b/Greenshot/releases/additional_files/readme.txt.template
index 4c85447db..984044afb 100644
--- a/Greenshot/releases/additional_files/readme.txt.template
+++ b/Greenshot/releases/additional_files/readme.txt.template
@@ -9,6 +9,36 @@ All details to our tickets can be found here: https://greenshot.atlassian.net
@DETAILVERSION@
+This is Greenshot 1.2.9BF2, the second bugfix release for Greenshot 1.2.9
+
+The following tickets are on the list for the bugfix release, the current state is not represented in UNSTABLE builds:
+* BUG-2051 Scroll-lock button not usable as hotkey
+* BUG-2055 Cannot paste Greenshot capture to Skype
+* BUG-2056 Cannot export to external command Paint.NET if .greenshot format is used
+* BUG-2068 Export to Confluence caused System.NullReferenceException
+* BUG-2081 Canvas resize (Ctrl + / Ctrl -) only works via numpad keys
+* BUG-2093 Shadow effects not renderingWindows 10 window border frame is not capture correctly on Windows 10
+* BUG-2095 'Save as' doesn't remember last saved directory (after restart)
+* BUG-2097 Window border is not captured on Windows 10
+* BUG-2098 Greenshot opens Explorer when clicking tray while notification is still showing
+* BUG-2100 ArgumentException when changing the icon size from 16 to 32
+* BUG-2101 Update to version 1.2.9.112 release -> Error 5 Access is denied
+* BUG-2102 InvalidOperationException when selecting a color
+* BUG-2103 ArgumentException when changing the icon size from 16 to 32
+* BUG-2104 Speechbubble can't be used after copy/paste
+* BUG-2105 Window border is not captured on Windows 10
+* BUG-2108 Capture last region doesn't work
+* BUG-2109 Double-click on textbox causes NullReferenceException
+* BUG-2110 Missing annotations when opening .greenshot files
+* BUG-2111 Drag and Drop image file on editor doesn't work
+* BUG-2114 Storage location reset to default if not available during start
+* BUG-2115 Error while trying to upload screenshot to Jira
+* FEATURE-998 The feature "Opening last capture in explorer should select/jump to the file" wasn't available everywhere
+
+
+1.2.9.112-9bc62ac RELEASE
+
+
This is a bugfix release for the Greenshot 1.2.9.104-3721c10 RELEASE
Bugs fixed:
diff --git a/GreenshotExternalCommandPlugin/ExternalCommandDestination.cs b/GreenshotExternalCommandPlugin/ExternalCommandDestination.cs
index 654c2051a..93c0e8096 100644
--- a/GreenshotExternalCommandPlugin/ExternalCommandDestination.cs
+++ b/GreenshotExternalCommandPlugin/ExternalCommandDestination.cs
@@ -43,33 +43,21 @@ namespace ExternalCommand {
_presetCommand = commando;
}
- public override string Designation {
- get {
- return "External " + _presetCommand.Replace(',','_');
- }
- }
+ public override string Designation => "External " + _presetCommand.Replace(',','_');
- public override string Description {
- get {
- return _presetCommand;
- }
- }
+ public override string Description => _presetCommand;
public override IEnumerable DynamicDestinations() {
yield break;
}
- public override Image DisplayIcon {
- get {
- return IconCache.IconForCommand(_presetCommand);
- }
- }
+ public override Image DisplayIcon => IconCache.IconForCommand(_presetCommand);
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)) {
config.RunInbackground.Add(_presetCommand, true);
@@ -154,12 +142,12 @@ namespace ExternalCommand {
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) {
+ } catch (Win32Exception w32Ex) {
try {
return CallExternalCommand(commando, fullPath, "runas", out output, out error);
} catch {
- w32ex.Data.Add("commandline", config.Commandline[_presetCommand]);
- w32ex.Data.Add("arguments", config.Argument[_presetCommand]);
+ w32Ex.Data.Add("commandline", config.Commandline[_presetCommand]);
+ w32Ex.Data.Add("arguments", config.Argument[_presetCommand]);
throw;
}
} catch (Exception ex) {
diff --git a/GreenshotFlickrPlugin/FlickrUtils.cs b/GreenshotFlickrPlugin/FlickrUtils.cs
index 00cb56ed4..39c423cdf 100644
--- a/GreenshotFlickrPlugin/FlickrUtils.cs
+++ b/GreenshotFlickrPlugin/FlickrUtils.cs
@@ -42,7 +42,7 @@ namespace GreenshotFlickrPlugin {
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}.jpg";
+ 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";
@@ -131,8 +131,9 @@ namespace GreenshotFlickrPlugin {
string farmId = item.Attributes["farm"].Value;
string serverId = item.Attributes["server"].Value;
string photoId = item.Attributes["id"].Value;
- string secret = item.Attributes["secret"].Value;
- return string.Format(FLICKR_FARM_URL, farmId, serverId, photoId, secret);
+ string originalsecret = item.Attributes["originalsecret"].Value;
+ string originalFormat = item.Attributes["originalformat"].Value;
+ return string.Format(FLICKR_FARM_URL, farmId, serverId, photoId, originalsecret, originalFormat);
}
}
}
diff --git a/GreenshotJiraPlugin/AsyncMemoryCache.cs b/GreenshotJiraPlugin/AsyncMemoryCache.cs
index f7d029750..479bbbd20 100644
--- a/GreenshotJiraPlugin/AsyncMemoryCache.cs
+++ b/GreenshotJiraPlugin/AsyncMemoryCache.cs
@@ -29,7 +29,7 @@ using System;
using System.Runtime.Caching;
using System.Threading;
using System.Threading.Tasks;
-using Dapplo.Log.Facade;
+using Dapplo.Log;
#endregion
diff --git a/GreenshotJiraPlugin/Forms/JiraForm.cs b/GreenshotJiraPlugin/Forms/JiraForm.cs
index cfd5183e6..f4a47a347 100644
--- a/GreenshotJiraPlugin/Forms/JiraForm.cs
+++ b/GreenshotJiraPlugin/Forms/JiraForm.cs
@@ -36,7 +36,6 @@ namespace GreenshotJiraPlugin.Forms {
private readonly JiraConnector _jiraConnector;
private Issue _selectedIssue;
private readonly GreenshotColumnSorter _columnSorter;
- private static readonly JiraConfiguration JiraConfig = IniConfig.GetIniSection();
private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection();
public JiraForm(JiraConnector jiraConnector) {
@@ -161,14 +160,21 @@ namespace GreenshotJiraPlugin.Forms {
jiraListView.LargeImageList = imageList;
foreach (var issue in issues) {
- var issueIcon = await _jiraConnector.GetIssueTypeBitmapAsync(issue);
- imageList.Images.Add(issueIcon);
-
var item = new ListViewItem
{
- Tag = issue,
- ImageIndex = imageList.Images.Count - 1
+ Tag = issue
};
+ try
+ {
+ var issueIcon = await _jiraConnector.GetIssueTypeBitmapAsync(issue);
+ imageList.Images.Add(issueIcon);
+ item.ImageIndex = imageList.Images.Count - 1;
+ }
+ catch (Exception ex)
+ {
+ Log.Warn("Problem loading issue type, ignoring", ex);
+ }
+
item.SubItems.Add(issue.Key);
item.SubItems.Add(issue.Fields.Created.ToString("d", DateTimeFormatInfo.InvariantInfo));
item.SubItems.Add(issue.Fields.Assignee?.DisplayName);
diff --git a/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj b/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj
index fe5838095..fb1e8108b 100644
--- a/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj
+++ b/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj
@@ -34,32 +34,42 @@
-
- ..\packages\Dapplo.HttpExtensions.0.5.43\lib\net45\Dapplo.HttpExtensions.dll
+
+ ..\packages\Dapplo.HttpExtensions.0.6.17\lib\net45\Dapplo.HttpExtensions.dll
True
-
- ..\packages\Dapplo.Jira.0.1.65\lib\net45\Dapplo.Jira.dll
+
+ ..\packages\Dapplo.Jira.0.5.8\lib\net45\Dapplo.Jira.dll
True
-
- ..\packages\Dapplo.Log.Facade.0.5.4\lib\net45\Dapplo.Log.Facade.dll
+
+ ..\packages\Dapplo.Log.1.0.23\lib\net45\Dapplo.Log.dll
True
..\Greenshot\Lib\log4net.dll
-
- ..\packages\Svg.2.2.2\lib\net35\Svg.dll
+
+
+
+
+ ..\packages\Svg.2.3.0\lib\net35\Svg.dll
True
+
+
+
+
+
+
+
@@ -94,7 +104,6 @@
-
Always
diff --git a/GreenshotJiraPlugin/IssueTypeBitmapCache.cs b/GreenshotJiraPlugin/IssueTypeBitmapCache.cs
index b48173e8f..782d2e9ed 100644
--- a/GreenshotJiraPlugin/IssueTypeBitmapCache.cs
+++ b/GreenshotJiraPlugin/IssueTypeBitmapCache.cs
@@ -33,11 +33,11 @@ namespace GreenshotJiraPlugin
///
public class IssueTypeBitmapCache : AsyncMemoryCache
{
- private readonly JiraApi _jiraApi;
+ private readonly IJiraClient _jiraClient;
- public IssueTypeBitmapCache(JiraApi jiraApi)
+ public IssueTypeBitmapCache(IJiraClient jiraClient)
{
- _jiraApi = jiraApi;
+ _jiraClient = jiraClient;
// Set the expire timeout to an hour
ExpireTimeSpan = TimeSpan.FromHours(4);
}
@@ -49,7 +49,7 @@ namespace GreenshotJiraPlugin
protected override async Task CreateAsync(IssueType issueType, CancellationToken cancellationToken = new CancellationToken())
{
- return await _jiraApi.GetUriContentAsync(issueType.IconUri, cancellationToken).ConfigureAwait(false);
+ return await _jiraClient.Server.GetUriContentAsync(issueType.IconUri, cancellationToken).ConfigureAwait(false);
}
}
}
diff --git a/GreenshotJiraPlugin/JiraConnector.cs b/GreenshotJiraPlugin/JiraConnector.cs
index ee9e98a2f..6d9c933f3 100644
--- a/GreenshotJiraPlugin/JiraConnector.cs
+++ b/GreenshotJiraPlugin/JiraConnector.cs
@@ -24,19 +24,20 @@ using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Dapplo.HttpExtensions;
+using Dapplo.HttpExtensions.Extensions;
using Dapplo.Jira;
+using Dapplo.Jira.Converters;
using Dapplo.Jira.Entities;
using Greenshot.IniFile;
using GreenshotPlugin.Core;
namespace GreenshotJiraPlugin {
///
- /// This encapsulates the JiraApi to make it possible to change as less old Greenshot code as needed
+ /// This encapsulates the JiraClient to make it possible to change as less old Greenshot code as needed
///
public class JiraConnector : IDisposable {
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(JiraConnector));
@@ -47,27 +48,19 @@ namespace GreenshotJiraPlugin {
private DateTimeOffset _loggedInTime = DateTimeOffset.MinValue;
private bool _loggedIn;
private readonly int _timeout;
- private JiraApi _jiraApi;
+ private IJiraClient _jiraClient;
private IssueTypeBitmapCache _issueTypeBitmapCache;
- private static readonly SvgBitmapHttpContentConverter SvgBitmapHttpContentConverterInstance = new SvgBitmapHttpContentConverter();
///
/// Initialize some basic stuff, in the case the SVG to bitmap converter
///
static JiraConnector()
{
- if (HttpExtensionsGlobals.HttpContentConverters.All(x => x.GetType() != typeof(SvgBitmapHttpContentConverter)))
- {
- HttpExtensionsGlobals.HttpContentConverters.Add(SvgBitmapHttpContentConverterInstance);
- }
- SvgBitmapHttpContentConverterInstance.Width = CoreConfig.IconSize.Width;
- SvgBitmapHttpContentConverterInstance.Height = CoreConfig.IconSize.Height;
CoreConfig.PropertyChanged += (sender, args) =>
{
if (args.PropertyName == nameof(CoreConfig.IconSize))
{
- SvgBitmapHttpContentConverterInstance.Width = CoreConfig.IconSize.Width;
- SvgBitmapHttpContentConverterInstance.Height = CoreConfig.IconSize.Height;
+ JiraPlugin.Instance.JiraConnector._jiraClient?.Behaviour.SetConfig(new SvgConfiguration { Width = CoreConfig.IconSize.Width, Height = CoreConfig.IconSize.Height });
}
};
@@ -77,7 +70,7 @@ namespace GreenshotJiraPlugin {
/// Dispose, logout the users
///
public void Dispose() {
- if (_jiraApi != null)
+ if (_jiraClient != null)
{
Task.Run(async () => await LogoutAsync()).Wait();
}
@@ -104,25 +97,27 @@ namespace GreenshotJiraPlugin {
/// Internal login which catches the exceptions
///
/// true if login was done sucessfully
- private async Task DoLoginAsync(string user, string password)
+ private async Task DoLoginAsync(string user, string password, CancellationToken cancellationToken = default(CancellationToken))
{
if (string.IsNullOrEmpty(user) || string.IsNullOrEmpty(password))
{
return false;
}
- _jiraApi = new JiraApi(new Uri(JiraConfig.Url));
- _issueTypeBitmapCache = new IssueTypeBitmapCache(_jiraApi);
+ _jiraClient = JiraClient.Create(new Uri(JiraConfig.Url));
+ _jiraClient.Behaviour.SetConfig(new SvgConfiguration { Width = CoreConfig.IconSize.Width, Height = CoreConfig.IconSize.Height });
+
+ _issueTypeBitmapCache = new IssueTypeBitmapCache(_jiraClient);
LoginInfo loginInfo;
try
{
- loginInfo = await _jiraApi.StartSessionAsync(user, password);
+ loginInfo = await _jiraClient.Session.StartAsync(user, password, cancellationToken);
Monitor = new JiraMonitor();
- await Monitor.AddJiraInstanceAsync(_jiraApi);
+ await Monitor.AddJiraInstanceAsync(_jiraClient, cancellationToken);
- var favIconUri = _jiraApi.JiraBaseUri.AppendSegments("favicon.ico");
+ var favIconUri = _jiraClient.JiraBaseUri.AppendSegments("favicon.ico");
try
{
- FavIcon = await _jiraApi.GetUriContentAsync(favIconUri);
+ FavIcon = await _jiraClient.Server.GetUriContentAsync(favIconUri, cancellationToken);
}
catch (Exception ex)
{
@@ -142,8 +137,8 @@ namespace GreenshotJiraPlugin {
/// If there are credentials, call the real login.
///
/// Task
- public async Task LoginAsync() {
- await LogoutAsync();
+ public async Task LoginAsync(CancellationToken cancellationToken = default(CancellationToken)) {
+ await LogoutAsync(cancellationToken);
try {
// Get the system name, so the user knows where to login to
var credentialsDialog = new CredentialsDialog(JiraConfig.Url)
@@ -151,7 +146,7 @@ namespace GreenshotJiraPlugin {
Name = null
};
while (credentialsDialog.Show(credentialsDialog.Name) == DialogResult.OK) {
- if (await DoLoginAsync(credentialsDialog.Name, credentialsDialog.Password)) {
+ if (await DoLoginAsync(credentialsDialog.Name, credentialsDialog.Password, cancellationToken)) {
if (credentialsDialog.SaveChecked) {
credentialsDialog.Confirm(true);
}
@@ -181,11 +176,11 @@ namespace GreenshotJiraPlugin {
///
/// End the session, if there was one
///
- public async Task LogoutAsync() {
- if (_jiraApi != null && _loggedIn)
+ public async Task LogoutAsync(CancellationToken cancellationToken = default(CancellationToken)) {
+ if (_jiraClient != null && _loggedIn)
{
Monitor.Dispose();
- await _jiraApi.EndSessionAsync();
+ await _jiraClient.Session.EndAsync(cancellationToken);
_loggedIn = false;
}
}
@@ -195,14 +190,14 @@ namespace GreenshotJiraPlugin {
/// Do not use ConfigureAwait to call this, as it will move await from the UI thread.
///
///
- private async Task CheckCredentialsAsync() {
+ private async Task CheckCredentialsAsync(CancellationToken cancellationToken = default(CancellationToken)) {
if (_loggedIn) {
if (_loggedInTime.AddMinutes(_timeout-1).CompareTo(DateTime.Now) < 0) {
- await LogoutAsync();
- await LoginAsync();
+ await LogoutAsync(cancellationToken);
+ await LoginAsync(cancellationToken);
}
} else {
- await LoginAsync();
+ await LoginAsync(cancellationToken);
}
}
@@ -210,23 +205,24 @@ namespace GreenshotJiraPlugin {
/// Get the favourite filters
///
/// List with filters
- public async Task> GetFavoriteFiltersAsync()
+ public async Task> GetFavoriteFiltersAsync(CancellationToken cancellationToken = default(CancellationToken))
{
- await CheckCredentialsAsync();
- return await _jiraApi.GetFavoriteFiltersAsync().ConfigureAwait(false);
+ await CheckCredentialsAsync(cancellationToken);
+ return await _jiraClient.Filter.GetFavoritesAsync(cancellationToken).ConfigureAwait(false);
}
///
/// Get the issue for a key
///
/// Jira issue key
+ /// CancellationToken
/// Issue
- public async Task GetIssueAsync(string issueKey)
+ public async Task GetIssueAsync(string issueKey, CancellationToken cancellationToken = default(CancellationToken))
{
- await CheckCredentialsAsync();
+ await CheckCredentialsAsync(cancellationToken);
try
{
- return await _jiraApi.GetIssueAsync(issueKey).ConfigureAwait(false);
+ return await _jiraClient.Issue.GetAsync(issueKey, cancellationToken).ConfigureAwait(false);
}
catch
{
@@ -243,12 +239,12 @@ namespace GreenshotJiraPlugin {
///
public async Task AttachAsync(string issueKey, IBinaryContainer content, CancellationToken cancellationToken = default(CancellationToken))
{
- await CheckCredentialsAsync();
+ await CheckCredentialsAsync(cancellationToken);
using (var memoryStream = new MemoryStream())
{
content.WriteToStream(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
- await _jiraApi.AttachAsync(issueKey, memoryStream, content.Filename, content.ContentType, cancellationToken).ConfigureAwait(false);
+ await _jiraClient.Attachment.AttachAsync(issueKey, memoryStream, content.Filename, content.ContentType, cancellationToken).ConfigureAwait(false);
}
}
@@ -261,8 +257,8 @@ namespace GreenshotJiraPlugin {
/// CancellationToken
public async Task AddCommentAsync(string issueKey, string body, string visibility = null, CancellationToken cancellationToken = default(CancellationToken))
{
- await CheckCredentialsAsync();
- await _jiraApi.AddCommentAsync(issueKey, body, visibility, cancellationToken).ConfigureAwait(false);
+ await CheckCredentialsAsync(cancellationToken);
+ await _jiraClient.Issue.AddCommentAsync(issueKey, body, visibility, cancellationToken).ConfigureAwait(false);
}
///
@@ -273,8 +269,8 @@ namespace GreenshotJiraPlugin {
///
public async Task> SearchAsync(Filter filter, CancellationToken cancellationToken = default(CancellationToken))
{
- await CheckCredentialsAsync();
- var searchResult = await _jiraApi.SearchAsync(filter.Jql, 20, new[] { "summary", "reporter", "assignee", "created", "issuetype" }, cancellationToken).ConfigureAwait(false);
+ await CheckCredentialsAsync(cancellationToken);
+ var searchResult = await _jiraClient.Issue.SearchAsync(filter.Jql, 20, new[] { "summary", "reporter", "assignee", "created", "issuetype" }, cancellationToken).ConfigureAwait(false);
return searchResult.Issues;
}
@@ -292,7 +288,7 @@ namespace GreenshotJiraPlugin {
///
/// Get the base uri
///
- public Uri JiraBaseUri => _jiraApi.JiraBaseUri;
+ public Uri JiraBaseUri => _jiraClient.JiraBaseUri;
///
/// Is the user "logged in?
diff --git a/GreenshotJiraPlugin/JiraDestination.cs b/GreenshotJiraPlugin/JiraDestination.cs
index 1b35e6fde..e6f60cd46 100644
--- a/GreenshotJiraPlugin/JiraDestination.cs
+++ b/GreenshotJiraPlugin/JiraDestination.cs
@@ -78,9 +78,17 @@ namespace GreenshotJiraPlugin {
{
if (_jiraIssue != null)
{
- displayIcon = jiraConnector.GetIssueTypeBitmapAsync(_jiraIssue).Result;
+ // Try to get the issue type as icon
+ try
+ {
+ displayIcon = jiraConnector.GetIssueTypeBitmapAsync(_jiraIssue).Result;
+ }
+ catch (Exception ex)
+ {
+ Log.Warn($"Problem loading issue type for {_jiraIssue.Key}, ignoring", ex);
+ }
}
- else
+ if (displayIcon == null)
{
displayIcon = jiraConnector.FavIcon;
}
diff --git a/GreenshotJiraPlugin/JiraMonitor.cs b/GreenshotJiraPlugin/JiraMonitor.cs
index 81605bddf..562bf6c4c 100644
--- a/GreenshotJiraPlugin/JiraMonitor.cs
+++ b/GreenshotJiraPlugin/JiraMonitor.cs
@@ -26,7 +26,7 @@ using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Dapplo.Jira;
-using Dapplo.Log.Facade;
+using Dapplo.Log;
using GreenshotJiraPlugin.Hooking;
namespace GreenshotJiraPlugin
@@ -42,9 +42,10 @@ namespace GreenshotJiraPlugin
private static readonly LogSource Log = new LogSource();
private readonly Regex _jiraKeyPattern = new Regex(@"[A-Z][A-Z0-9]+\-[0-9]+");
private readonly WindowsTitleMonitor _monitor;
- private readonly IList _jiraInstances = new List();
- private readonly IDictionary _projectJiraApiMap = new Dictionary();
+ private readonly IList _jiraInstances = new List();
+ private readonly IDictionary _projectJiraClientMap = new Dictionary();
private readonly int _maxEntries;
+ // TODO: Add issues from issueHistory (JQL -> Where.IssueKey.InIssueHistory())
private IDictionary _recentJiras = new Dictionary();
///
@@ -92,10 +93,10 @@ namespace GreenshotJiraPlugin
/// Retrieve the API belonging to a JiraDetails
///
///
- /// JiraAPI
- public JiraApi GetJiraApiForKey(JiraDetails jiraDetails)
+ /// IJiraClient
+ public IJiraClient GetJiraClientForKey(JiraDetails jiraDetails)
{
- return _projectJiraApiMap[jiraDetails.ProjectKey];
+ return _projectJiraClientMap[jiraDetails.ProjectKey];
}
///
@@ -116,17 +117,17 @@ namespace GreenshotJiraPlugin
///
///
///
- public async Task AddJiraInstanceAsync(JiraApi jiraInstance, CancellationToken token = default(CancellationToken))
+ public async Task AddJiraInstanceAsync(IJiraClient jiraInstance, CancellationToken token = default(CancellationToken))
{
_jiraInstances.Add(jiraInstance);
- var projects = await jiraInstance.GetProjectsAsync(token).ConfigureAwait(false);
+ var projects = await jiraInstance.Project.GetAllAsync(cancellationToken: token).ConfigureAwait(false);
if (projects != null)
{
foreach (var project in projects)
{
- if (!_projectJiraApiMap.ContainsKey(project.Key))
+ if (!_projectJiraClientMap.ContainsKey(project.Key))
{
- _projectJiraApiMap.Add(project.Key, jiraInstance);
+ _projectJiraClientMap.Add(project.Key, jiraInstance);
}
}
}
@@ -141,10 +142,10 @@ namespace GreenshotJiraPlugin
{
try
{
- JiraApi jiraApi;
- if (_projectJiraApiMap.TryGetValue(jiraDetails.ProjectKey, out jiraApi))
+ IJiraClient jiraClient;
+ if (_projectJiraClientMap.TryGetValue(jiraDetails.ProjectKey, out jiraClient))
{
- var issue = await jiraApi.GetIssueAsync(jiraDetails.JiraKey).ConfigureAwait(false);
+ var issue = await jiraClient.Issue.GetAsync(jiraDetails.JiraKey).ConfigureAwait(false);
jiraDetails.JiraIssue = issue;
}
// Send event
@@ -178,9 +179,9 @@ namespace GreenshotJiraPlugin
var projectKey = jiraKeyParts[0];
var jiraId = jiraKeyParts[1];
- JiraApi jiraApi;
+ IJiraClient jiraClient;
// Check if we have a JIRA instance with a project for this key
- if (_projectJiraApiMap.TryGetValue(projectKey, out jiraApi))
+ if (_projectJiraClientMap.TryGetValue(projectKey, out jiraClient))
{
// We have found a project for this _jira key, so it must be a valid & known JIRA
JiraDetails currentJiraDetails;
@@ -207,8 +208,7 @@ namespace GreenshotJiraPlugin
if (_recentJiras.Count > _maxEntries)
{
// Add it to the list of recent Jiras
- IList clonedList = new List(_recentJiras.Values);
- _recentJiras = (from jiraDetails in clonedList
+ _recentJiras = (from jiraDetails in _recentJiras.Values.ToList()
orderby jiraDetails.SeenAt descending
select jiraDetails).Take(_maxEntries).ToDictionary(jd => jd.JiraKey, jd => jd);
}
diff --git a/GreenshotJiraPlugin/JiraPlugin.cs b/GreenshotJiraPlugin/JiraPlugin.cs
index a7240293e..ed26d888d 100644
--- a/GreenshotJiraPlugin/JiraPlugin.cs
+++ b/GreenshotJiraPlugin/JiraPlugin.cs
@@ -24,7 +24,9 @@ using Greenshot.IniFile;
using Greenshot.Plugin;
using System;
using System.Threading.Tasks;
-using Dapplo.Log.Facade;
+using Dapplo.Log;
+using Greenshot.Forms;
+using Greenshot.Helpers;
using GreenshotJiraPlugin.Forms;
using GreenshotPlugin.Core;
using log4net;
@@ -57,6 +59,22 @@ namespace GreenshotJiraPlugin {
public JiraPlugin() {
_instance = this;
+ // Added to prevent Greenshot from shutting down when there was an exception in a Task
+ TaskScheduler.UnobservedTaskException += (sender, args) =>
+ {
+ try
+ {
+ Exception exceptionToLog = args.Exception;
+ string exceptionText = EnvironmentInfo.BuildReport(exceptionToLog);
+ Log.Error("Exception caught in the UnobservedTaskException handler.");
+ Log.Error(exceptionText);
+ new BugReportForm(exceptionText).ShowDialog();
+ }
+ finally
+ {
+ args.SetObserved();
+ }
+ };
}
public IEnumerable Destinations() {
diff --git a/GreenshotJiraPlugin/Log4NetLogger.cs b/GreenshotJiraPlugin/Log4NetLogger.cs
index 1b7ce2661..3018a8823 100644
--- a/GreenshotJiraPlugin/Log4NetLogger.cs
+++ b/GreenshotJiraPlugin/Log4NetLogger.cs
@@ -19,7 +19,7 @@
* along with this program. If not, see .
*/
-using Dapplo.Log.Facade;
+using Dapplo.Log;
using log4net;
namespace GreenshotJiraPlugin
diff --git a/GreenshotJiraPlugin/SvgBitmapHttpContentConverter.cs b/GreenshotJiraPlugin/SvgBitmapHttpContentConverter.cs
deleted file mode 100644
index 47b3a24d1..000000000
--- a/GreenshotJiraPlugin/SvgBitmapHttpContentConverter.cs
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: http://getgreenshot.org/
- * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using Dapplo.HttpExtensions;
-using Dapplo.HttpExtensions.ContentConverter;
-using Dapplo.HttpExtensions.Extensions;
-using Dapplo.HttpExtensions.Support;
-using Dapplo.Log.Facade;
-using System.Net.Http;
-using System.Net.Http.Headers;
-
-namespace GreenshotJiraPlugin
-{
- ///
- /// This adds SVG image support for the Jira Plugin
- ///
- public class SvgBitmapHttpContentConverter : IHttpContentConverter
- {
- private static readonly LogSource Log = new LogSource();
- private static readonly IList SupportedContentTypes = new List();
-
- static SvgBitmapHttpContentConverter()
- {
- SupportedContentTypes.Add(MediaTypes.Svg.EnumValueOf());
- }
-
- ///
- public int Order => 0;
-
- public int Width { get; set; }
-
- public int Height { get; set; }
-
- ///
- /// This checks if the HttpContent can be converted to a Bitmap and is assignable to the specified Type
- ///
- /// This should be something we can assign Bitmap to
- /// HttpContent to process
- /// true if it can convert
- public bool CanConvertFromHttpContent(Type typeToConvertTo, HttpContent httpContent)
- {
- if (typeToConvertTo == typeof(object) || !typeToConvertTo.IsAssignableFrom(typeof(Bitmap)))
- {
- return false;
- }
- var httpBehaviour = HttpBehaviour.Current;
- return !httpBehaviour.ValidateResponseContentType || SupportedContentTypes.Contains(httpContent.GetContentType());
- }
-
- ///
- public async Task