Merge pull request #1 from greenshot/release/1.2.9BF2

Release/1.2.9 bf2
This commit is contained in:
XCL 2017-01-25 23:30:33 +08:00 committed by GitHub
commit f65b86f165
34 changed files with 357 additions and 361 deletions

View file

@ -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);

View file

@ -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))

View file

@ -56,9 +56,10 @@ namespace Greenshot.Drawing
/// <summary>
/// Restore the target gripper
/// </summary>
/// <param name="context"></param>
protected override void OnDeserialized(StreamingContext context)
/// <param name="streamingContext">StreamingContext</param>
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);
}

View file

@ -272,8 +272,11 @@ namespace Greenshot.Drawing
_parent.Controls.Add(_textBox);
}
EnsureTextBoxContrast();
_textBox.Show();
_textBox.Focus();
if (_textBox != null)
{
_textBox.Show();
_textBox.Focus();
}
}
/// <summary>
@ -281,6 +284,10 @@ namespace Greenshot.Drawing
/// </summary>
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
/// </summary>
private void UpdateTextBoxPosition()
{
if (_textBox == null)
{
return;
}
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
int lineWidth = (int)Math.Floor(lineThickness / 2d);

View file

@ -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;
}

View file

@ -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 {
/// <summary>
/// The Contextmenu_OpenRecent currently opens the last know save location
/// </summary>
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);

View file

@ -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);
}

View file

@ -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<CoreConfiguration>();
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;

View file

@ -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:

View file

@ -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<IDestination> 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) {

View file

@ -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);
}
}
}

View file

@ -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

View file

@ -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<JiraConfiguration>();
private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>();
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);

View file

@ -34,32 +34,42 @@
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<ItemGroup>
<Reference Include="Dapplo.HttpExtensions, Version=0.5.43.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Dapplo.HttpExtensions.0.5.43\lib\net45\Dapplo.HttpExtensions.dll</HintPath>
<Reference Include="Dapplo.HttpExtensions, Version=0.6.17.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Dapplo.HttpExtensions.0.6.17\lib\net45\Dapplo.HttpExtensions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Dapplo.Jira, Version=0.1.65.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Dapplo.Jira.0.1.65\lib\net45\Dapplo.Jira.dll</HintPath>
<Reference Include="Dapplo.Jira, Version=0.5.8.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Dapplo.Jira.0.5.8\lib\net45\Dapplo.Jira.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Dapplo.Log.Facade, Version=0.5.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Dapplo.Log.Facade.0.5.4\lib\net45\Dapplo.Log.Facade.dll</HintPath>
<Reference Include="Dapplo.Log, Version=1.0.23.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Dapplo.Log.1.0.23\lib\net45\Dapplo.Log.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="log4net">
<HintPath>..\Greenshot\Lib\log4net.dll</HintPath>
</Reference>
<Reference Include="Svg, Version=2.2.1.38382, Culture=neutral, PublicKeyToken=12a0bac221edeae2, processorArchitecture=MSIL">
<HintPath>..\packages\Svg.2.2.2\lib\net35\Svg.dll</HintPath>
<Reference Include="Microsoft.VisualBasic" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="Svg, Version=2.2.1.39233, Culture=neutral, PublicKeyToken=12a0bac221edeae2, processorArchitecture=MSIL">
<HintPath>..\packages\Svg.2.3.0\lib\net35\Svg.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Runtime.Caching" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Web.Services" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="AsyncMemoryCache.cs" />
@ -94,7 +104,6 @@
<Compile Include="LanguageKeys.cs" />
<Compile Include="Log4NetLogger.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SvgBitmapHttpContentConverter.cs" />
<Compile Include="SvgImage.cs" />
<None Include="Languages\language_jiraplugin-de-DE.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>

View file

@ -33,11 +33,11 @@ namespace GreenshotJiraPlugin
/// </summary>
public class IssueTypeBitmapCache : AsyncMemoryCache<IssueType, Bitmap>
{
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<Bitmap> CreateAsync(IssueType issueType, CancellationToken cancellationToken = new CancellationToken())
{
return await _jiraApi.GetUriContentAsync<Bitmap>(issueType.IconUri, cancellationToken).ConfigureAwait(false);
return await _jiraClient.Server.GetUriContentAsync<Bitmap>(issueType.IconUri, cancellationToken).ConfigureAwait(false);
}
}
}

View file

@ -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 {
/// <summary>
/// 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
/// </summary>
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();
/// <summary>
/// Initialize some basic stuff, in the case the SVG to bitmap converter
/// </summary>
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
/// </summary>
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
/// </summary>
/// <returns>true if login was done sucessfully</returns>
private async Task<bool> DoLoginAsync(string user, string password)
private async Task<bool> 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<Bitmap>(favIconUri);
FavIcon = await _jiraClient.Server.GetUriContentAsync<Bitmap>(favIconUri, cancellationToken);
}
catch (Exception ex)
{
@ -142,8 +137,8 @@ namespace GreenshotJiraPlugin {
/// If there are credentials, call the real login.
/// </summary>
/// <returns>Task</returns>
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 {
/// <summary>
/// End the session, if there was one
/// </summary>
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.
/// </summary>
/// <returns></returns>
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
/// </summary>
/// <returns>List with filters</returns>
public async Task<IList<Filter>> GetFavoriteFiltersAsync()
public async Task<IList<Filter>> GetFavoriteFiltersAsync(CancellationToken cancellationToken = default(CancellationToken))
{
await CheckCredentialsAsync();
return await _jiraApi.GetFavoriteFiltersAsync().ConfigureAwait(false);
await CheckCredentialsAsync(cancellationToken);
return await _jiraClient.Filter.GetFavoritesAsync(cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// Get the issue for a key
/// </summary>
/// <param name="issueKey">Jira issue key</param>
/// <param name="cancellationToken">CancellationToken</param>
/// <returns>Issue</returns>
public async Task<Issue> GetIssueAsync(string issueKey)
public async Task<Issue> 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 {
/// <returns></returns>
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 {
/// <param name="cancellationToken">CancellationToken</param>
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);
}
/// <summary>
@ -273,8 +269,8 @@ namespace GreenshotJiraPlugin {
/// <returns></returns>
public async Task<IList<Issue>> 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 {
/// <summary>
/// Get the base uri
/// </summary>
public Uri JiraBaseUri => _jiraApi.JiraBaseUri;
public Uri JiraBaseUri => _jiraClient.JiraBaseUri;
/// <summary>
/// Is the user "logged in?

View file

@ -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;
}

View file

@ -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<JiraApi> _jiraInstances = new List<JiraApi>();
private readonly IDictionary<string, JiraApi> _projectJiraApiMap = new Dictionary<string, JiraApi>();
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>();
/// <summary>
@ -92,10 +93,10 @@ namespace GreenshotJiraPlugin
/// Retrieve the API belonging to a JiraDetails
/// </summary>
/// <param name="jiraDetails"></param>
/// <returns>JiraAPI</returns>
public JiraApi GetJiraApiForKey(JiraDetails jiraDetails)
/// <returns>IJiraClient</returns>
public IJiraClient GetJiraClientForKey(JiraDetails jiraDetails)
{
return _projectJiraApiMap[jiraDetails.ProjectKey];
return _projectJiraClientMap[jiraDetails.ProjectKey];
}
/// <summary>
@ -116,17 +117,17 @@ namespace GreenshotJiraPlugin
/// </summary>
/// <param name="jiraInstance"></param>
/// <param name="token"></param>
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<JiraDetails> clonedList = new List<JiraDetails>(_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);
}

View file

@ -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<IDestination> Destinations() {

View file

@ -19,7 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Dapplo.Log.Facade;
using Dapplo.Log;
using log4net;
namespace GreenshotJiraPlugin

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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
{
/// <summary>
/// This adds SVG image support for the Jira Plugin
/// </summary>
public class SvgBitmapHttpContentConverter : IHttpContentConverter
{
private static readonly LogSource Log = new LogSource();
private static readonly IList<string> SupportedContentTypes = new List<string>();
static SvgBitmapHttpContentConverter()
{
SupportedContentTypes.Add(MediaTypes.Svg.EnumValueOf());
}
/// <inheritdoc />
public int Order => 0;
public int Width { get; set; }
public int Height { get; set; }
/// <summary>
/// This checks if the HttpContent can be converted to a Bitmap and is assignable to the specified Type
/// </summary>
/// <param name="typeToConvertTo">This should be something we can assign Bitmap to</param>
/// <param name="httpContent">HttpContent to process</param>
/// <returns>true if it can convert</returns>
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());
}
/// <inheritdoc />
public async Task<object> ConvertFromHttpContentAsync(Type resultType, HttpContent httpContent, CancellationToken cancellationToken = default(CancellationToken))
{
if (!CanConvertFromHttpContent(resultType, httpContent))
{
var exMessage = "CanConvertFromHttpContent resulted in false, ConvertFromHttpContentAsync is not supposed to be called.";
Log.Error().WriteLine(exMessage);
throw new NotSupportedException(exMessage);
}
using (var memoryStream = (MemoryStream) await StreamHttpContentConverter.Instance.ConvertFromHttpContentAsync(typeof(MemoryStream), httpContent, cancellationToken).ConfigureAwait(false))
{
Log.Debug().WriteLine("Creating a Bitmap from the SVG.");
var svgImage = new SvgImage(memoryStream)
{
Height = Height,
Width = Width
};
return svgImage.Image;
}
}
/// <inheritdoc />
public bool CanConvertToHttpContent(Type typeToConvert, object content)
{
return false;
}
/// <inheritdoc />
public HttpContent ConvertToHttpContent(Type typeToConvert, object content)
{
return null;
}
/// <inheritdoc />
public void AddAcceptHeadersForType(Type resultType, HttpRequestMessage httpRequestMessage)
{
if (resultType == null)
{
throw new ArgumentNullException(nameof(resultType));
}
if (httpRequestMessage == null)
{
throw new ArgumentNullException(nameof(httpRequestMessage));
}
if (resultType == typeof(object) || !resultType.IsAssignableFrom(typeof(Bitmap)))
{
return;
}
httpRequestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(MediaTypes.Svg.EnumValueOf()));
Log.Debug().WriteLine("Modified the header(s) of the HttpRequestMessage: Accept: {0}", httpRequestMessage.Headers.Accept);
}
}
}

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Dapplo.HttpExtensions" version="0.5.43" targetFramework="net45" />
<package id="Dapplo.Jira" version="0.1.65" targetFramework="net45" />
<package id="Dapplo.Log.Facade" version="0.5.4" targetFramework="net45" />
<package id="Dapplo.HttpExtensions" version="0.6.17" targetFramework="net45" />
<package id="Dapplo.Jira" version="0.5.8" targetFramework="net45" />
<package id="Dapplo.Log" version="1.0.23" targetFramework="net45" />
<package id="LibZ.Tool" version="1.2.0.0" targetFramework="net45" />
<package id="Svg" version="2.2.2" targetFramework="net45" />
<package id="Svg" version="2.3.0" targetFramework="net45" />
</packages>

View file

@ -20,7 +20,6 @@
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
@ -48,15 +47,6 @@ namespace GreenshotPlugin.Controls {
private static int _hotKeyCounter = 1;
private const uint WM_HOTKEY = 0x312;
private static IntPtr _hotkeyHwnd;
// static HotkeyControl() {
// StringBuilder keyName = new StringBuilder();
// for(uint sc = 0; sc < 500; sc++) {
// if (GetKeyNameText(sc << 16, keyName, 100) != 0) {
// LOG.DebugFormat("SC {0} = {1}", sc, keyName);
// }
// }
// }
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum Modifiers : uint {
@ -96,8 +86,8 @@ namespace GreenshotPlugin.Controls {
// ArrayLists used to enforce the use of proper modifiers.
// Shift+A isn't a valid hotkey, for instance, as it would screw up when the user is typing.
private readonly ArrayList _needNonShiftModifier;
private readonly ArrayList _needNonAltGrModifier;
private readonly IList<int> _needNonShiftModifier = new List<int>();
private readonly IList<int> _needNonAltGrModifier = new List<int>();
private readonly ContextMenu _dummy = new ContextMenu();
@ -138,9 +128,6 @@ namespace GreenshotPlugin.Controls {
KeyUp += HotkeyControl_KeyUp;
KeyDown += HotkeyControl_KeyDown;
// Fill the ArrayLists that contain all invalid hotkey combinations
_needNonShiftModifier = new ArrayList();
_needNonAltGrModifier = new ArrayList();
PopulateModifierLists();
}
@ -180,8 +167,6 @@ namespace GreenshotPlugin.Controls {
_needNonShiftModifier.Add((int)Keys.Return);
_needNonShiftModifier.Add((int)Keys.Escape);
_needNonShiftModifier.Add((int)Keys.NumLock);
_needNonShiftModifier.Add((int)Keys.Scroll);
_needNonShiftModifier.Add((int)Keys.Pause);
// Ctrl+Alt + 0 - 9
for (Keys k = Keys.D0; k <= Keys.D9; k++) {

View file

@ -68,6 +68,7 @@ namespace GreenshotPlugin.Controls {
ApplyFilterOptions();
string initialDirectory = null;
try {
conf.ValidateAndCorrectOutputFileAsFullpath();
initialDirectory = Path.GetDirectoryName(conf.OutputFileAsFullpath);
} catch {
LOG.WarnFormat("OutputFileAsFullpath was set to {0}, ignoring due to problem in path.", conf.OutputFileAsFullpath);
@ -90,12 +91,12 @@ namespace GreenshotPlugin.Controls {
PrepareFilterOptions();
string fdf = "";
int preselect = 0;
var outputFileFormatAsString = Enum.GetName(typeof(OutputFormat), conf.OutputFileFormat);
var outputFileFormatAsString = Enum.GetName(typeof(OutputFormat), conf.OutputFileFormat);
for(int i=0; i<_filterOptions.Length; i++){
FilterOption fo = _filterOptions[i];
fdf += fo.Label + "|*." + fo.Extension + "|";
if(outputFileFormatAsString == fo.Extension)
preselect = i;
if(outputFileFormatAsString == fo.Extension)
preselect = i;
}
fdf = fdf.Substring(0, fdf.Length-1);
SaveFileDialog.Filter = fdf;

View file

@ -813,10 +813,10 @@ EndSelection:<<<<<<<4
string[] dropFileNames = (string[]) dataObject.GetData(DataFormats.FileDrop);
if (dropFileNames != null && dropFileNames.Length > 0)
{
return dropFileNames.Where(filename => !string.IsNullOrEmpty(filename))
return dropFileNames
.Where(filename => !string.IsNullOrEmpty(filename))
.Where(Path.HasExtension)
.Select(filename => Path.GetExtension(filename).ToLowerInvariant())
.Where(ext => ImageHelper.StreamConverters.Keys.Contains(ext));
.Where(filename => ImageHelper.StreamConverters.Keys.Contains(Path.GetExtension(filename).ToLowerInvariant().Substring(1)));
}
return Enumerable.Empty<string>();
}

View file

@ -274,6 +274,9 @@ namespace GreenshotPlugin.Core {
[IniProperty("LastCapturedRegion", Description = "The last used region, for reuse in the capture last region")]
public Rectangle LastCapturedRegion { get; set; }
[IniProperty("Win10BorderCrop", Description = "The capture is cropped with these settings, e.g. when you don't want to color around it -1,-1"), DefaultValue("0,0")]
public Size Win10BorderCrop { get; set; }
private Size _iconSize;
[IniProperty("IconSize", Description = "Defines the size of the icons (e.g. for the buttons in the editor), default value 16,16 anything bigger will cause scaling", DefaultValue = "16,16")]
public Size IconSize {
@ -350,9 +353,8 @@ namespace GreenshotPlugin.Core {
case "OutputFileAsFullpath":
if (IniConfig.IsPortable) {
return Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots\dummy.png");
} else {
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop),"dummy.png");
}
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop),"dummy.png");
case "OutputFilePath":
if (IniConfig.IsPortable) {
string pafOutputFilePath = Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots");
@ -523,13 +525,27 @@ namespace GreenshotPlugin.Core {
if (WebRequestReadWriteTimeout < 1) {
WebRequestReadWriteTimeout = 100;
}
}
// Added for BUG-1992, reset the OutputFilePath / OutputFileAsFullpath if they don't exist (e.g. the configuration is used on a different PC)
/// <summary>
/// Validate the OutputFilePath, and if this is not correct it will be set to the default
/// Added for BUG-1992, reset the OutputFilePath / OutputFileAsFullpath if they don't exist (e.g. the configuration is used on a different PC)
/// </summary>
public void ValidateAndCorrectOutputFilePath()
{
if (!Directory.Exists(OutputFilePath))
{
OutputFilePath = GetDefault(nameof(OutputFilePath)) as string;
}
if (!File.Exists(OutputFileAsFullpath))
}
/// <summary>
/// Validate the OutputFileAsFullpath, and if this is not correct it will be set to the default
/// Added for BUG-1992, reset the OutputFilePath / OutputFileAsFullpath if they don't exist (e.g. the configuration is used on a different PC)
/// </summary>
public void ValidateAndCorrectOutputFileAsFullpath()
{
var outputFilePath = Path.GetDirectoryName(OutputFileAsFullpath);
if (outputFilePath == null || (!File.Exists(OutputFileAsFullpath) && !Directory.Exists(outputFilePath)))
{
OutputFileAsFullpath = GetDefault(nameof(OutputFileAsFullpath)) as string;
}

View file

@ -0,0 +1,54 @@
using System;
using System.Diagnostics;
using System.IO;
namespace GreenshotPlugin.Core
{
/// <summary>
/// Simple utility for the explorer
/// </summary>
public static class ExplorerHelper
{
/// <summary>
/// Open the path in the windows explorer.
/// If the path is a directory, it will just open the explorer with that directory.
/// If the path is a file, the explorer is opened with the directory and the file is selected.
/// </summary>
/// <param name="path">Path to file or directory</param>
public static bool OpenInExplorer(string path)
{
if (path == null)
{
return false;
}
try
{
// Check if path is a directory
if (Directory.Exists(path))
{
using (Process.Start(path))
{
return true;
}
}
// 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);
return true;
}
}
}
catch (Exception ex)
{
// Make sure we show what we tried to open in the exception
ex.Data.Add("path", path);
throw;
}
return false;
}
}
}

View file

@ -105,7 +105,7 @@ namespace GreenshotPlugin.Core {
bool useMemoryStream = false;
MemoryStream memoryStream = null;
if (outputSettings.Format == OutputFormat.greenshot && surface == null) {
throw new ArgumentException("Surface needs to be se when using OutputFormat.Greenshot");
throw new ArgumentException("Surface needs to be set when using OutputFormat.Greenshot");
}
try {

View file

@ -770,7 +770,7 @@ namespace GreenshotPlugin.Core {
{
// Somehow DWM doesn't calculate it corectly, there is a 1 pixel border around the capture
// Remove this border, currently it's fixed but TODO: Make it depend on the OS?
windowRect.Inflate(-1, -1);
windowRect.Inflate(Conf.Win10BorderCrop);
_previousWindowRectangle = windowRect;
_lastWindowRectangleRetrieveTime = now;
return windowRect;
@ -1001,7 +1001,7 @@ namespace GreenshotPlugin.Core {
// TODO: Also 8.x?
if (Environment.OSVersion.IsWindows10())
{
captureRectangle.Inflate(-1, -1);
captureRectangle.Inflate(Conf.Win10BorderCrop);
}
if (autoMode) {
@ -1250,11 +1250,13 @@ namespace GreenshotPlugin.Core {
size = result ? new Size((int)windowInfo.cxWindowBorders, (int)windowInfo.cyWindowBorders) : Size.Empty;
return result;
}
/// <summary>
/// Set the window as foreground window
/// </summary>
public static void ToForeground(IntPtr handle)
/// <param name="handle">hWnd of the window to bring to the foreground</param>
/// <param name="workaround">bool with true to use a trick to really bring the window to the foreground</param>
public static void ToForeground(IntPtr handle, bool workaround = true)
{
// Do nothing if the window is already in the foreground
if (User32.GetForegroundWindow() == handle)
@ -1266,10 +1268,14 @@ namespace GreenshotPlugin.Core {
const int EXTENDEDKEY = 0x1;
const int KEYUP = 0x2;
// Simulate an "ALT" key press.
User32.keybd_event(ALT, 0x45, EXTENDEDKEY | 0, 0);
// Simulate an "ALT" key release.
User32.keybd_event(ALT, 0x45, EXTENDEDKEY | KEYUP, 0);
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms633539(v=vs.85).aspx
if (workaround)
{
// Simulate an "ALT" key press.
User32.keybd_event(ALT, 0x45, EXTENDEDKEY | 0, 0);
// Simulate an "ALT" key release.
User32.keybd_event(ALT, 0x45, EXTENDEDKEY | KEYUP, 0);
}
// Show window in forground.
User32.SetForegroundWindow(handle);
@ -1278,8 +1284,9 @@ namespace GreenshotPlugin.Core {
/// <summary>
/// Set the window as foreground window
/// </summary>
public void ToForeground() {
ToForeground(Handle);
/// <param name="workaround">true to use a workaround, otherwise the window might only flash</param>
public void ToForeground(bool workaround = true) {
ToForeground(Handle, workaround);
}
/// <summary>

View file

@ -47,6 +47,7 @@
<Compile Include="Controls\GreenshotRadioButton.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Core\ExplorerHelper.cs" />
<Compile Include="Effects\AdjustEffect.cs" />
<Compile Include="Effects\BorderEffect.cs" />
<Compile Include="Core\CaptureHandler.cs" />

View file

@ -98,8 +98,15 @@ namespace Greenshot.Plugin {
ReduceColors = reduceColors;
}
public SurfaceOutputSettings PreventGreenshotFormat() {
if (Format == OutputFormat.greenshot) {
/// <summary>
/// BUG-2056 reported a logical issue, using greenshot format as the default causes issues with the external commands.
/// </summary>
/// <returns>this for fluent API usage</returns>
public SurfaceOutputSettings PreventGreenshotFormat()
{
// If OutputFormat is Greenshot, use PNG instead.
if (Format == OutputFormat.greenshot)
{
Format = OutputFormat.png;
}
return this;

View file

@ -171,11 +171,16 @@ namespace GreenshotPlugin.UnmanagedHelpers {
/// </summary>
/// <param name="radius"></param>
/// <returns>false if blur is not possible</returns>
public static bool IsBlurPossible(int radius) {
public static bool IsBlurPossible(int radius)
{
if (!_isBlurEnabled) {
return false;
}
return Environment.OSVersion.Version.Minor < 2 || radius >= 20;
if (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor < 2)
{
return true;
}
return Environment.OSVersion.Version.Major > 6 && radius >= 20;
}
/// <summary>

View file

@ -70,8 +70,11 @@ namespace GreenshotWin10Plugin
using (var logoStream = new MemoryRandomAccessStream())
using (var thumbnailStream = new MemoryRandomAccessStream())
{
var outputSettings = new SurfaceOutputSettings();
outputSettings.PreventGreenshotFormat();
// Create capture for export
ImageOutput.SaveToStream(surface, imageStream, new SurfaceOutputSettings());
ImageOutput.SaveToStream(surface, imageStream, outputSettings);
imageStream.Position = 0;
Log.Info("Created RandomAccessStreamReference for the image");
var imageRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(imageStream);
@ -83,7 +86,7 @@ namespace GreenshotWin10Plugin
{
using (var thumbnail = ImageHelper.CreateThumbnail(tmpImageForThumbnail, 240, 160))
{
ImageOutput.SaveToStream(thumbnail, null, thumbnailStream, new SurfaceOutputSettings());
ImageOutput.SaveToStream(thumbnail, null, thumbnailStream, outputSettings);
thumbnailStream.Position = 0;
thumbnailRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(thumbnailStream);
Log.Info("Created RandomAccessStreamReference for the thumbnail");
@ -94,7 +97,7 @@ namespace GreenshotWin10Plugin
{
using (var logoThumbnail = ImageHelper.CreateThumbnail(logo, 30, 30))
{
ImageOutput.SaveToStream(logoThumbnail, null, logoStream, new SurfaceOutputSettings());
ImageOutput.SaveToStream(logoThumbnail, null, logoStream, outputSettings);
logoStream.Position = 0;
logoRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(logoStream);
Log.Info("Created RandomAccessStreamReference for the logo");

View file

@ -1,7 +1,7 @@
version: 1.2.9.{build}
branches:
only:
- release/1.2.9
- release/1.2.9BF2
skip_tags: true
configuration: Release
platform: Any CPU