diff --git a/Greenshot-OCR-Plugin/Greenshot-OCR-Plugin.csproj b/Greenshot-OCR-Plugin/Greenshot-OCR-Plugin.csproj index 2dd1dc941..76d1060f3 100644 --- a/Greenshot-OCR-Plugin/Greenshot-OCR-Plugin.csproj +++ b/Greenshot-OCR-Plugin/Greenshot-OCR-Plugin.csproj @@ -1,4 +1,5 @@ - + + {C6988EE8-2FEE-4349-9F09-F9628A0D8965} Debug @@ -15,13 +16,6 @@ false OnBuildSuccess - - x86 - False - Auto - 4194304 - 4096 - bin\Debug\ true @@ -29,6 +23,11 @@ False True DEBUG;TRACE + False + Auto + 4194304 + x86 + 4096 bin\Release\ @@ -36,6 +35,11 @@ None True False + False + Auto + 4194304 + AnyCPU + 4096 @@ -51,6 +55,7 @@ + @@ -63,9 +68,13 @@ Always + + Always + Always + diff --git a/Greenshot-OCR-Plugin/Language.cs b/Greenshot-OCR-Plugin/Language.cs index dc7a65d4a..4f4a441f2 100644 --- a/Greenshot-OCR-Plugin/Language.cs +++ b/Greenshot-OCR-Plugin/Language.cs @@ -19,11 +19,7 @@ * along with this program. If not, see . */ using System; -using System.Diagnostics; -using System.Globalization; -using System.Resources; using System.Threading; - using GreenshotPlugin.Core; namespace GreenshotOCR { diff --git a/Greenshot-OCR-Plugin/Languages/language_ocrplugin-fr-FR.xml b/Greenshot-OCR-Plugin/Languages/language_ocrplugin-fr-FR.xml new file mode 100644 index 000000000..e2d9b4dad --- /dev/null +++ b/Greenshot-OCR-Plugin/Languages/language_ocrplugin-fr-FR.xml @@ -0,0 +1,14 @@ + + + + + Langage pour l'OCR + + + Orienter l'image + + + Redresser l'image + + + \ No newline at end of file diff --git a/Greenshot-OCR-Plugin/Languages/language_ocrplugin-zh-CN.xml b/Greenshot-OCR-Plugin/Languages/language_ocrplugin-zh-CN.xml new file mode 100644 index 000000000..24ab22537 --- /dev/null +++ b/Greenshot-OCR-Plugin/Languages/language_ocrplugin-zh-CN.xml @@ -0,0 +1,14 @@ + + + + + OCR语言 + + + 图像定位 + + + 图像矫正 + + + \ No newline at end of file diff --git a/Greenshot-OCR-Plugin/ModiInterop.cs b/Greenshot-OCR-Plugin/ModiInterop.cs index eebe230c2..ce93923ac 100644 --- a/Greenshot-OCR-Plugin/ModiInterop.cs +++ b/Greenshot-OCR-Plugin/ModiInterop.cs @@ -19,11 +19,9 @@ * along with this program. If not, see . */ using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; using System.Collections; using Greenshot.Interop; - + namespace GreenshotOCR { [ComProgId("MODI.Document")] public interface ModiDocu : Common { @@ -33,6 +31,7 @@ namespace GreenshotOCR { } void Create(string file); void OCR(ModiLanguage language, bool Orientimage, bool StraightenImage); + void SaveAs(string filename, FileFormat fileFormat, CompressionLevel compressionLevel); } public interface Common : IDisposable { @@ -84,4 +83,16 @@ namespace GreenshotOCR { TURKISH = 31, SYSDEFAULT = 2048 } + + public enum CompressionLevel { + miCOMP_LEVEL_LOW = 0, + miCOMP_LEVEL_MEDIUM = 1, + miCOMP_LEVEL_HIGH = 2 + } + public enum FileFormat { + miFILE_FORMAT_DEFAULTVALUE = -1, + miFILE_FORMAT_TIFF = 1, + miFILE_FORMAT_TIFF_LOSSLESS = 2, + miFILE_FORMAT_MDI = 4 + } } diff --git a/Greenshot-OCR-Plugin/OCRConfiguration.cs b/Greenshot-OCR-Plugin/OCRConfiguration.cs index 63707c085..71b762e2b 100644 --- a/Greenshot-OCR-Plugin/OCRConfiguration.cs +++ b/Greenshot-OCR-Plugin/OCRConfiguration.cs @@ -19,8 +19,7 @@ * along with this program. If not, see . */ using System; -using System.Collections.Generic; -using GreenshotPlugin.Core; +using IniFile; namespace GreenshotOCR { /// diff --git a/Greenshot/Helpers/ImageHelper.cs b/Greenshot-OCR-Plugin/OCRDestination.cs similarity index 52% rename from Greenshot/Helpers/ImageHelper.cs rename to Greenshot-OCR-Plugin/OCRDestination.cs index 27007932f..cf254c0c2 100644 --- a/Greenshot/Helpers/ImageHelper.cs +++ b/Greenshot-OCR-Plugin/OCRDestination.cs @@ -20,35 +20,47 @@ */ using System; using System.Drawing; +using System.IO; +using System.Windows.Forms; -namespace Greenshot.Helpers { +using Greenshot.Interop; +using Greenshot.Plugin; +using GreenshotPlugin.Controls; +using GreenshotPlugin.Core; +using IniFile; + +namespace GreenshotOCR { /// - /// Description of ImageHelper. + /// Description of OCRDestination. /// - public class ImageHelper { - private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ImageHelper)); + public class OCRDestination : AbstractDestination { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OCRDestination)); + private static OCRConfiguration config = IniConfig.GetIniSection(); + private const int MIN_WIDTH = 130; + private const int MIN_HEIGHT = 130; + private ILanguage lang = Language.GetInstance(); - private ImageHelper() { + public override string Designation { + get { + return "OCR"; + } } - /// - /// Crops the image to the specified rectangle - /// - /// Image to crop - /// Rectangle with bitmap coordinates, will be "intersected" to the bitmap - public static bool Crop(ref Image image, ref Rectangle cropRectangle) { - Image returnImage = null; - if (image != null && image is Bitmap && ((image.Width * image.Height) > 0)) { - cropRectangle.Intersect(new Rectangle(0,0, image.Width, image.Height)); - if (cropRectangle.Width != 0 || cropRectangle.Height != 0) { - returnImage = (image as Bitmap).Clone(cropRectangle, image.PixelFormat); - image.Dispose(); - image = returnImage; - return true; - } + public override string Description { + get { + return "OCR"; } - LOG.Warn("Can't crop a null/zero size image!"); - return false; + } + + public override bool isActive { + get { + return true; + } + } + + public override bool ExportCapture(ISurface surface, ICaptureDetails captureDetails) { + OcrPlugin.DoOCR(surface); + return true; } } } diff --git a/Greenshot-OCR-Plugin/OCRPlugin.cs b/Greenshot-OCR-Plugin/OCRPlugin.cs index 5563f7348..cf054880e 100644 --- a/Greenshot-OCR-Plugin/OCRPlugin.cs +++ b/Greenshot-OCR-Plugin/OCRPlugin.cs @@ -21,17 +21,15 @@ using System; using System.Collections.Generic; using System.Drawing; -using System.Drawing.Imaging; using System.IO; -using System.Reflection; -using System.Runtime.Serialization.Formatters.Binary; -using System.Text; using System.Windows.Forms; using Greenshot.Interop; using Greenshot.Plugin; using GreenshotPlugin.Controls; using GreenshotPlugin.Core; +using IniFile; + //using Microsoft.Win32; namespace GreenshotOCR { @@ -42,30 +40,36 @@ namespace GreenshotOCR { private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OcrPlugin)); private const string CONFIG_FILENAME = "ocr-config.properties"; - private IGreenshotPluginHost host; - private ICaptureHost captureHost = null; + private static IGreenshotHost host; + private static OCRConfiguration config; private PluginAttribute myAttributes; - private OCRConfiguration config; private ToolStripMenuItem ocrMenuItem = new ToolStripMenuItem(); private int hotkeyIdentifier = 0; public OcrPlugin() { } + public IEnumerable Destinations() { + yield break; + } + public IEnumerable Processors() { + yield break; + } + /// /// Implementation of the IGreenshotPlugin.Initialize /// /// Use the IGreenshotPluginHost interface to register events /// Use the ICaptureHost interface to register in the MainContextMenu /// My own attributes - public void Initialize(IGreenshotPluginHost host, ICaptureHost captureHost, PluginAttribute myAttributes) { + /// true if plugin is initialized, false if not (doesn't show) + public virtual bool Initialize(IGreenshotHost greenshotHost, PluginAttribute myAttributes) { LOG.Debug("Initialize called of " + myAttributes.Name); - this.host = (IGreenshotPluginHost)host; - this.captureHost = captureHost; + host = greenshotHost; this.myAttributes = myAttributes; if (!HasMODI()) { LOG.Warn("No MODI found!"); - return; + return false; } // Load configuration config = IniConfig.GetIniSection(); @@ -79,22 +83,8 @@ namespace GreenshotOCR { // Here we can hang ourselves to the main context menu! ocrMenuItem.Text = "Region OCR"; ocrMenuItem.Click += new System.EventHandler(MainMenuClick); - - ContextMenuStrip contextMenu = host.MainMenu; - bool addedItem = false; - - // Try to find a separator, so we insert ourselves before - for(int i=0; i < contextMenu.Items.Count; i++) { - if (contextMenu.Items[i].GetType() == typeof(ToolStripSeparator)) { - contextMenu.Items.Insert(i, ocrMenuItem); - addedItem = true; - break; - } - } - // If we didn't insert the item, we just add it... - if (!addedItem) { - contextMenu.Items.Add(ocrMenuItem); - } + PluginUtils.AddToContextMenu(host, ocrMenuItem); + return true; } /// @@ -138,7 +128,7 @@ namespace GreenshotOCR { private void StartOCRRegion() { LOG.Debug("Starting OCR!"); - captureHost.MakeCapture(CaptureMode.Region, false, new CaptureHandler(DoOCR)); + host.CaptureRegion(false, new OCRDestination()); } private void MyHotkeyHandler() { @@ -160,15 +150,10 @@ namespace GreenshotOCR { /// Has the Image and the capture details private const int MIN_WIDTH = 130; private const int MIN_HEIGHT = 130; - private void DoOCR(object sender, CaptureTakenEventArgs eventArgs) { - if (eventArgs.Capture.Image == null) { - return; - } - string file = host.GetFilename(OutputFormat.bmp, eventArgs.Capture.CaptureDetails); - string filePath = Path.Combine(Path.GetTempPath(),file); - - using (FileStream stream = File.Create(filePath)) { - Image capturedImage = eventArgs.Capture.Image; + public static void DoOCR(ISurface surface) { + string filePath = null; + + using (Image capturedImage = surface.GetImageForExport()) { if (capturedImage.Width < MIN_WIDTH || capturedImage.Height < MIN_HEIGHT) { LOG.Debug("Captured image is not big enough for OCR, growing image..."); int newWidth = Math.Max(capturedImage.Width, MIN_WIDTH); @@ -178,10 +163,10 @@ namespace GreenshotOCR { graphics.Clear(Color.White); graphics.DrawImage(capturedImage, Point.Empty); } - host.SaveToStream(tmpImage, stream, OutputFormat.bmp, 100); + filePath = host.SaveToTmpFile(tmpImage, OutputFormat.bmp, 100); } } else { - host.SaveToStream(capturedImage, stream, OutputFormat.bmp, 100); + filePath = host.SaveToTmpFile(capturedImage, OutputFormat.bmp, 100); } } @@ -227,7 +212,7 @@ namespace GreenshotOCR { } return true; } catch(Exception e) { - LOG.Debug("Error trying to initiate MODI:", e); + LOG.DebugFormat("Error trying to initiate MODI: {0}", e.Message); } LOG.InfoFormat("No Microsoft Office Document Imaging (MODI) found, disabling OCR"); return false; diff --git a/Greenshot-OCR-Plugin/SettingsForm.cs b/Greenshot-OCR-Plugin/SettingsForm.cs index 5c7d750f8..e73b1a44c 100644 --- a/Greenshot-OCR-Plugin/SettingsForm.cs +++ b/Greenshot-OCR-Plugin/SettingsForm.cs @@ -19,11 +19,7 @@ * along with this program. If not, see . */ using System; -using System.Collections.Generic; -using System.Drawing; using System.Windows.Forms; - -using GreenshotPlugin.Controls; using GreenshotPlugin.Core; namespace GreenshotOCR { diff --git a/Greenshot-RunAtOutput-Plugin/RunAtOutput.cs b/Greenshot-RunAtOutput-Plugin/RunAtOutput.cs deleted file mode 100644 index 488113f13..000000000 --- a/Greenshot-RunAtOutput-Plugin/RunAtOutput.cs +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Diagnostics; -using System.Drawing; -using System.Drawing.Imaging; -using System.IO; -using System.Text; -using System.Windows.Forms; -using System.Xml.Serialization; - -using Greenshot.Plugin; -using GreenshotPlugin.Core; - -namespace RunAtOutput { - /// - /// An Plugin to run commands after an image was written - /// - public class RunAtOutputPlugin : IGreenshotPlugin { - private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(RunAtOutputPlugin)); - private IGreenshotPluginHost host; - private ICaptureHost captureHost = null; - private PluginAttribute myAttributes; - private RunAtOutputConfiguration config; - - public RunAtOutputPlugin() { - } - - /// - /// Implementation of the IGreenshotPlugin.Initialize - /// - /// Use the IGreenshotPluginHost interface to register events - /// Use the ICaptureHost interface to register in the MainContextMenu - /// My own attributes - public virtual void Initialize(IGreenshotPluginHost pluginHost, ICaptureHost captureHost, PluginAttribute myAttributes) { - LOG.Debug("Initialize called of " + myAttributes.Name); - - this.host = (IGreenshotPluginHost)pluginHost; - this.captureHost = captureHost; - this.myAttributes = myAttributes; - this.host.OnImageOutput += new OnImageOutputHandler(ImageOutput); - - this.config = IniConfig.GetIniSection(); - } - - public virtual void Shutdown() { - LOG.Debug("Shutdown of " + myAttributes.Name); - this.host.OnImageOutput -= new OnImageOutputHandler(ImageOutput); - } - - /// - /// Implementation of the IPlugin.Configure - /// - public virtual void Configure() { - LOG.Debug("Configure called"); - new SettingsForm().ShowDialog(); - } - - /// - /// Handling of the OnImageOutputHandler event from the IGreenshotPlugin - /// - /// Has the FullPath to the image - private void ImageOutput(object sender, ImageOutputEventArgs eventArgs) { - LOG.Debug("ImageOutput called with full path: " + eventArgs.FullPath); - foreach(string commando in config.active) { - string commandline = config.commandlines[commando]; - string arguments = config.arguments[commando]; - if (commandline != null && commandline.Length > 0) { - Process p = new Process(); - p.StartInfo.FileName = commandline; - p.StartInfo.Arguments = String.Format(arguments, eventArgs.FullPath); - p.StartInfo.UseShellExecute = false; - p.StartInfo.RedirectStandardOutput = true; - LOG.Info("Starting : " + p.StartInfo.FileName + " " + p.StartInfo.Arguments); - p.Start(); - string output = p.StandardOutput.ReadToEnd(); - if (output != null && output.Trim().Length > 0) { - LOG.Info("Output:\n" + output); - } - LOG.Info("Finished : " + p.StartInfo.FileName + " " + p.StartInfo.Arguments); - } - } - } - } -} \ No newline at end of file diff --git a/Greenshot-TitleFix-Plugin/FixTitle.cs b/Greenshot-TitleFix-Plugin/FixTitle.cs deleted file mode 100644 index 0ec5badbe..000000000 --- a/Greenshot-TitleFix-Plugin/FixTitle.cs +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.IO; -using System.Text; -using System.Text.RegularExpressions; -using System.Windows.Forms; - -using Greenshot.Plugin; -using GreenshotPlugin.Core; - -namespace TitleFix { - /// - /// An example Plugin so developers can see how they can develop their own plugin - /// - public class TitleFix : IGreenshotPlugin { - private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(TitleFix)); - - private IGreenshotPluginHost host; - private ICaptureHost captureHost = null; - private PluginAttribute myAttributes; - private TitleFixConfiguration config = null; - - public TitleFix() { - } - - /// - /// Implementation of the IGreenshotPlugin.Initialize - /// - /// Use the IGreenshotPluginHost interface to register events - /// Use the ICaptureHost interface to register in the MainContextMenu - /// My own attributes - public virtual void Initialize(IGreenshotPluginHost pluginHost, ICaptureHost captureHost, PluginAttribute myAttributes) { - LOG.Debug("Initialize called of " + myAttributes.Name); - - this.host = (IGreenshotPluginHost)pluginHost; - this.captureHost = captureHost; - this.myAttributes = myAttributes; - - this.config = IniConfig.GetIniSection(); - - // check configuration - List corruptKeys = new List(); - foreach(string key in config.active) { - if (!config.matchers.ContainsKey(key) || !config.matchers.ContainsKey(key)) { - LOG.Warn("Key " + key + " not found, configuration is broken! Disabling this key!"); - corruptKeys.Add(key); - } - } - - // Fix configuration if needed - if(corruptKeys.Count > 0) { - foreach(string corruptKey in corruptKeys) { - // Removing any reference to the key - config.active.Remove(corruptKey); - config.matchers.Remove(corruptKey); - config.replacers.Remove(corruptKey); - } - config.IsDirty = true; - } - if(config.IsDirty) { - IniConfig.Save(); - } - - this.host.OnCaptureTaken += new OnCaptureTakenHandler(CaptureTaken); - } - - public virtual void Shutdown() { - LOG.Debug("Shutdown of " + myAttributes.Name); - this.host.OnCaptureTaken -= new OnCaptureTakenHandler(CaptureTaken); - } - - /// - /// Implementation of the IPlugin.Configure - /// - public virtual void Configure() { - LOG.Debug("Configure called"); - } - - /// - /// Implementation of the OnCaptureTaken event - /// - private void CaptureTaken(object sender, CaptureTakenEventArgs eventArgs) { - string title = eventArgs.Capture.CaptureDetails.Title; - LOG.Debug("Title before: " + title); - if (title != null && title.Length > 0) { - title = title.Trim(); - foreach(string titleIdentifier in config.active) { - string regexpString = config.matchers[titleIdentifier]; - string replaceString = config.replacers[titleIdentifier]; - if (regexpString != null && regexpString.Length > 0) { - Regex regex = new Regex(regexpString); - title = regex.Replace(title, replaceString); - } - } - } - LOG.Debug("Title after: " + title); - eventArgs.Capture.CaptureDetails.Title = title; - } - } -} \ No newline at end of file diff --git a/Greenshot-TitleFix-Plugin/TitleFixConfiguration.cs b/Greenshot-TitleFix-Plugin/TitleFixConfiguration.cs deleted file mode 100644 index 554e55630..000000000 --- a/Greenshot-TitleFix-Plugin/TitleFixConfiguration.cs +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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 GreenshotPlugin.Core; - -namespace TitleFix { - /// - /// Description of FlickrConfiguration. - /// - [IniSection("TitleFix", Description="Greenshot TitleFix Plugin configuration")] - public class TitleFixConfiguration : IniSection { - [IniProperty("ActiveFixes", Description="The fixes that are active.")] - public List active; - - [IniProperty("Matcher", Description="The regular expressions to match the title with.")] - public Dictionary matchers; - - [IniProperty("Replacer", Description="The replacements for the matchers.")] - public Dictionary replacers; - - /// - /// Supply values we can't put as defaults - /// - /// The property to return a default for - /// object with the default value for the supplied property - public override object GetDefault(string property) { - switch(property) { - case "ActiveFixes": - List activeDefaults = new List(); - activeDefaults.Add("Firefox"); - activeDefaults.Add("IE"); - activeDefaults.Add("Chrome"); - return activeDefaults; - case "Matcher": - Dictionary matcherDefaults = new Dictionary(); - matcherDefaults.Add("Firefox", " - Mozilla Firefox.*"); - matcherDefaults.Add("IE", " - Microsoft Internet Explorer.*"); - matcherDefaults.Add("Chrome", " - Google Chrome.*"); - return matcherDefaults; - case "Replacer": - Dictionary replacerDefaults = new Dictionary(); - replacerDefaults.Add("Firefox", ""); - replacerDefaults.Add("IE", ""); - replacerDefaults.Add("Chrome", ""); - return replacerDefaults; - } - return null; - } - } -} \ No newline at end of file diff --git a/Greenshot/AssemblyInfo.cs.template b/Greenshot/AssemblyInfo.cs.template index a5861768b..071f4e981 100644 --- a/Greenshot/AssemblyInfo.cs.template +++ b/Greenshot/AssemblyInfo.cs.template @@ -19,7 +19,6 @@ * along with this program. If not, see . */ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // Information about this assembly is defined by the following @@ -48,4 +47,4 @@ using System.Runtime.InteropServices; // You can specify all values by your own or you can build default build and revision // numbers with the '*' character (the default): -[assembly: AssemblyVersion("0.8.1.$WCREV$")] +[assembly: AssemblyVersion("0.9.0.$WCREV$")] diff --git a/Greenshot/Configuration/AppConfig.cs b/Greenshot/Configuration/AppConfig.cs index 8bb36c843..19969af63 100644 --- a/Greenshot/Configuration/AppConfig.cs +++ b/Greenshot/Configuration/AppConfig.cs @@ -19,25 +19,17 @@ * along with this program. If not, see . */ using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.IO; -using System.Reflection; -using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Text.RegularExpressions; -using System.Threading; using System.Windows.Forms; -using Greenshot.Drawing; -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using Greenshot.UnmanagedHelpers; -using GreenshotPlugin.Controls; +using GreenshotPlugin.UnmanagedHelpers; using GreenshotPlugin.Core; +using Greenshot.Plugin; +using IniFile; namespace Greenshot.Configuration { public enum ScreenshotDestinations {Editor=1, FileDefault=2, FileWithDialog=4, Clipboard=8, Printer=16, EMail=32} @@ -183,22 +175,22 @@ namespace Greenshot.Configuration { } coreConfiguration.CaptureDelay = delay; if ((appConfig.Output_Destinations & ScreenshotDestinations.Clipboard) == ScreenshotDestinations.Clipboard) { - coreConfiguration.OutputDestinations.Add(Destination.Clipboard); + coreConfiguration.OutputDestinations.Add("Clipboard"); } if ((appConfig.Output_Destinations & ScreenshotDestinations.Editor) == ScreenshotDestinations.Editor) { - coreConfiguration.OutputDestinations.Add(Destination.Editor); + coreConfiguration.OutputDestinations.Add("Editor"); } if ((appConfig.Output_Destinations & ScreenshotDestinations.EMail) == ScreenshotDestinations.EMail) { - coreConfiguration.OutputDestinations.Add(Destination.EMail); + coreConfiguration.OutputDestinations.Add("EMail"); } if ((appConfig.Output_Destinations & ScreenshotDestinations.Printer) == ScreenshotDestinations.Printer) { - coreConfiguration.OutputDestinations.Add(Destination.Printer); + coreConfiguration.OutputDestinations.Add("Printer"); } if ((appConfig.Output_Destinations & ScreenshotDestinations.FileDefault) == ScreenshotDestinations.FileDefault) { - coreConfiguration.OutputDestinations.Add(Destination.FileDefault); + coreConfiguration.OutputDestinations.Add("File"); } if ((appConfig.Output_Destinations & ScreenshotDestinations.FileWithDialog) == ScreenshotDestinations.FileWithDialog) { - coreConfiguration.OutputDestinations.Add(Destination.FileWithDialog); + coreConfiguration.OutputDestinations.Add("FileWithDialog"); } IniConfig.Save(); } catch (Exception e) { diff --git a/Greenshot/Configuration/EditorConfiguration.cs b/Greenshot/Configuration/EditorConfiguration.cs index 0193ae0a2..598951e36 100644 --- a/Greenshot/Configuration/EditorConfiguration.cs +++ b/Greenshot/Configuration/EditorConfiguration.cs @@ -21,15 +21,10 @@ using System; using System.Collections.Generic; using System.Drawing; -using System.Drawing.Imaging; -using System.IO; -using System.Windows.Forms; -using Greenshot.Drawing; using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using Greenshot.UnmanagedHelpers; -using GreenshotPlugin.Core; +using GreenshotPlugin.UnmanagedHelpers; +using IniFile; namespace Greenshot.Configuration { /// @@ -56,19 +51,8 @@ namespace Greenshot.Configuration { [IniProperty("WindowNormalPosition", Description="Position of normal window", DefaultValue="100,100,400,400")] public Rectangle WindowNormalPosition; - /// - /// Supply values we can't put as defaults - /// - /// The property to return a default for - /// object with the default value for the supplied property - public override object GetDefault(string property) { - switch(property) { - case "RecentColors": - return new List(); - } - return null; - } - + [IniProperty("SuppressSaveDialogAtClose", Description="Suppressed the 'do you want to save' dialog when closing the editor.", DefaultValue="False")] + public bool SuppressSaveDialogAtClose; /// Type of the class for which to create the field /// FieldType of the field to construct /// FieldType of the field to construct diff --git a/Greenshot/Configuration/Language.cs b/Greenshot/Configuration/Language.cs index 67dd29abb..aceaec5c0 100644 --- a/Greenshot/Configuration/Language.cs +++ b/Greenshot/Configuration/Language.cs @@ -19,15 +19,8 @@ * along with this program. If not, see . */ using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Text; -using System.Threading; -using System.Windows.Forms; -using System.Xml; - using GreenshotPlugin.Core; +using IniFile; namespace Greenshot.Configuration { /// @@ -36,18 +29,25 @@ namespace Greenshot.Configuration { public class Language : LanguageContainer, ILanguage { private static ILanguage uniqueInstance; private const string LANGUAGE_FILENAME_PATTERN = @"language-*.xml"; - private static CoreConfiguration conf = IniConfig.GetIniSection(); public static ILanguage GetInstance() { + return GetInstance(true); + } + + public static ILanguage GetInstance(bool freeResources) { if(uniqueInstance == null) { uniqueInstance = new LanguageContainer(); uniqueInstance.LanguageFilePattern = LANGUAGE_FILENAME_PATTERN; uniqueInstance.Load(); + CoreConfiguration conf = IniConfig.GetIniSection(); if (string.IsNullOrEmpty(conf.Language)) { uniqueInstance.SynchronizeLanguageToCulture(); } else { uniqueInstance.SetLanguage(conf.Language); } + if (freeResources) { + uniqueInstance.FreeResources(); + } } return uniqueInstance; } diff --git a/Greenshot/Configuration/LanguageKeys.cs b/Greenshot/Configuration/LanguageKeys.cs index d7a52ee46..ec5aee6c6 100644 --- a/Greenshot/Configuration/LanguageKeys.cs +++ b/Greenshot/Configuration/LanguageKeys.cs @@ -22,6 +22,7 @@ using System; namespace Greenshot.Configuration { public enum LangKey { + none, about_bugs, about_donations, about_host, @@ -88,6 +89,7 @@ namespace Greenshot.Configuration { editor_drawellipse, editor_drawhighlighter, editor_drawline, + editor_drawfreehand, editor_drawrectangle, editor_drawtextbox, editor_duplicate, @@ -127,6 +129,9 @@ namespace Greenshot.Configuration { editor_title, editor_uponelevel, editor_uptotop, + editor_autocrop, + editor_undo, + editor_redo, error, error_multipleinstances, error_nowriteaccess, @@ -162,6 +167,7 @@ namespace Greenshot.Configuration { settings_destination_file, settings_destination_fileas, settings_destination_printer, + settings_destination_picker, settings_editor, settings_filenamepattern, settings_general, @@ -187,6 +193,7 @@ namespace Greenshot.Configuration { settings_tooltip_registerhotkeys, settings_tooltip_storagelocation, settings_visualization, + settings_shownotify, settings_waittime, settings_windowscapture, settings_window_capture_mode, @@ -198,6 +205,7 @@ namespace Greenshot.Configuration { warning_hotkeys, hotkeys, wait_ie_capture, - update_found + update_found, + exported_to } } diff --git a/Greenshot/Configuration/RuntimeConfig.cs b/Greenshot/Configuration/RuntimeConfig.cs index 879a2ee69..04200cbf4 100644 --- a/Greenshot/Configuration/RuntimeConfig.cs +++ b/Greenshot/Configuration/RuntimeConfig.cs @@ -18,10 +18,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -using System.Drawing.Imaging; -using System.Drawing; -using System.Windows.Forms; using System; +using System.Collections.Generic; +using System.Drawing; + +using Greenshot.Plugin; namespace Greenshot.Configuration { /// diff --git a/Greenshot/Controls/BindableToolStripButton.cs b/Greenshot/Controls/BindableToolStripButton.cs index 7dcad5c4a..9d59f4edc 100644 --- a/Greenshot/Controls/BindableToolStripButton.cs +++ b/Greenshot/Controls/BindableToolStripButton.cs @@ -21,7 +21,6 @@ using System; using System.ComponentModel; using System.Windows.Forms; -using System.Windows.Forms.Design; namespace Greenshot.Controls { /// diff --git a/Greenshot/Controls/BindableToolStripComboBox.cs b/Greenshot/Controls/BindableToolStripComboBox.cs index 7a1d6ba79..aa4cf2c00 100644 --- a/Greenshot/Controls/BindableToolStripComboBox.cs +++ b/Greenshot/Controls/BindableToolStripComboBox.cs @@ -21,7 +21,6 @@ using System; using System.ComponentModel; using System.Windows.Forms; -using System.Windows.Forms.Design; namespace Greenshot.Controls { /// diff --git a/Greenshot/Controls/BindableToolStripDropDownButton.cs b/Greenshot/Controls/BindableToolStripDropDownButton.cs index 44ddfc213..3b7e4bad2 100644 --- a/Greenshot/Controls/BindableToolStripDropDownButton.cs +++ b/Greenshot/Controls/BindableToolStripDropDownButton.cs @@ -21,7 +21,6 @@ using System; using System.ComponentModel; using System.Windows.Forms; -using System.Windows.Forms.Design; namespace Greenshot.Controls { /// diff --git a/Greenshot/Controls/ColorButton.cs b/Greenshot/Controls/ColorButton.cs index 566a7f348..fbe58caf6 100644 --- a/Greenshot/Controls/ColorButton.cs +++ b/Greenshot/Controls/ColorButton.cs @@ -24,8 +24,6 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; -using GreenshotPlugin.Core; - namespace Greenshot.Controls { /// /// Description of ColorButton. diff --git a/Greenshot/Controls/FontFamilyComboBox.cs b/Greenshot/Controls/FontFamilyComboBox.cs index f14546e52..9fcc9173f 100644 --- a/Greenshot/Controls/FontFamilyComboBox.cs +++ b/Greenshot/Controls/FontFamilyComboBox.cs @@ -20,9 +20,8 @@ */ using System; using System.ComponentModel; -using System.Windows.Forms; -using System.Windows.Forms.Design; using System.Drawing; +using System.Windows.Forms; namespace Greenshot.Controls { /// diff --git a/Greenshot/Controls/ToolStripColorButton.cs b/Greenshot/Controls/ToolStripColorButton.cs index 631cdf438..8e1729e91 100644 --- a/Greenshot/Controls/ToolStripColorButton.cs +++ b/Greenshot/Controls/ToolStripColorButton.cs @@ -24,9 +24,6 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; -using Greenshot.Configuration; -using GreenshotPlugin.Core; - namespace Greenshot.Controls { public class ToolStripColorButton : ToolStripButton, INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; diff --git a/Greenshot/Destinations/ClipboardDestination.cs b/Greenshot/Destinations/ClipboardDestination.cs new file mode 100644 index 000000000..74b74b5c9 --- /dev/null +++ b/Greenshot/Destinations/ClipboardDestination.cs @@ -0,0 +1,89 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Windows.Forms; + +using Greenshot.Configuration; +using GreenshotPlugin.Core; +using Greenshot.Plugin; +using Greenshot.Helpers; +using IniFile; + +namespace Greenshot.Destinations { + /// + /// Description of ClipboardDestination. + /// + public class ClipboardDestination : AbstractDestination { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ClipboardDestination)); + private static CoreConfiguration conf = IniConfig.GetIniSection(); + public const string DESIGNATION = "Clipboard"; + + private ILanguage lang = Language.GetInstance(); + + public override string Designation { + get { + return DESIGNATION; + } + } + + public override string Description { + get { + return lang.GetString(LangKey.settings_destination_clipboard); + } + } + public override int Priority { + get { + return 2; + } + } + + public override Keys EditorShortcutKeys { + get { + return Keys.Control | Keys.Shift | Keys.C; + } + } + + public override Image DisplayIcon { + get { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ImageEditorForm)); + return ((System.Drawing.Image)(resources.GetObject("copyToolStripMenuItem.Image"))); + } + } + + public override bool ExportCapture(ISurface surface, ICaptureDetails captureDetails) { + try { + using (Image image = surface.GetImageForExport()) { + ClipboardHelper.SetClipboardData(image); + surface.Modified = false; + } + surface.SendMessageEvent(this, SurfaceMessageTyp.Info, lang.GetString(LangKey.editor_storedtoclipboard)); + return true; + } catch (Exception) { + surface.SendMessageEvent(this, SurfaceMessageTyp.Error, lang.GetString(LangKey.editor_clipboardfailed)); + } + + return false; + } + } +} diff --git a/Greenshot/Destinations/EditorDestination.cs b/Greenshot/Destinations/EditorDestination.cs new file mode 100644 index 000000000..b5c5b6b1a --- /dev/null +++ b/Greenshot/Destinations/EditorDestination.cs @@ -0,0 +1,122 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Drawing.Imaging; +using System.Drawing.Printing; +using System.IO; +using System.Windows.Forms; + +using Greenshot.Configuration; +using GreenshotPlugin.Core; +using Greenshot.Plugin; +using Greenshot.Helpers; +using IniFile; + +namespace Greenshot.Destinations { + /// + /// Description of EditorDestination. + /// + public class EditorDestination : AbstractDestination { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(EditorDestination)); + private static CoreConfiguration conf = IniConfig.GetIniSection(); + public const string DESIGNATION = "Editor"; + private ILanguage lang = Language.GetInstance(); + private IImageEditor editor = null; + private static Image greenshotIcon = GreenshotPlugin.Core.GreenshotResources.getGreenshotIcon().ToBitmap(); + + public EditorDestination() { + } + + public EditorDestination(IImageEditor editor) { + this.editor = editor; + } + + public override string Designation { + get { + return DESIGNATION; + } + } + + public override string Description { + get { + if (editor == null) { + return lang.GetString(LangKey.settings_destination_editor); + } else { + return lang.GetString(LangKey.settings_destination_editor) + " - " + editor.CaptureDetails.Title; + } + } + } + + public override int Priority { + get { + return 1; + } + } + + public override bool isDynamic { + get { + return true; + } + } + + public override Image DisplayIcon { + get { + return greenshotIcon; + } + } + + public override IEnumerable DynamicDestinations() { + foreach (IImageEditor editor in ImageEditorForm.Editors) { + yield return new EditorDestination(editor); + } + } + + public override bool ExportCapture(ISurface surface, ICaptureDetails captureDetails) { + if (editor == null) { + // Make sure we collect the garbage before opening the screenshot + GC.Collect(); + GC.WaitForPendingFinalizers(); + + try { + ImageEditorForm editorForm = new ImageEditorForm(surface, false); // Output made?? + + if (!string.IsNullOrEmpty(captureDetails.Filename)) { + editorForm.SetImagePath(captureDetails.Filename); + } + editorForm.Show(); + editorForm.Activate(); + LOG.Debug("Finished opening Editor"); + return true; + } catch (Exception e) { + LOG.Error(e); + } + } else { + using (Bitmap image = (Bitmap)surface.GetImageForExport()) { + editor.Surface.AddBitmapContainer(image, 10, 10); + } + surface.SendMessageEvent(this, SurfaceMessageTyp.Info, lang.GetFormattedString(LangKey.exported_to, Description)); + } + return false; + } + } +} diff --git a/Greenshot/Destinations/EmailDestination.cs b/Greenshot/Destinations/EmailDestination.cs new file mode 100644 index 000000000..835be2cc1 --- /dev/null +++ b/Greenshot/Destinations/EmailDestination.cs @@ -0,0 +1,200 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Text.RegularExpressions; +using System.Windows.Forms; + +using Greenshot.Configuration; +using Greenshot.Helpers; +using Greenshot.Helpers.OfficeInterop; +using Greenshot.Plugin; +using GreenshotPlugin.Core; +using IniFile; + +namespace Greenshot.Destinations { + /// + /// Description of EmailDestination. + /// + public class EmailDestination : AbstractDestination { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(EmailDestination)); + private static CoreConfiguration conf = IniConfig.GetIniSection(); + private static string exePath = null; + private static Image icon = null; + private static bool isActiveFlag = false; + private static bool isOutlookUsed = false; + private static string mapiClient = null; + public const string DESIGNATION = "EMail"; + private string outlookInspectorCaption = null; + private ILanguage lang = Language.GetInstance(); + + static EmailDestination() { + // Logic to decide what email implementation we use + if (EmailConfigHelper.HasMAPI()) { + isActiveFlag = true; + mapiClient = EmailConfigHelper.GetMapiClient(); + if (!string.IsNullOrEmpty(mapiClient)) { + if (mapiClient.ToLower().Contains("microsoft outlook")) { + isOutlookUsed = true; + } + } + } else if (EmailConfigHelper.HasOutlook()) { + mapiClient = "Microsoft Outlook"; + isActiveFlag = true; + isOutlookUsed = true; + } + + if (isOutlookUsed) { + exePath = GetExePath("OUTLOOK.EXE"); + if (exePath != null && File.Exists(exePath)) { + icon = GetExeIcon(exePath); + } else { + exePath = null; + } + if (exePath == null) { + isOutlookUsed = false; + if (!EmailConfigHelper.HasMAPI()) { + isActiveFlag = false; + } + } + } + if (isActiveFlag && !isOutlookUsed) { + // Use default email icon + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ImageEditorForm)); + icon = ((System.Drawing.Image)(resources.GetObject("btnEmail.Image"))); + } + } + + public EmailDestination() { + + } + public EmailDestination(string outlookInspectorCaption) { + this.outlookInspectorCaption = outlookInspectorCaption; + } + + public override string Designation { + get { + return DESIGNATION; + } + } + + public override string Description { + get { + // Make sure there is some kind of "mail" name + if (mapiClient == null) { + mapiClient = lang.GetString(LangKey.editor_email); + } + + if (outlookInspectorCaption == null) { + return mapiClient; + } else { + return mapiClient + " - " + outlookInspectorCaption; + } + } + } + + public override int Priority { + get { + return 3; + } + } + + public override bool isActive { + get { + return isActiveFlag; + } + } + + public override bool isDynamic { + get { + return isOutlookUsed; + } + } + + public override Keys EditorShortcutKeys { + get { + return Keys.Control | Keys.E; + } + } + + public override Image DisplayIcon { + get { + return icon; + } + } + + public override IEnumerable DynamicDestinations() { + if (!isOutlookUsed) { + yield break; + } + List inspectorCaptions = OutlookExporter.RetrievePossibleTargets(); + if (inspectorCaptions != null) { + foreach (string inspectorCaption in inspectorCaptions) { + yield return new EmailDestination(inspectorCaption); + } + } + } + + public override bool ExportCapture(ISurface surface, ICaptureDetails captureDetails) { + if (!isOutlookUsed) { + using (Image image = surface.GetImageForExport()) { + MapiMailMessage.SendImage(image, captureDetails); + surface.Modified = false; + surface.SendMessageEvent(this, SurfaceMessageTyp.Info, "Exported to " + mapiClient); + } + return true; + } + + // Outlook logic + string tmpFile = captureDetails.Filename; + if (tmpFile == null) { + using (Image image = surface.GetImageForExport()) { + tmpFile = ImageOutput.SaveNamedTmpFile(image, captureDetails, conf.OutputFileFormat, conf.OutputFileJpegQuality); + } + } + // Create a attachment name for the image + string attachmentName = captureDetails.Title; + if (!string.IsNullOrEmpty(attachmentName)) { + attachmentName = attachmentName.Trim(); + } + // Set default if non is set + 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]", ""); + + if (outlookInspectorCaption != null) { + OutlookExporter.ExportToInspector(outlookInspectorCaption, tmpFile, attachmentName); + } else { + OutlookExporter.ExportToOutlook(tmpFile, captureDetails.Title, attachmentName); + } + surface.SendMessageEvent(this, SurfaceMessageTyp.Info, lang.GetFormattedString(LangKey.exported_to, Description)); + surface.Modified = false; + + // Don't know how to handle a cancel in the email + + return true; + } + } +} \ No newline at end of file diff --git a/Greenshot/Destinations/ExcelDestination.cs b/Greenshot/Destinations/ExcelDestination.cs new file mode 100644 index 000000000..a7dcfdb14 --- /dev/null +++ b/Greenshot/Destinations/ExcelDestination.cs @@ -0,0 +1,125 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Windows.Forms; + +using Greenshot.Configuration; +using GreenshotPlugin.Core; +using Greenshot.Plugin; +using Greenshot.Helpers; +using Greenshot.Helpers.OfficeInterop; +using IniFile; + +namespace Greenshot.Destinations { + /// + /// Description of PowerpointDestination. + /// + public class ExcelDestination : AbstractDestination { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ExcelDestination)); + private static CoreConfiguration conf = IniConfig.GetIniSection(); + private static string exePath = null; + private static Image icon = null; + private ILanguage lang = Language.GetInstance(); + private string workbookName = null; + + static ExcelDestination() { + exePath = GetExePath("EXCEL.EXE"); + if (exePath != null && File.Exists(exePath)) { + icon = GetExeIcon(exePath); + } else { + exePath = null; + } + } + + public ExcelDestination() { + } + + public ExcelDestination(string workbookName) { + this.workbookName = workbookName; + } + + public override string Designation { + get { + return "Excel"; + } + } + + public override string Description { + get { + if (workbookName == null) { + return "Microsoft Excel"; + } else { + return "Microsoft Excel - " + workbookName; + } + } + } + + public override int Priority { + get { + return 5; + } + } + + public override bool isDynamic { + get { + return true; + } + } + + public override bool isActive { + get { + return exePath != null; + } + } + + public override Image DisplayIcon { + get { + return icon; + } + } + + public override IEnumerable DynamicDestinations() { + foreach (string workbookName in ExcelExporter.GetWorkbooks()) { + yield return new ExcelDestination(workbookName); + } + } + + public override bool ExportCapture(ISurface surface, ICaptureDetails captureDetails) { + string tmpFile = captureDetails.Filename; + if (tmpFile == null) { + using (Image image = surface.GetImageForExport()) { + tmpFile = ImageOutput.SaveNamedTmpFile(image, captureDetails, conf.OutputFileFormat, conf.OutputFileJpegQuality); + } + } + if (workbookName != null) { + ExcelExporter.InsertIntoExistingWorkbook(workbookName, tmpFile); + } else { + ExcelExporter.InsertIntoNewWorkbook(tmpFile); + } + surface.SendMessageEvent(this, SurfaceMessageTyp.Info, lang.GetFormattedString(LangKey.exported_to, Description)); + surface.Modified = false; + return true; + } + } +} diff --git a/Greenshot/Destinations/FileDestination.cs b/Greenshot/Destinations/FileDestination.cs new file mode 100644 index 000000000..b1d220d19 --- /dev/null +++ b/Greenshot/Destinations/FileDestination.cs @@ -0,0 +1,112 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Windows.Forms; + +using Greenshot.Configuration; +using GreenshotPlugin.Core; +using Greenshot.Plugin; +using Greenshot.Helpers; +using IniFile; + +namespace Greenshot.Destinations { + /// + /// Description of FileSaveAsDestination. + /// + public class FileDestination : AbstractDestination { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(FileDestination)); + private static CoreConfiguration conf = IniConfig.GetIniSection(); + public const string DESIGNATION = "FileNoDialog"; + private ILanguage lang = Language.GetInstance(); + + public override string Designation { + get { + return DESIGNATION; + } + } + + public override string Description { + get { + return lang.GetString(LangKey.quicksettings_destination_file); + } + } + + public override int Priority { + get { + return 0; + } + } + + public override Keys EditorShortcutKeys { + get { + return Keys.Control | Keys.S; + } + } + + public override Image DisplayIcon { + get { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ImageEditorForm)); + return ((System.Drawing.Image)(resources.GetObject("saveToolStripMenuItem.Image"))); + } + } + + public override bool ExportCapture(ISurface surface, ICaptureDetails captureDetails) { + bool outputMade = false; + string pattern = conf.OutputFileFilenamePattern; + if (string.IsNullOrEmpty(pattern)) { + pattern = "greenshot ${capturetime}"; + } + string filename = FilenameHelper.GetFilenameFromPattern(pattern, conf.OutputFileFormat, captureDetails); + string filepath = FilenameHelper.FillVariables(conf.OutputFilePath, false); + string fullPath = Path.Combine(filepath,filename); + + // Catching any exception to prevent that the user can't write in the directory. + // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218, #3004642 + using (Image image = surface.GetImageForExport()) { + try { + // TODO: For now we overwrite, but this should be fixed some time + ImageOutput.Save(image, fullPath, true); + outputMade = true; + } catch (Exception e) { + LOG.Error("Error saving screenshot!", e); + // Show the problem + MessageBox.Show(lang.GetString(LangKey.error_save), lang.GetString(LangKey.error)); + // when save failed we present a SaveWithDialog + fullPath = ImageOutput.SaveWithDialog(image, captureDetails); + outputMade = (fullPath != null); + } + } + // Don't overwite filename if no output is made + if (outputMade) { + surface.LastSaveFullPath = fullPath; + surface.Modified = false; + captureDetails.Filename = fullPath; + surface.SendMessageEvent(this, SurfaceMessageTyp.FileSaved, lang.GetFormattedString(LangKey.editor_imagesaved,surface.LastSaveFullPath)); + } else { + surface.SendMessageEvent(this, SurfaceMessageTyp.Info, ""); + } + return outputMade; + } + } +} diff --git a/Greenshot/Destinations/FileWithDialogDestination.cs b/Greenshot/Destinations/FileWithDialogDestination.cs new file mode 100644 index 000000000..1d895a307 --- /dev/null +++ b/Greenshot/Destinations/FileWithDialogDestination.cs @@ -0,0 +1,92 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Windows.Forms; + +using Greenshot.Configuration; +using GreenshotPlugin.Core; +using Greenshot.Plugin; +using Greenshot.Helpers; +using IniFile; + +namespace Greenshot.Destinations { + /// + /// Description of FileWithDialog. + /// + public class FileWithDialogDestination : AbstractDestination { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(FileWithDialogDestination)); + private static CoreConfiguration conf = IniConfig.GetIniSection(); + public const string DESIGNATION = "FileDialog"; + + private ILanguage lang = Language.GetInstance(); + + public override string Designation { + get { + return DESIGNATION; + } + } + + public override string Description { + get { + return lang.GetString(LangKey.settings_destination_fileas); + } + } + + public override int Priority { + get { + return 0; + } + } + + public override Keys EditorShortcutKeys { + get { + return Keys.Control | Keys.Shift | Keys.S; + } + } + + public override Image DisplayIcon { + get { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ImageEditorForm)); + return ((System.Drawing.Image)(resources.GetObject("saveToolStripMenuItem.Image"))); + } + } + + public override bool ExportCapture(ISurface surface, ICaptureDetails captureDetails) { + string savedTo = null; + using (Image image = surface.GetImageForExport()) { + // Bug #2918756 don't overwrite path if SaveWithDialog returns null! + savedTo = ImageOutput.SaveWithDialog(image, captureDetails); + if (savedTo != null) { + surface.Modified = false; + surface.LastSaveFullPath = savedTo; + captureDetails.Filename = savedTo; + surface.SendMessageEvent(this, SurfaceMessageTyp.FileSaved, lang.GetFormattedString(LangKey.editor_imagesaved,surface.LastSaveFullPath)); + } else { + surface.SendMessageEvent(this, SurfaceMessageTyp.Info, ""); + } + } + return savedTo != null; + } + } +} diff --git a/Greenshot/Destinations/PickerDestination.cs b/Greenshot/Destinations/PickerDestination.cs new file mode 100644 index 000000000..7342eecc0 --- /dev/null +++ b/Greenshot/Destinations/PickerDestination.cs @@ -0,0 +1,133 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Windows.Forms; + +using Greenshot.Configuration; +using GreenshotPlugin.Core; +using Greenshot.Plugin; +using Greenshot.Helpers; +using Greenshot.Forms; +using IniFile; + +namespace Greenshot.Destinations { + /// + /// Description of PickerDestination. + /// + public class PickerDestination : AbstractDestination { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(PickerDestination)); + private static CoreConfiguration conf = IniConfig.GetIniSection(); + public const string DESIGNATION = "Picker"; + private ILanguage lang = Language.GetInstance(); + + public override string Designation { + get { + return DESIGNATION; + } + } + + public override string Description { + get { + return lang.GetString(LangKey.settings_destination_picker); + } + } + + public override int Priority { + get { + return 1; + } + } + + public override bool isActive { + get { + return conf.isExperimentalFeatureEnabled("Picker"); + } + } + + public override bool ExportCapture(ISurface surface, ICaptureDetails captureDetails) { + ContextMenuStrip menu = new ContextMenuStrip(); + menu.Closed += delegate(object source, ToolStripDropDownClosedEventArgs eventArgs) { + // Dispose surface when no item was clicked, else the dispose should be made there! + if (eventArgs.CloseReason != ToolStripDropDownCloseReason.ItemClicked) { + LOG.DebugFormat("Disposing as no item was clicked, reason: {0}", eventArgs.CloseReason); + surface.Dispose(); + } + }; + + foreach(IDestination destination in DestinationHelper.GetAllDestinations()) { + if ("Picker".Equals(destination.Designation)) { + continue; + } + if (!destination.isActive) { + continue; + } + // Fix foreach loop variable for the delegate + ToolStripMenuItem item = destination.GetMenuItem(delegate(object sender, EventArgs e) { + ToolStripMenuItem toolStripMenuItem = sender as ToolStripMenuItem; + if (toolStripMenuItem == null) { + return; + } + IDestination clickedDestination = (IDestination)toolStripMenuItem.Tag; + if (clickedDestination == null) { + return; + } + bool result = clickedDestination.ExportCapture(surface, captureDetails); + // TODO: Find some better way to detect that we exported to the editor + if (!EditorDestination.DESIGNATION.Equals(clickedDestination.Designation) || result == false) { + LOG.DebugFormat("Disposing as Destination was {0} and result {1}", clickedDestination.Description, result); + // Cleanup surface + surface.Dispose(); + } + // Make sure the menu is closed + menu.Close(); + }); + if (item != null) { + menu.Items.Add(item); + } + } + menu.Items.Add(new ToolStripSeparator()); + ToolStripMenuItem closeItem = new ToolStripMenuItem(lang.GetString(LangKey.editor_close)); + closeItem.Image = ((System.Drawing.Image)(new System.ComponentModel.ComponentResourceManager(typeof(ImageEditorForm)).GetObject("closeToolStripMenuItem.Image"))); + closeItem.Click += delegate { + // This menu entry is the close itself, we can dispose the surface + menu.Close(); + surface.Dispose(); + }; + menu.Items.Add(closeItem); + + // find a suitable location + Point location = Cursor.Position; + Rectangle menuRectangle = new Rectangle(location, menu.Size); + menuRectangle.Intersect(WindowCapture.GetScreenBounds()); + if (menuRectangle.Height < menu.Height) { + location.Offset(-40, -(menuRectangle.Height - menu.Height)); + } else { + location.Offset(-40, -10); + } + menu.Show(location); + menu.Focus(); + return true; + } + } +} diff --git a/Greenshot/Destinations/PowerpointDestination.cs b/Greenshot/Destinations/PowerpointDestination.cs new file mode 100644 index 000000000..19fa161f8 --- /dev/null +++ b/Greenshot/Destinations/PowerpointDestination.cs @@ -0,0 +1,127 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Windows.Forms; + +using Greenshot.Configuration; +using GreenshotPlugin.Core; +using Greenshot.Plugin; +using Greenshot.Helpers; +using Greenshot.Helpers.OfficeInterop; +using IniFile; + +namespace Greenshot.Destinations { + /// + /// Description of PowerpointDestination. + /// + public class PowerpointDestination : AbstractDestination { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(PowerpointDestination)); + private static CoreConfiguration conf = IniConfig.GetIniSection(); + private static string exePath = null; + private static Image icon = null; + private ILanguage lang = Language.GetInstance(); + private string presentationName = null; + + static PowerpointDestination() { + exePath = GetExePath("POWERPNT.EXE"); + if (exePath != null && File.Exists(exePath)) { + icon = GetExeIcon(exePath); + } else { + exePath = null; + } + } + + public PowerpointDestination() { + } + + public PowerpointDestination(string presentationName) { + this.presentationName = presentationName; + } + + public override string Designation { + get { + return "Powerpoint"; + } + } + + public override string Description { + get { + if (presentationName == null) { + return "Microsoft Powerpoint"; + } else { + return "Microsoft Powerpoint - " + presentationName; + } + } + } + + public override int Priority { + get { + return 4; + } + } + + public override bool isDynamic { + get { + return true; + } + } + + public override bool isActive { + get { + return exePath != null; + } + } + + public override Image DisplayIcon { + get { + return icon; + } + } + + public override IEnumerable DynamicDestinations() { + foreach (string presentationName in PowerpointExporter.GetPowerpointPresentations()) { + yield return new PowerpointDestination(presentationName); + } + } + + public override bool ExportCapture(ISurface surface, ICaptureDetails captureDetails) { + string tmpFile = captureDetails.Filename; + Size imageSize = Size.Empty; + if (tmpFile == null) { + using (Image image = surface.GetImageForExport()) { + tmpFile = ImageOutput.SaveNamedTmpFile(image, captureDetails, conf.OutputFileFormat, conf.OutputFileJpegQuality); + imageSize = image.Size; + } + } + if (presentationName != null) { + PowerpointExporter.ExportToPresentation(presentationName, tmpFile, imageSize, captureDetails); + } else { + PowerpointExporter.InsertIntoNewPresentation(tmpFile, imageSize, captureDetails); + } + surface.SendMessageEvent(this, SurfaceMessageTyp.Info, lang.GetFormattedString(LangKey.exported_to, Description)); + surface.Modified = false; + return true; + } + } +} diff --git a/Greenshot/Destinations/PrinterDestination.cs b/Greenshot/Destinations/PrinterDestination.cs new file mode 100644 index 000000000..c973fbbe8 --- /dev/null +++ b/Greenshot/Destinations/PrinterDestination.cs @@ -0,0 +1,89 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Drawing.Printing; +using System.IO; +using System.Windows.Forms; + +using Greenshot.Configuration; +using GreenshotPlugin.Core; +using Greenshot.Plugin; +using Greenshot.Helpers; +using IniFile; + +namespace Greenshot.Destinations { + /// + /// Description of PrinterDestination. + /// + public class PrinterDestination : AbstractDestination { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(PrinterDestination)); + private static CoreConfiguration conf = IniConfig.GetIniSection(); + public const string DESIGNATION = "Printer"; + + private ILanguage lang = Language.GetInstance(); + + public override string Designation { + get { + return DESIGNATION; + } + } + + public override string Description { + get { + return lang.GetString(LangKey.settings_destination_printer); + } + } + + public override int Priority { + get { + return 2; + } + } + + public override Keys EditorShortcutKeys { + get { + return Keys.Control | Keys.P; + } + } + + public override Image DisplayIcon { + get { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ImageEditorForm)); + return ((System.Drawing.Image)(resources.GetObject("printToolStripMenuItem.Image"))); + } + } + + public override bool ExportCapture(ISurface surface, ICaptureDetails captureDetails) { + PrinterSettings printerSettings = null; + using (Image image = surface.GetImageForExport()) { + printerSettings = new PrintHelper(image, captureDetails).PrintWithDialog(); + if (printerSettings != null) { + surface.Modified = false; + surface.SendMessageEvent(this, SurfaceMessageTyp.Info, lang.GetFormattedString(LangKey.editor_senttoprinter, printerSettings.PrinterName)); + } + } + + return printerSettings != null; + } + } +} diff --git a/Greenshot/Destinations/WordDestination.cs b/Greenshot/Destinations/WordDestination.cs new file mode 100644 index 000000000..798e6f911 --- /dev/null +++ b/Greenshot/Destinations/WordDestination.cs @@ -0,0 +1,128 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Drawing.Imaging; +using System.IO; +using System.Windows.Forms; + +using Greenshot.Configuration; +using GreenshotPlugin.Core; +using Greenshot.Plugin; +using Greenshot.Helpers; +using Greenshot.Helpers.OfficeInterop; +using IniFile; + +namespace Greenshot.Destinations { + /// + /// Description of EmailDestination. + /// + public class WordDestination : AbstractDestination { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(WordDestination)); + private static CoreConfiguration conf = IniConfig.GetIniSection(); + private static string exePath = null; + private static Image icon = null; + private ILanguage lang = Language.GetInstance(); + private string wordCaption = null; + + static WordDestination() { + exePath = GetExePath("WINWORD.EXE"); + if (exePath != null && File.Exists(exePath)) { + icon = GetExeIcon(exePath); + } else { + exePath = null; + } + } + + public WordDestination() { + + } + + public WordDestination(string wordCaption) { + this.wordCaption = wordCaption; + } + + public override string Designation { + get { + return "Word"; + } + } + + public override string Description { + get { + if (wordCaption == null) { + return "Microsoft Word"; + } else { + return "Microsoft Word - " + wordCaption; + } + } + } + + public override int Priority { + get { + return 4; + } + } + + public override bool isDynamic { + get { + return true; + } + } + + public override bool isActive { + get { + return exePath != null; + } + } + + public override Image DisplayIcon { + get { + return icon; + } + } + + public override IEnumerable DynamicDestinations() { + foreach (string wordCaption in WordExporter.GetWordDocuments()) { + yield return new WordDestination(wordCaption); + } + } + + public override bool ExportCapture(ISurface surface, ICaptureDetails captureDetails) { + string tmpFile = captureDetails.Filename; + if (tmpFile == null) { + using (Image image = surface.GetImageForExport()) { + tmpFile = ImageOutput.SaveNamedTmpFile(image, captureDetails, conf.OutputFileFormat, conf.OutputFileJpegQuality); + } + } + if (wordCaption != null) { + WordExporter.InsertIntoExistingDocument(wordCaption, tmpFile); + } else { + WordExporter.InsertIntoNewDocument(tmpFile); + } + surface.SendMessageEvent(this, SurfaceMessageTyp.Info, lang.GetFormattedString(LangKey.exported_to, Description)); + surface.Modified = false; + + return true; + } + } +} diff --git a/Greenshot/Drawing/ArrowContainer.cs b/Greenshot/Drawing/ArrowContainer.cs index 54f7d97fb..dfae20645 100644 --- a/Greenshot/Drawing/ArrowContainer.cs +++ b/Greenshot/Drawing/ArrowContainer.cs @@ -19,13 +19,9 @@ * along with this program. If not, see . */ using System; -using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; -using System.Runtime.Serialization; -using System.Windows.Forms; -using Greenshot.Configuration; using Greenshot.Drawing.Fields; using Greenshot.Helpers; using Greenshot.Plugin.Drawing; @@ -44,144 +40,93 @@ namespace Greenshot.Drawing { AddField(GetType(), FieldType.ARROWHEADS, 2); AddField(GetType(), FieldType.LINE_COLOR, Color.Red); AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); - AddField(GetType(), FieldType.SHADOW, false); + AddField(GetType(), FieldType.SHADOW, true); AddField(GetType(), FieldType.ARROWHEADS, Greenshot.Drawing.ArrowContainer.ArrowHeadCombination.END_POINT); } public override void Draw(Graphics g, RenderMode rm) { - g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - ArrowHeadCombination heads = (ArrowHeadCombination)GetFieldValue(FieldType.ARROWHEADS);; - if ( shadow && lineThickness > 0 ) { - //draw shadow first - int basealpha = 100; - int alpha = basealpha; - int steps = 5; - int currentStep = 1; - while ( currentStep <= steps ) { - using (Pen shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))) { - shadowCapPen.Width = lineThickness; - - if ( heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.START_POINT ) shadowCapPen.CustomStartCap = ARROW_CAP; - if ( heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.END_POINT ) shadowCapPen.CustomEndCap = ARROW_CAP; - - g.DrawLine(shadowCapPen, - this.Left + currentStep, - this.Top + currentStep, - this.Left + currentStep + this.Width, - this.Top + currentStep + this.Height); - - currentStep++; - alpha = alpha - (basealpha / steps); + if (lineThickness > 0 ) { + g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + ArrowHeadCombination heads = (ArrowHeadCombination)GetFieldValue(FieldType.ARROWHEADS); + if (shadow) { + //draw shadow first + int basealpha = 100; + int alpha = basealpha; + int steps = 5; + int currentStep = 1; + while ( currentStep <= steps ) { + using (Pen shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))) { + shadowCapPen.Width = lineThickness; + SetArrowHeads(heads, shadowCapPen); + + g.DrawLine(shadowCapPen, + this.Left + currentStep, + this.Top + currentStep, + this.Left + currentStep + this.Width, + this.Top + currentStep + this.Height); + + currentStep++; + alpha = alpha - (basealpha / steps); + } + } + + } + using (Pen pen = new Pen(lineColor)) { + pen.Width = lineThickness; + + if ( pen.Width > 0 ) { + SetArrowHeads(heads, pen); + g.DrawLine(pen, this.Left, this.Top, this.Left + this.Width, this.Top + this.Height); } } } - - using (Pen pen = new Pen(lineColor)) { - pen.Width = lineThickness; - - if ( pen.Width > 0 ) { - if ( heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.START_POINT ) pen.CustomStartCap = ARROW_CAP; - if ( heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.END_POINT ) pen.CustomEndCap = ARROW_CAP; - - g.DrawLine(pen, this.Left, this.Top, this.Left + this.Width, this.Top + this.Height); - } - + } + + private void SetArrowHeads(ArrowHeadCombination heads, Pen pen) { + if ( heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.START_POINT ) { + pen.CustomStartCap = ARROW_CAP; + } + if ( heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.END_POINT ) { + pen.CustomEndCap = ARROW_CAP; } } public override Rectangle DrawingBounds { get { - int lineThickness = 0; - if (HasField(FieldType.LINE_THICKNESS)) { - lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - } - int arrowCapWidth = 0; - int arrowCapHeight = 0; - if (HasField(FieldType.ARROWHEADS)) { - ArrowHeadCombination heads = (ArrowHeadCombination)GetFieldValue(FieldType.ARROWHEADS); - if(heads.Equals(ArrowHeadCombination.START_POINT) || heads.Equals(ArrowHeadCombination.END_POINT) || heads.Equals(ArrowHeadCombination.BOTH)) { - arrowCapWidth = (int)ARROW_CAP.Width * lineThickness; - arrowCapHeight = (int)ARROW_CAP.Height * lineThickness; + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + if (lineThickness > 0) { + using (Pen pen = new Pen(Color.White)) { + pen.Width = lineThickness; + SetArrowHeads((ArrowHeadCombination)GetFieldValue(FieldType.ARROWHEADS), pen); + GraphicsPath path = new GraphicsPath(); + path.AddLine(this.Left, this.Top, this.Left + this.Width, this.Top + this.Height); + Rectangle drawingBounds = Rectangle.Round(path.GetBounds(new Matrix(), pen)); + drawingBounds.Inflate(2,2); + return drawingBounds; } + } else { + return Rectangle.Empty; } - - int offset = Math.Max(lineThickness/2, Math.Max(arrowCapWidth, arrowCapHeight)); - return new Rectangle(Bounds.Left-offset, Bounds.Top-offset, Bounds.Width+offset*2, Bounds.Height+offset*2); - } } public override bool ClickableAt(int x, int y) { - bool ret = false; - ret = base.ClickableAt(x, y); - if(!ret) { - // line has not been clicked, check arrow heads - ArrowHeadCombination heads = (ArrowHeadCombination)GetFieldValue(FieldType.ARROWHEADS); - if(!ArrowHeadCombination.NONE.Equals(heads)) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - double arrowCapHalfWidth = ARROW_CAP.Width * lineThickness / 2; - double arrowCapHeight = ARROW_CAP.Height * lineThickness; - // we have to check only if arrow heads are wider than tolerated area of LineContainer - if(arrowCapHalfWidth > MAX_CLICK_DISTANCE_TOLERANCE) { - double mouseToLineDist = DrawingHelper.CalculateLinePointDistance(Left, Top, Left+Width, Top+Height, x, y); - if(mouseToLineDist > -1) { // point next to line at all? - if(heads.Equals(ArrowHeadCombination.END_POINT) || heads.Equals(ArrowHeadCombination.BOTH)) { - // calculate a perpendicular line at arrow tip to hittest arrow head easily - int p1x = Left + Width + Height; - int p1y = Top + Height - Width; - int p2x = Left + Width - Height; - int p2y = Top + Height + Width; - - double mouseToPerpDist = DrawingHelper.CalculateLinePointDistance(p1x,p1y,p2x,p2y, x, y); - if( - // point located within rectangular area of width/height of arrowhead? - mouseToLineDist <= arrowCapHalfWidth - && mouseToPerpDist <= arrowCapHeight - // point located within arrowhead? (nearer to line than to perp * w/h-factor) - && mouseToLineDist < mouseToPerpDist * arrowCapHalfWidth / arrowCapHeight) { - return true; - } - } - if(heads.Equals(ArrowHeadCombination.START_POINT) || heads.Equals(ArrowHeadCombination.BOTH)) { - // calculate a perpendicular line at arrow tip to hittest arrow head easily - int p1x = Left - Height; - int p1y = Top + Width; - int p2x = Left + Height; - int p2y = Top - Width; - - double mouseToPerpDist = DrawingHelper.CalculateLinePointDistance(p1x,p1y,p2x,p2y, x, y); - if( - // point located within rectangular area of width/height of arrowhead? - mouseToLineDist <= arrowCapHalfWidth - && mouseToPerpDist <= arrowCapHeight - // point located within arrowhead? (nearer to line than to perp * w/h-factor) - && mouseToLineDist < mouseToPerpDist * arrowCapHalfWidth / arrowCapHeight) { - return true; - } - - - } - } - - } + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; + if (lineThickness > 0) { + using (Pen pen = new Pen(Color.White)) { + pen.Width = lineThickness; + SetArrowHeads((ArrowHeadCombination)GetFieldValue(FieldType.ARROWHEADS), pen); + GraphicsPath path = new GraphicsPath(); + path.AddLine(this.Left, this.Top, this.Left + this.Width, this.Top + this.Height); + return path.IsOutlineVisible(x,y, pen); } - - } - - return ret; - - /*int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - double distance = DrawingHelper.CalculateLinePointDistance(this.Left, this.Top, this.Left + this.Width, this.Top + this.Height, x, y); - if (distance < 0) { + } else { return false; } - return distance <= Math.Max(lineThickness / 2, 10);*/ } - } } diff --git a/Greenshot/Drawing/BitmapContainer.cs b/Greenshot/Drawing/BitmapContainer.cs index a4bc67424..e1192f940 100644 --- a/Greenshot/Drawing/BitmapContainer.cs +++ b/Greenshot/Drawing/BitmapContainer.cs @@ -20,14 +20,14 @@ */ using System; using System.Drawing; +using System.Drawing.Imaging; using System.IO; -using System.Runtime.Serialization; using System.Windows.Forms; -using Greenshot.Configuration; using Greenshot.Drawing.Fields; using Greenshot.Helpers; using Greenshot.Plugin.Drawing; +using GreenshotPlugin.Core; namespace Greenshot.Drawing { /// @@ -40,10 +40,12 @@ namespace Greenshot.Drawing { protected Bitmap bitmap; public BitmapContainer(Surface parent, string filename) : this(parent) { + AddField(GetType(), FieldType.SHADOW, false); Load(filename); } public BitmapContainer(Surface parent) : base(parent) { + AddField(GetType(), FieldType.SHADOW, false); } @@ -93,17 +95,38 @@ namespace Greenshot.Drawing { public void Load(string filename) { if (File.Exists(filename)) { - using (Bitmap fileBitmap = new Bitmap(filename)) { - Bitmap = fileBitmap; - LOG.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); - } + Bitmap = ImageHelper.LoadBitmap(filename); + LOG.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); } } - public override void Draw(Graphics g, RenderMode rm) { + public override void Draw(Graphics graphics, RenderMode rm) { if (bitmap != null) { - g.DrawImage(bitmap, Bounds); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + if (shadow) { + ImageAttributes ia = new ImageAttributes(); + ColorMatrix cm = new ColorMatrix(); + cm.Matrix00 = 0; + cm.Matrix11 = 0; + cm.Matrix22 = 0; + cm.Matrix33 = 0.25f; + ia.SetColorMatrix(cm); + graphics.DrawImage(bitmap, new Rectangle(Bounds.Left+2, Bounds.Top+2, Bounds.Width, Bounds.Height), 0, 0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, ia); + } + graphics.DrawImage(bitmap, Bounds); } } + + public override void AddContextMenuItems(ContextMenuStrip menu) { + base.AddContextMenuItems(menu); + ToolStripMenuItem resetItem = new ToolStripMenuItem("Reset size"); + resetItem.Click += delegate { + this.Invalidate(); + Width = Bitmap.Width; + Height = Bitmap.Height; + this.Invalidate(); + }; + menu.Items.Add(resetItem); + } } } diff --git a/Greenshot/Drawing/CropContainer.cs b/Greenshot/Drawing/CropContainer.cs index 00061cab6..1a6c39d0a 100644 --- a/Greenshot/Drawing/CropContainer.cs +++ b/Greenshot/Drawing/CropContainer.cs @@ -20,7 +20,6 @@ */ using System; using System.Drawing; -using System.Runtime.Serialization; using System.Windows.Forms; using Greenshot.Drawing.Fields; @@ -57,5 +56,9 @@ namespace Greenshot.Drawing { g.FillRectangle(cropBrush, new Rectangle(0, r.Top + r.Height, parent.Width, parent.Height - (r.Top + r.Height))); } } + + public override void ShowContextMenu(MouseEventArgs e) { + // No context menu for the CropContainer + } } } diff --git a/Greenshot/Drawing/CursorContainer.cs b/Greenshot/Drawing/CursorContainer.cs index 925d1518c..0b6d8dde3 100644 --- a/Greenshot/Drawing/CursorContainer.cs +++ b/Greenshot/Drawing/CursorContainer.cs @@ -20,14 +20,9 @@ */ using System; using System.Drawing; -using System.Drawing.Drawing2D; using System.IO; -using System.Runtime.Serialization; using System.Windows.Forms; -using Greenshot.Configuration; -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; using Greenshot.Plugin.Drawing; namespace Greenshot.Drawing { @@ -106,5 +101,17 @@ namespace Greenshot.Drawing { cursor.DrawStretched(graphics, Bounds); } } + + public override void AddContextMenuItems(ContextMenuStrip menu) { + base.AddContextMenuItems(menu); + ToolStripMenuItem resetItem = new ToolStripMenuItem("Reset size"); + resetItem.Click += delegate { + this.Invalidate(); + Width = cursor.Size.Width; + Height = cursor.Size.Height; + this.Invalidate(); + }; + menu.Items.Add(resetItem); + } } } diff --git a/Greenshot/Drawing/DrawableContainer.cs b/Greenshot/Drawing/DrawableContainer.cs index df0e64fbd..5e247edb3 100644 --- a/Greenshot/Drawing/DrawableContainer.cs +++ b/Greenshot/Drawing/DrawableContainer.cs @@ -22,18 +22,17 @@ using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.Runtime.Serialization; using System.Windows.Forms; using Greenshot.Configuration; -using Greenshot.Controls; using Greenshot.Drawing.Fields; using Greenshot.Drawing.Filters; using Greenshot.Helpers; using Greenshot.Plugin; +using GreenshotPlugin.Core; using Greenshot.Plugin.Drawing; +using Greenshot.Memento; +using IniFile; namespace Greenshot.Drawing { /// @@ -45,6 +44,10 @@ namespace Greenshot.Drawing { [Serializable()] public abstract class DrawableContainer : AbstractFieldHolderWithChildren, INotifyPropertyChanged, IDrawableContainer { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(DrawableContainer)); + private static System.ComponentModel.ComponentResourceManager editorFormResources = new System.ComponentModel.ComponentResourceManager(typeof(ImageEditorForm)); + private static CoreConfiguration conf = IniConfig.GetIniSection(); + + private bool isMadeUndoable = false; [NonSerialized] private PropertyChangedEventHandler propertyChanged; @@ -53,32 +56,36 @@ namespace Greenshot.Drawing { remove{ propertyChanged -= value; } } -// public List filters = new List(); public List Filters { get { List ret = new List(); foreach(IFieldHolder c in Children) { - if(c is IFilter) ret.Add(c as IFilter); + if (c is IFilter) { + ret.Add(c as IFilter); + } } return ret; } } [NonSerialized] - protected Surface parent; + internal Surface parent; public ISurface Parent { get { return parent; } set { SwitchParent((Surface)value); } } [NonSerialized] - protected Label[] grippers; + protected Gripper[] grippers; private bool layoutSuspended = false; [NonSerialized] private bool selected = false; public bool Selected { get {return selected;} - set {selected = value; OnPropertyChanged("Selected"); } + set { + selected = value; + OnPropertyChanged("Selected"); + } } [NonSerialized] @@ -87,29 +94,86 @@ namespace Greenshot.Drawing { private int left = 0; public int Left { get { return left; } - set { left = value; DoLayout();} + set { + if(value != left) { + left = value; + DoLayout(); + } + } } private int top = 0; public int Top { get { return top; } - set { top = value; DoLayout();} + set { + if(value != top) { + top = value; + DoLayout(); + } + } } private int width = 0; public int Width { get { return width; } - set { width = value; DoLayout();} + set { + if(value != width) { + width = value; + DoLayout(); + } + } } private int height = 0; public int Height { get { return height; } - set { height = value; DoLayout();} + set { + if(value != height) { + height = value; + DoLayout(); + } + } } + public Point Location { + get { + return new Point(left, top); + } + } + + public Size Size { + get { + return new Size(width, height); + } + } + + [NonSerialized] + /// + /// will store current bounds of this DrawableContainer before starting a resize + /// + private Rectangle boundsBeforeResize = Rectangle.Empty; + + [NonSerialized] + /// + /// "workbench" rectangle - used for calculatoing bounds during resizing (to be applied to this DrawableContainer afterwards) + /// + private RectangleF boundsAfterResize = RectangleF.Empty; + public Rectangle Bounds { - get { return GuiRectangle.GetGuiRectangle(left, top, width, height); } + get { return GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); } + set { + Left = round(value.Left); + Top = round(value.Top); + Width = round(value.Width); + Height = round(value.Height); + } + } + + public void ApplyBounds(RectangleF newBounds) { + Left = round(newBounds.Left); + Top = round(newBounds.Top); + Width = round(newBounds.Width); + Height = round(newBounds.Height); } public DrawableContainer(Surface parent) { @@ -124,6 +188,18 @@ namespace Greenshot.Drawing { public void Remove(IFilter filter) { RemoveChild(filter); } + + private int round(float f) { + if(float.IsPositiveInfinity(f) || f>int.MaxValue/2) return int.MaxValue/2; + else if (float.IsNegativeInfinity(f) || fint.MaxValue/2) return int.MaxValue/2; + else if (Double.IsNegativeInfinity(d) || d grippers[4].Left && grippers[0].Top > grippers[4].Top) { - grippers[0].Cursor = Cursors.SizeNWSE; - grippers[2].Cursor = Cursors.SizeNESW; - grippers[4].Cursor = Cursors.SizeNWSE; - grippers[6].Cursor = Cursors.SizeNESW; - } else if((grippers[0].Left > grippers[4].Left && grippers[0].Top < grippers[4].Top) || - grippers[0].Left < grippers[4].Left && grippers[0].Top > grippers[4].Top) { - grippers[0].Cursor = Cursors.SizeNESW; - grippers[2].Cursor = Cursors.SizeNWSE; - grippers[4].Cursor = Cursors.SizeNESW; - grippers[6].Cursor = Cursors.SizeNWSE; - } else if (grippers[0].Left == grippers[4].Left) { - grippers[0].Cursor = Cursors.SizeNS; - grippers[4].Cursor = Cursors.SizeNS; - } else if (grippers[0].Top == grippers[4].Top) { - grippers[0].Cursor = Cursors.SizeWE; - grippers[4].Cursor = Cursors.SizeWE; + if((grippers[Gripper.POSITION_TOP_LEFT].Left < grippers[Gripper.POSITION_BOTTOM_RIGHT].Left && grippers[Gripper.POSITION_TOP_LEFT].Top < grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) || + grippers[Gripper.POSITION_TOP_LEFT].Left > grippers[Gripper.POSITION_BOTTOM_RIGHT].Left && grippers[Gripper.POSITION_TOP_LEFT].Top > grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) { + grippers[Gripper.POSITION_TOP_LEFT].Cursor = Cursors.SizeNWSE; + grippers[Gripper.POSITION_TOP_RIGHT].Cursor = Cursors.SizeNESW; + grippers[Gripper.POSITION_BOTTOM_RIGHT].Cursor = Cursors.SizeNWSE; + grippers[Gripper.POSITION_BOTTOM_LEFT].Cursor = Cursors.SizeNESW; + } else if((grippers[Gripper.POSITION_TOP_LEFT].Left > grippers[Gripper.POSITION_BOTTOM_RIGHT].Left && grippers[Gripper.POSITION_TOP_LEFT].Top < grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) || + grippers[Gripper.POSITION_TOP_LEFT].Left < grippers[Gripper.POSITION_BOTTOM_RIGHT].Left && grippers[Gripper.POSITION_TOP_LEFT].Top > grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) { + grippers[Gripper.POSITION_TOP_LEFT].Cursor = Cursors.SizeNESW; + grippers[Gripper.POSITION_TOP_RIGHT].Cursor = Cursors.SizeNWSE; + grippers[Gripper.POSITION_BOTTOM_RIGHT].Cursor = Cursors.SizeNESW; + grippers[Gripper.POSITION_BOTTOM_LEFT].Cursor = Cursors.SizeNWSE; + } else if (grippers[Gripper.POSITION_TOP_LEFT].Left == grippers[Gripper.POSITION_BOTTOM_RIGHT].Left) { + grippers[Gripper.POSITION_TOP_LEFT].Cursor = Cursors.SizeNS; + grippers[Gripper.POSITION_BOTTOM_RIGHT].Cursor = Cursors.SizeNS; + } else if (grippers[Gripper.POSITION_TOP_LEFT].Top == grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) { + grippers[Gripper.POSITION_TOP_LEFT].Cursor = Cursors.SizeWE; + grippers[Gripper.POSITION_BOTTOM_RIGHT].Cursor = Cursors.SizeWE; } } } @@ -270,31 +343,48 @@ namespace Greenshot.Drawing { mx = e.X; my = e.Y; Status = EditStatus.RESIZING; + boundsBeforeResize = new Rectangle(left, top, width, height); + boundsAfterResize = new RectangleF(boundsBeforeResize.Left, boundsBeforeResize.Top, boundsBeforeResize.Width, boundsBeforeResize.Height); + isMadeUndoable = false; } private void gripperMouseUp(object sender, MouseEventArgs e) { Status = EditStatus.IDLE; + boundsBeforeResize = Rectangle.Empty; + boundsAfterResize = RectangleF.Empty; + isMadeUndoable = false; Invalidate(); } private void gripperMouseMove(object sender, MouseEventArgs e) { if(Status.Equals(EditStatus.RESIZING)) { + // check if we already made this undoable + if (!isMadeUndoable) { + // don't allow another undo until we are finished with this move + isMadeUndoable = true; + // Make undo-able + MakeBoundsChangeUndoable(false); + } + Invalidate(); SuspendLayout(); - Label gr = (Label)sender; - int gripperIndex = Int16.Parse(gr.Name.Substring(7)); - if(gripperIndex <= 2) { // top row - this.Top += e.Y - my; - this.Height -= e.Y - my; - } else if(gripperIndex >= 4 && gripperIndex <= 6) { // bottom row - this.Height += e.Y - my; - } - if(gripperIndex >=2 && gripperIndex <= 4) { // right row - this.Width += e.X - mx; - } else if(gripperIndex >=6 || gripperIndex == 0) { // left row - this.Left += e.X - mx; - this.Width -= e.X - mx; - } + + Gripper gr = (Gripper)sender; + int absX = gr.Left + e.X; + int absY = gr.Top + e.Y; + + // reset "workbench" rectangle to current bounds + boundsAfterResize.X = boundsBeforeResize.X; + boundsAfterResize.Y = boundsBeforeResize.Y; + boundsAfterResize.Width = boundsBeforeResize.Width; + boundsAfterResize.Height = boundsBeforeResize.Height; + + // calculate scaled rectangle + ScaleHelper.Scale(ref boundsAfterResize, gr.Position, new PointF(absX, absY), ScaleHelper.GetScaleOptions()); + + // apply scaled bounds to this DrawableContainer + ApplyBounds(boundsAfterResize); + ResumeLayout(); Invalidate(); } @@ -320,11 +410,11 @@ namespace Greenshot.Drawing { public abstract void Draw(Graphics graphics, RenderMode renderMode); public virtual void DrawContent(Graphics graphics, Bitmap bmp, RenderMode renderMode, Rectangle clipRectangle) { - if(Children.Count > 0) { + if (Children.Count > 0) { if(Status != EditStatus.IDLE) { DrawSelectionBorder(graphics, Bounds); } else { - if(clipRectangle.Width != 0 && clipRectangle.Height != 0) { + if (clipRectangle.Width != 0 && clipRectangle.Height != 0) { foreach(IFilter filter in Filters) { if (filter.Invert) { filter.Apply(graphics, bmp, Bounds, renderMode); @@ -359,8 +449,8 @@ namespace Greenshot.Drawing { } } - public void ShowGrippers() { - for(int i=0; i + /// Make a following bounds change on this drawablecontainer undoable! + /// + /// true means allow the moves to be merged + public void MakeBoundsChangeUndoable(bool allowMerge) { + this.parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(this), allowMerge); + } + public void MoveBy(int dx, int dy) { this.SuspendLayout(); this.Left += dx; @@ -381,9 +486,55 @@ namespace Greenshot.Drawing { this.ResumeLayout(); } + /// + /// A handler for the MouseDown, used if you don't want the surface to handle this for you + /// + /// current mouse x + /// current mouse y + /// true if the event is handled, false if the surface needs to handle it + public virtual bool HandleMouseDown(int x, int y) { + Left = boundsBeforeResize.X = x; + Top = boundsBeforeResize.Y = y; + return true; + } + + /// + /// A handler for the MouseMove, used if you don't want the surface to handle this for you + /// + /// current mouse x + /// current mouse y + /// true if the event is handled, false if the surface needs to handle it + public virtual bool HandleMouseMove(int x, int y) { + Invalidate(); + SuspendLayout(); + + // reset "workrbench" rectangle to current bounds + boundsAfterResize.X = boundsBeforeResize.Left; + boundsAfterResize.Y = boundsBeforeResize.Top; + boundsAfterResize.Width = x - boundsAfterResize.Left; + boundsAfterResize.Height = y - boundsAfterResize.Top; + + ScaleHelper.Scale(boundsBeforeResize, x, y, ref boundsAfterResize, GetAngleRoundProcessor()); + + // apply scaled bounds to this DrawableContainer + ApplyBounds(boundsAfterResize); + + ResumeLayout(); + Invalidate(); + return true; + } + + /// + /// A handler for the MouseUp + /// + /// current mouse x + /// current mouse y + public virtual void HandleMouseUp(int x, int y) { + } + private void SwitchParent(Surface newParent) { - if(parent != null) { - for(int i=0; i + /// This method will be called before a field is changes. + /// Using this makes it possible to invalidate the object as is before changing. + /// + /// The field to be changed + /// The new value + public virtual void BeforeFieldChange(Field fieldToBeChanged, object newValue) { + parent.MakeUndoable(new ChangeFieldHolderMemento(this, fieldToBeChanged), true); + Invalidate(); + } + /// /// Handle the field changed event, this should invalidate the correct bounds (e.g. when shadow comes or goes more pixels!) /// @@ -431,5 +593,101 @@ namespace Greenshot.Drawing { } Invalidate(); } + + protected virtual ScaleHelper.IDoubleProcessor GetAngleRoundProcessor() { + return ScaleHelper.ShapeAngleRoundBehavior.Instance; + } + + /// + /// Add items to a context menu for the selected item + /// + /// + public virtual void AddContextMenuItems(ContextMenuStrip menu) { + DrawableContainerList myselfAsList = new DrawableContainerList(); + myselfAsList.Add(this); + ILanguage lang = Language.GetInstance(); + bool push = parent.Elements.CanPushDown(myselfAsList); + bool pull = parent.Elements.CanPullUp(myselfAsList); + + ToolStripMenuItem item; + + // Pull "up" + if (pull) { + item = new ToolStripMenuItem(lang.GetString(LangKey.editor_uptotop)); + item.Click += delegate { + parent.Elements.PullElementsToTop(myselfAsList); + parent.Elements.Invalidate(); + }; + menu.Items.Add(item); + item = new ToolStripMenuItem(lang.GetString(LangKey.editor_uponelevel)); + item.Click += delegate { + parent.Elements.PullElementsUp(myselfAsList); + parent.Elements.Invalidate(); + }; + menu.Items.Add(item); + } + // Push "down" + if (push) { + item = new ToolStripMenuItem(lang.GetString(LangKey.editor_downtobottom)); + item.Click += delegate { + parent.Elements.PushElementsToBottom(myselfAsList); + parent.Elements.Invalidate(); + }; + menu.Items.Add(item); + item = new ToolStripMenuItem(lang.GetString(LangKey.editor_downonelevel)); + item.Click += delegate { + parent.Elements.PushElementsDown(myselfAsList); + parent.Elements.Invalidate(); + }; + menu.Items.Add(item); + } + + // Duplicate + item = new ToolStripMenuItem(lang.GetString(LangKey.editor_duplicate)); + item.Click += delegate { + DrawableContainerList dcs = myselfAsList.Clone(); + dcs.Parent = parent; + dcs.MoveBy(10,10); + parent.AddElements(dcs); + parent.DeselectAllElements(); + parent.SelectElements(dcs); + }; + menu.Items.Add(item); + + // Copy + item = new ToolStripMenuItem(lang.GetString(LangKey.editor_copytoclipboard)); + item.Image = ((System.Drawing.Image)(editorFormResources.GetObject("copyToolStripMenuItem.Image"))); + item.Click += delegate { + ClipboardHelper.SetClipboardData(typeof(DrawableContainerList), myselfAsList); + }; + menu.Items.Add(item); + + // Cut + item = new ToolStripMenuItem(lang.GetString(LangKey.editor_cuttoclipboard)); + item.Image = ((System.Drawing.Image)(editorFormResources.GetObject("editor_cuttoclipboard.Image"))); + item.Click += delegate { + ClipboardHelper.SetClipboardData(typeof(DrawableContainerList), myselfAsList); + parent.RemoveElement(this, true); + }; + menu.Items.Add(item); + + // Delete + item = new ToolStripMenuItem(lang.GetString(LangKey.editor_deleteelement)); + item.Image = ((System.Drawing.Image)(editorFormResources.GetObject("removeObjectToolStripMenuItem.Image"))); + item.Click += delegate { + parent.RemoveElement(this, true); + }; + menu.Items.Add(item); + } + + public virtual void ShowContextMenu(MouseEventArgs e) { + if (conf.isExperimentalFeatureEnabled("Contextmenu")) { + ContextMenuStrip menu = new ContextMenuStrip(); + AddContextMenuItems(menu); + if (menu.Items.Count > 0) { + menu.Show(parent, e.Location); + } + } + } } } \ No newline at end of file diff --git a/Greenshot/Drawing/DrawableContainerList.cs b/Greenshot/Drawing/DrawableContainerList.cs index dd0acc8d3..c4c933c3b 100644 --- a/Greenshot/Drawing/DrawableContainerList.cs +++ b/Greenshot/Drawing/DrawableContainerList.cs @@ -19,12 +19,10 @@ * along with this program. If not, see . */ using System; -using System.Collections; using System.Collections.Generic; using System.Drawing; -using System.Windows.Forms; - using Greenshot.Drawing.Fields; +using Greenshot.Memento; using Greenshot.Plugin; using Greenshot.Plugin.Drawing; @@ -84,6 +82,22 @@ namespace Greenshot.Drawing { } } + /// + /// Make a following bounds change on this containerlist undoable! + /// + /// true means allow the moves to be merged + public void MakeBoundsChangeUndoable(bool allowMerge) { + List movingList = new List(); + Surface surface = null; + foreach(DrawableContainer dc in this) { + movingList.Add(dc); + surface = dc.parent; + } + if (movingList.Count > 0 && surface != null) { + surface.MakeUndoable(new DrawableContainerBoundsChangeMemento(movingList), allowMerge); + } + } + /// /// Moves all elements in the list by the given amount of pixels. /// @@ -93,14 +107,13 @@ namespace Greenshot.Drawing { // Track modifications bool modified = false; - // Invalidate before moving (otherwise the old locations aren't refreshed + // Invalidate before moving, otherwise the old locations aren't refreshed this.Invalidate(); foreach(DrawableContainer dc in this) { dc.Left += dx; dc.Top += dy; modified = true; } - // Invalidate after this.Invalidate(); diff --git a/Greenshot/Drawing/EllipseContainer.cs b/Greenshot/Drawing/EllipseContainer.cs index 5e3d42229..86dcb8836 100644 --- a/Greenshot/Drawing/EllipseContainer.cs +++ b/Greenshot/Drawing/EllipseContainer.cs @@ -20,10 +20,8 @@ */ using System; using System.Drawing; -using System.Runtime.Serialization; -using System.Windows.Forms; +using System.Drawing.Drawing2D; -using Greenshot.Configuration; using Greenshot.Drawing.Fields; using Greenshot.Helpers; using Greenshot.Plugin.Drawing; @@ -38,7 +36,7 @@ namespace Greenshot.Drawing { AddField(GetType(), FieldType.LINE_THICKNESS, 2); AddField(GetType(), FieldType.LINE_COLOR, Color.Red); AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); - AddField(GetType(), FieldType.SHADOW, false); + AddField(GetType(), FieldType.SHADOW, true); } public override void Draw(Graphics graphics, RenderMode renderMode) { @@ -68,9 +66,10 @@ namespace Greenshot.Drawing { //draw the original shape Rectangle rect = GuiRectangle.GetGuiRectangle(this.Left, this.Top, this.Width, this.Height); - - using (Brush brush = new SolidBrush(fillColor)) { - graphics.FillEllipse(brush, rect); + if (!Color.Transparent.Equals(fillColor)) { + using (Brush brush = new SolidBrush(fillColor)) { + graphics.FillEllipse(brush, rect); + } } using (Pen pen = new Pen(lineColor)) { @@ -87,5 +86,30 @@ namespace Greenshot.Drawing { // ellipse: x^2/a^2 + y^2/b^2 = 1 return Math.Pow(xDistanceFromCenter,2)/Math.Pow(Width/2,2) + Math.Pow(yDistanceFromCenter,2)/Math.Pow(Height/2,2) < 1; } + + public override bool ClickableAt(int x, int y) { + Rectangle rect = GuiRectangle.GetGuiRectangle(this.Left, this.Top, this.Width, this.Height); + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + + // If we clicked inside the rectangle and it's visible we are clickable at. + if (!Color.Transparent.Equals(fillColor)) { + if (Contains(x,y)) { + return true; + } + } + + // check the rest of the lines + if (lineThickness > 0) { + using (Pen pen = new Pen(Color.White)) { + pen.Width = lineThickness; + GraphicsPath path = new GraphicsPath(); + path.AddEllipse(rect); + return path.IsOutlineVisible(x, y, pen); + } + } else { + return false; + } + } } } diff --git a/Greenshot/Drawing/Fields/AbstractFieldHolder.cs b/Greenshot/Drawing/Fields/AbstractFieldHolder.cs index e136a511f..6e366022c 100644 --- a/Greenshot/Drawing/Fields/AbstractFieldHolder.cs +++ b/Greenshot/Drawing/Fields/AbstractFieldHolder.cs @@ -20,14 +20,11 @@ */ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Drawing; -using System.Reflection; using System.Runtime.Serialization; using Greenshot.Configuration; -using Greenshot.Helpers; -using GreenshotPlugin.Core; +using IniFile; namespace Greenshot.Drawing.Fields { /// @@ -61,7 +58,11 @@ namespace Greenshot.Drawing.Fields { fieldsByType = new Dictionary(); // listen to changing properties foreach(Field field in fields) { - field.PropertyChanged += delegate { if(fieldChanged != null) fieldChanged(this, new FieldChangedEventArgs(field)); }; + field.PropertyChanged += delegate { + if (fieldChanged != null) { + fieldChanged(this, new FieldChangedEventArgs(field)); + } + }; fieldsByType[field.FieldType] = field; } } @@ -71,8 +72,8 @@ namespace Greenshot.Drawing.Fields { } public virtual void AddField(Field field) { - if(fieldsByType != null && fieldsByType.ContainsKey(field.FieldType)) { - if(LOG.IsDebugEnabled) { + if (fieldsByType != null && fieldsByType.ContainsKey(field.FieldType)) { + if (LOG.IsDebugEnabled) { LOG.DebugFormat("A field with of type '{0}' already exists in this {1}, will overwrite.", field.FieldType, GetType()); } } @@ -85,7 +86,11 @@ namespace Greenshot.Drawing.Fields { public void RemoveField(Field field) { fields.Remove(field); fieldsByType.Remove(field.FieldType); - field.PropertyChanged -= delegate { if(fieldChanged != null) fieldChanged(this, new FieldChangedEventArgs(field)); }; + field.PropertyChanged -= delegate { + if (fieldChanged != null) { + fieldChanged(this, new FieldChangedEventArgs(field)); + } + }; } public List GetFields() { @@ -97,7 +102,7 @@ namespace Greenshot.Drawing.Fields { try { return fieldsByType[fieldType]; } catch(KeyNotFoundException e) { - throw new ArgumentException("Field '"+fieldType+"' does not exist in " + GetType(), e); + throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType(), e); } } @@ -152,8 +157,9 @@ namespace Greenshot.Drawing.Fields { } protected void OnFieldChanged(object sender, FieldChangedEventArgs e){ - if(fieldChanged != null) fieldChanged(sender, e); + if (fieldChanged != null) { + fieldChanged(sender, e); + } } - } } diff --git a/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs b/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs index 29df7cb9f..8bac8c605 100644 --- a/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs +++ b/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs @@ -20,13 +20,8 @@ */ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.Reflection; using System.Runtime.Serialization; -using Greenshot.Helpers; - namespace Greenshot.Drawing.Fields { /// /// Basic IFieldHolderWithChildren implementation. Similar to IFieldHolder, diff --git a/Greenshot/Drawing/Fields/Field.cs b/Greenshot/Drawing/Fields/Field.cs index 92259972c..d1db76e56 100644 --- a/Greenshot/Drawing/Fields/Field.cs +++ b/Greenshot/Drawing/Fields/Field.cs @@ -33,10 +33,16 @@ namespace Greenshot.Drawing.Fields { public object myValue; public object Value { - get { return myValue; } - set { if(!object.Equals(myValue,value)) { + get { + return myValue; + } + set { + if (!object.Equals(myValue,value)) { myValue = value; - if(PropertyChanged!=null) PropertyChanged(this, new PropertyChangedEventArgs("Value")); } + if (PropertyChanged!=null) { + PropertyChanged(this, new PropertyChangedEventArgs("Value")); + } + } } } public FieldType FieldType; diff --git a/Greenshot/Drawing/Fields/FieldAggregator.cs b/Greenshot/Drawing/Fields/FieldAggregator.cs index e31d73a73..a92e47e97 100644 --- a/Greenshot/Drawing/Fields/FieldAggregator.cs +++ b/Greenshot/Drawing/Fields/FieldAggregator.cs @@ -21,13 +21,9 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.Drawing; -using System.Reflection; using Greenshot.Configuration; -using Greenshot.Drawing.Filters; -using Greenshot.Helpers; -using GreenshotPlugin.Core; +using IniFile; namespace Greenshot.Drawing.Fields { /// @@ -69,8 +65,9 @@ namespace Greenshot.Drawing.Fields { BindElement(dc); } } + public void BindElement(DrawableContainer dc) { - if(!boundContainers.Contains(dc)) { + if (!boundContainers.Contains(dc)) { boundContainers.Add(dc); dc.ChildrenChanged += delegate { UpdateFromBoundElements(); }; UpdateFromBoundElements(); @@ -85,7 +82,7 @@ namespace Greenshot.Drawing.Fields { public void UpdateElement(DrawableContainer dc) { internalUpdateRunning = true; foreach(Field field in GetFields()) { - if(dc.HasField(field.FieldType) && field.HasValue) { + if (dc.HasField(field.FieldType) && field.HasValue) { //if(LOG.IsDebugEnabled) LOG.Debug(" "+field+ ": "+field.Value); dc.SetFieldValue(field.FieldType, field.Value); } @@ -94,7 +91,7 @@ namespace Greenshot.Drawing.Fields { } public void UnbindElement(DrawableContainer dc) { - if(boundContainers.Contains(dc)) { + if (boundContainers.Contains(dc)) { boundContainers.Remove(dc); UpdateFromBoundElements(); } @@ -111,7 +108,6 @@ namespace Greenshot.Drawing.Fields { /// private void ClearFields() { internalUpdateRunning = true; - //if(LOG.IsDebugEnabled) LOG.Debug("Clearing fields internally"); foreach(Field field in GetFields()) { field.Value = null; } @@ -134,7 +130,7 @@ namespace Greenshot.Drawing.Fields { private List FindCommonFields() { List ret = null; - if(boundContainers.Count > 0) { + if (boundContainers.Count > 0) { // take all fields from the least selected container... ret = boundContainers[boundContainers.Count-1].GetFields(); for(int i=0;i fieldsToRemove = new List(); foreach(Field f in ret) { // ... throw out those that do not apply to one of the other containers - if(!dc.HasField(f.FieldType)) { + if (!dc.HasField(f.FieldType)) { fieldsToRemove.Add(f); } } @@ -151,19 +147,24 @@ namespace Greenshot.Drawing.Fields { } } } - if(ret == null) ret = new List(); + if (ret == null) { + ret = new List(); + } return ret; } public void OwnPropertyChanged(object sender, PropertyChangedEventArgs ea) { Field field = (Field) sender; - if(!internalUpdateRunning && field.Value!=null) { - foreach(DrawableContainer dc in boundContainers) { - if(dc.HasField(field.FieldType)) { - Field dcf = dc.GetField(field.FieldType); - dcf.Value = field.Value; + if (!internalUpdateRunning && field.Value != null) { + foreach(DrawableContainer drawableContainer in boundContainers) { + if (drawableContainer.HasField(field.FieldType)) { + Field drawableContainerField = drawableContainer.GetField(field.FieldType); + // Notify before change, so we can e.g. invalidate the area + drawableContainer.BeforeFieldChange(drawableContainerField, field.Value); + + drawableContainerField.Value = field.Value; // update last used from DC field, so that scope is honored - editorConfiguration.UpdateLastFieldValue(dcf); + editorConfiguration.UpdateLastFieldValue(drawableContainerField); } } } diff --git a/Greenshot/Drawing/Fields/FieldType.cs b/Greenshot/Drawing/Fields/FieldType.cs index 4b6374cf2..7fb29bba7 100644 --- a/Greenshot/Drawing/Fields/FieldType.cs +++ b/Greenshot/Drawing/Fields/FieldType.cs @@ -19,7 +19,6 @@ * along with this program. If not, see . */ using System; -using System.Drawing; namespace Greenshot.Drawing.Fields { /// diff --git a/Greenshot/Drawing/FilterContainer.cs b/Greenshot/Drawing/FilterContainer.cs index 8ce516184..c20ebe17d 100644 --- a/Greenshot/Drawing/FilterContainer.cs +++ b/Greenshot/Drawing/FilterContainer.cs @@ -19,14 +19,8 @@ * along with this program. If not, see . */ using System; -using System.Collections.Generic; using System.Drawing; -using System.Drawing.Drawing2D; -using System.Runtime.Serialization; -using System.Windows.Forms; - using Greenshot.Drawing.Fields; -using Greenshot.Drawing.Filters; using Greenshot.Helpers; using Greenshot.Plugin.Drawing; diff --git a/Greenshot/Drawing/Filters/AbstractFilter.cs b/Greenshot/Drawing/Filters/AbstractFilter.cs index 6b3ed431a..37715a09e 100644 --- a/Greenshot/Drawing/Filters/AbstractFilter.cs +++ b/Greenshot/Drawing/Filters/AbstractFilter.cs @@ -19,14 +19,12 @@ * along with this program. If not, see . */ using System; -using System.Collections.Generic; using System.ComponentModel; using System.Drawing; -using System.Runtime.Serialization; -using Greenshot.Drawing; using Greenshot.Drawing.Fields; using Greenshot.Plugin.Drawing; +using GreenshotPlugin.Core; /// /// Graphical filter which can be added to DrawableContainer. diff --git a/Greenshot/Drawing/Filters/BlurFilter.cs b/Greenshot/Drawing/Filters/BlurFilter.cs index ea7e6cd8d..46174f571 100644 --- a/Greenshot/Drawing/Filters/BlurFilter.cs +++ b/Greenshot/Drawing/Filters/BlurFilter.cs @@ -16,15 +16,10 @@ ///////////////////////////////////////////////////////////////////////////////// using System; -using System.ComponentModel; using System.Drawing; -using System.Runtime.Serialization; -using System.Windows.Forms; - -using Greenshot.Configuration; using Greenshot.Drawing.Fields; -using Greenshot.Drawing.Filters; using Greenshot.Plugin.Drawing; +using GreenshotPlugin.Core; namespace Greenshot.Drawing.Filters { [Serializable()] @@ -78,14 +73,13 @@ namespace Greenshot.Drawing.Filters { int r = blurRadius; int[] w = CreateGaussianBlurRow(r); int wlen = w.Length; - + long[] waSums = new long[wlen]; + long[] wcSums = new long[wlen]; + long[] aSums = new long[wlen]; + long[] bSums = new long[wlen]; + long[] gSums = new long[wlen]; + long[] rSums = new long[wlen]; for (int y = 0; y < applyRect.Height; ++y) { - long* waSums = stackalloc long[wlen]; - long* wcSums = stackalloc long[wlen]; - long* aSums = stackalloc long[wlen]; - long* bSums = stackalloc long[wlen]; - long* gSums = stackalloc long[wlen]; - long* rSums = stackalloc long[wlen]; long waSum = 0; long wcSum = 0; long aSum = 0; diff --git a/Greenshot/Drawing/Filters/BrightnessFilter.cs b/Greenshot/Drawing/Filters/BrightnessFilter.cs index d109c33f4..8265ad136 100644 --- a/Greenshot/Drawing/Filters/BrightnessFilter.cs +++ b/Greenshot/Drawing/Filters/BrightnessFilter.cs @@ -20,10 +20,6 @@ */ using System; using System.Drawing; -using System.Drawing.Imaging; -using System.Runtime.Serialization; - -using Greenshot.Configuration; using Greenshot.Drawing.Fields; using Greenshot.Plugin.Drawing; diff --git a/Greenshot/Drawing/Filters/FastSmoothFilter.cs b/Greenshot/Drawing/Filters/FastSmoothFilter.cs deleted file mode 100644 index d5bcdc753..000000000 --- a/Greenshot/Drawing/Filters/FastSmoothFilter.cs +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Drawing; -using System.Drawing.Imaging; -using System.Runtime.Serialization; - -using Greenshot.Drawing.Fields; -using Greenshot.Plugin.Drawing; - -namespace Greenshot.Drawing.Filters { - [Serializable()] - public class FastSmoothFilter : AbstractFilter { - private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(FastSmoothFilter)); - - public FastSmoothFilter(DrawableContainer parent) : base(parent) { - AddField(GetType(), FieldType.BLUR_RADIUS, 3); - } - - public unsafe override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle applyRect, RenderMode renderMode) { - Rectangle sourceRect = new Rectangle(applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height); - Rectangle bitmapRect = new Rectangle(0,0, applyBitmap.Width, applyBitmap.Height); - - if(sourceRect.Equals(Rectangle.Empty)) { - sourceRect = bitmapRect; - } else { - sourceRect.Intersect(bitmapRect); - } - // Does the rect have any pixels? - if (sourceRect.Height <= 0 || sourceRect.Width <= 0) { - return; - } - - int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS); - - // Calculate new sourceRect to include the matrix size if possible - - int leftOffset = Math.Min(sourceRect.X, blurRadius); - int rightOffset = Math.Min(applyBitmap.Width - (sourceRect.X + sourceRect.Width), blurRadius); - int topOffset = Math.Min(sourceRect.Y, blurRadius); - int bottomOffset = Math.Min(applyBitmap.Height - (sourceRect.Y + sourceRect.Height), blurRadius); - LOG.Debug(String.Format("Offsets: {0},{1},{2},{3}", leftOffset, rightOffset, topOffset, bottomOffset)); - LOG.Debug(String.Format("SourceRect before: {0},{1},{2},{3}", sourceRect.X, sourceRect.Width, sourceRect.Y, sourceRect.Height)); - sourceRect.X -= leftOffset; - sourceRect.Width += leftOffset + rightOffset; - sourceRect.Y -= topOffset; - sourceRect.Height += topOffset + bottomOffset; - LOG.Debug(String.Format("SourceRect after: {0},{1},{2},{3}", sourceRect.X, sourceRect.Width, sourceRect.Y, sourceRect.Height)); - // Make a copy of the applyBitmap for reading - - using (Bitmap sourceBitmap = applyBitmap.Clone(sourceRect, applyBitmap.PixelFormat)) { - ApplySmooth(sourceBitmap, applyBitmap, sourceRect, blurRadius); - } - } - - public static bool ApplySmooth(Bitmap sourceBitmap, Bitmap destinationBitmap, Rectangle destRectangle, int blurRadius) { - if (blurRadius < 1) { - return false; - } - - BitmapData destbitmapData = destinationBitmap.LockBits(destRectangle, ImageLockMode.WriteOnly, destinationBitmap.PixelFormat); - BitmapData srcBitmapData = sourceBitmap.LockBits(new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), - ImageLockMode.ReadOnly, - sourceBitmap.PixelFormat); - - int destStride = destbitmapData.Stride; - int srcStride = srcBitmapData.Stride; - - IntPtr destScan0 = destbitmapData.Scan0; - IntPtr srcScan0 = srcBitmapData.Scan0; - - int bIndex; - int gIndex; - int rIndex; - //int aIndex; - int bytesPerPixel; - switch(destinationBitmap.PixelFormat) { - case PixelFormat.Format32bppArgb: - // GDI+ lies to us - the return format is BGR, NOT RGB. - bIndex = 0; - gIndex = 1; - rIndex = 2; - //aIndex = 3; - bytesPerPixel = 4; - break; - case PixelFormat.Format32bppRgb: - // GDI+ lies to us - the return format is BGR, NOT RGB. - bIndex = 0; - gIndex = 1; - rIndex = 2; - bytesPerPixel = 4; - break; - case PixelFormat.Format24bppRgb: - // GDI+ lies to us - the return format is BGR, NOT RGB. - bIndex = 0; - gIndex = 1; - rIndex = 2; - bytesPerPixel = 3; - break; - default: - throw new FormatException("Bitmap.Pixelformat."+destinationBitmap.PixelFormat+" is currently not supported. Supported: Format32bpp(A)Rgb, Format24bppRgb"); - } - long ticks = DateTime.Now.Ticks; - unsafe { - int width = destRectangle.Width - (blurRadius*2); - int height = destRectangle.Height - (blurRadius*2); - int diameter = (2 * blurRadius) + 1; - int mid = ((diameter-1)/2) + 1; - int midPixel = mid * bytesPerPixel; - int midLine = (mid - 1) * destStride; - int writeRPixelOffset = midLine + midPixel + rIndex; - int writeGPixelOffset = midLine + midPixel + gIndex; - int writeBPixelOffset = midLine + midPixel + bIndex; - int readRPixelOffset = diameter * bytesPerPixel + rIndex; - int readGPixelOffset = diameter * bytesPerPixel + gIndex; - int readBPixelOffset = diameter * bytesPerPixel + bIndex; - - int destOffset = destStride - (width*bytesPerPixel); - int srcOffset = srcStride - (width*bytesPerPixel); - int factor = diameter * diameter; - - byte *destBitmapPointer = (byte *)(void *)destScan0; - byte *srcBitmapPointer = (byte *)(void *)srcScan0; - int pixel, lineOffset; - - int rTotal, gTotal, bTotal; - int [,]r = new int[diameter,diameter]; - int [,]g = new int[diameter,diameter]; - int [,]b = new int[diameter,diameter]; - for (int y=0; y < height; y++) { - // Reset totals - rTotal = gTotal = bTotal = 0; - - // Intial load: Do the complete radius, fill the arrays with their values - lineOffset = 0; // Offset relative to the srcBitmapPointer - // Vertical loop - for (int v = 0; v < diameter; v++) { - // Start at beginning of the current line - int index = lineOffset; - // Horizontal loop - for (int currentRow = 0; currentRow < diameter; currentRow++) { - // Get & add values - rTotal += r[v,currentRow] = srcBitmapPointer[index + rIndex]; - gTotal += g[v,currentRow] = srcBitmapPointer[index + gIndex]; - bTotal += b[v,currentRow] = srcBitmapPointer[index + bIndex]; - // Move 1px to the right - index += bytesPerPixel; - } - // Move to next line - lineOffset += srcStride; - } - - // Now loop the complete line from left to right - for (int x=0; x < width; x++ ) { - // Draw Pixel with calculated values - pixel = rTotal / factor; - if (pixel < 0) pixel = 0; - if (pixel > 255) pixel = 255; - destBitmapPointer[writeRPixelOffset]= (byte)pixel; - - pixel = gTotal / factor; - if (pixel < 0) pixel = 0; - if (pixel > 255) pixel = 255; - destBitmapPointer[writeGPixelOffset]= (byte)pixel; - - pixel = bTotal / factor; - if (pixel < 0) pixel = 0; - if (pixel > 255) pixel = 255; - destBitmapPointer[writeBPixelOffset]= (byte)pixel; - - // Update values with next "row" - int oldRow = x % diameter; - srcBitmapPointer += bytesPerPixel; - lineOffset = 0; - // Vertical Loop, subtract the stored value and add the new value - for (int v = 0; v < diameter; v++) { - // Subtrace the first value, so we can add the new later - rTotal -= r[v, oldRow]; - gTotal -= g[v, oldRow]; - bTotal -= b[v, oldRow]; - - // Get & add the next values - rTotal += r[v, oldRow] = srcBitmapPointer[readRPixelOffset + lineOffset]; - gTotal += g[v, oldRow] = srcBitmapPointer[readGPixelOffset + lineOffset]; - bTotal += b[v, oldRow] = srcBitmapPointer[readBPixelOffset + lineOffset]; - - // Goto next line - lineOffset += srcStride; - } - destBitmapPointer += bytesPerPixel; - } - srcBitmapPointer += srcOffset; - destBitmapPointer += destOffset; - } - } - LOG.Info("Ticks = " + (DateTime.Now.Ticks - ticks)); - - destinationBitmap.UnlockBits(destbitmapData); - sourceBitmap.UnlockBits(srcBitmapData); - return true; - } - - /** - * Checks if the supplied Bitmap has a PixelFormat we support - */ - private bool SupportsPixelFormat(Bitmap bitmap) { - return (bitmap.PixelFormat.Equals(PixelFormat.Format32bppArgb) || - bitmap.PixelFormat.Equals(PixelFormat.Format32bppRgb) || - bitmap.PixelFormat.Equals(PixelFormat.Format24bppRgb)); - } - - } -} diff --git a/Greenshot/Drawing/Filters/GrayscaleFilter.cs b/Greenshot/Drawing/Filters/GrayscaleFilter.cs index d56855fdc..14753c305 100644 --- a/Greenshot/Drawing/Filters/GrayscaleFilter.cs +++ b/Greenshot/Drawing/Filters/GrayscaleFilter.cs @@ -20,10 +20,6 @@ */ using System; using System.Drawing; -using System.Drawing.Imaging; -using System.Runtime.Serialization; - -using Greenshot.Plugin.Drawing; namespace Greenshot.Drawing.Filters { /// diff --git a/Greenshot/Drawing/Filters/HighlightFilter.cs b/Greenshot/Drawing/Filters/HighlightFilter.cs index 5200d244b..513808440 100644 --- a/Greenshot/Drawing/Filters/HighlightFilter.cs +++ b/Greenshot/Drawing/Filters/HighlightFilter.cs @@ -20,10 +20,6 @@ */ using System; using System.Drawing; -using System.Drawing.Imaging; -using System.Runtime.Serialization; - -using Greenshot.Configuration; using Greenshot.Drawing.Fields; using Greenshot.Plugin.Drawing; diff --git a/Greenshot/Drawing/Filters/IFilter.cs b/Greenshot/Drawing/Filters/IFilter.cs index 723203d48..0b59a1620 100644 --- a/Greenshot/Drawing/Filters/IFilter.cs +++ b/Greenshot/Drawing/Filters/IFilter.cs @@ -19,11 +19,9 @@ * along with this program. If not, see . */ using System; -using System.Collections.Generic; using System.ComponentModel; using System.Drawing; -using Greenshot.Drawing; using Greenshot.Drawing.Fields; using Greenshot.Plugin.Drawing; diff --git a/Greenshot/Drawing/Filters/MagnifierFilter.cs b/Greenshot/Drawing/Filters/MagnifierFilter.cs index d9e08a9f9..43107c7b2 100644 --- a/Greenshot/Drawing/Filters/MagnifierFilter.cs +++ b/Greenshot/Drawing/Filters/MagnifierFilter.cs @@ -20,12 +20,9 @@ */ using System; using System.Drawing; -using System.Drawing.Imaging; -using System.Runtime.Serialization; - -using Greenshot.Configuration; using Greenshot.Drawing.Fields; using Greenshot.Plugin.Drawing; +using GreenshotPlugin.Core; namespace Greenshot.Drawing.Filters { [Serializable()] diff --git a/Greenshot/Drawing/Filters/PixelizationFilter.cs b/Greenshot/Drawing/Filters/PixelizationFilter.cs index cc779dbcb..8006a34c9 100644 --- a/Greenshot/Drawing/Filters/PixelizationFilter.cs +++ b/Greenshot/Drawing/Filters/PixelizationFilter.cs @@ -21,13 +21,11 @@ using System; using System.Collections.Generic; using System.Drawing; -using System.Drawing.Imaging; -using System.Runtime.Serialization; -using Greenshot.Configuration; using Greenshot.Drawing.Fields; using Greenshot.Helpers; using Greenshot.Plugin.Drawing; +using GreenshotPlugin.Core; namespace Greenshot.Drawing.Filters { [Serializable()] diff --git a/Greenshot/Drawing/FreehandContainer.cs b/Greenshot/Drawing/FreehandContainer.cs new file mode 100644 index 000000000..eea8e9fba --- /dev/null +++ b/Greenshot/Drawing/FreehandContainer.cs @@ -0,0 +1,272 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Drawing; +using System.Drawing.Drawing2D; +using System.ComponentModel; +using System.Collections.Generic; +using System.Runtime.Serialization; +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using Greenshot.Plugin.Drawing; + +namespace Greenshot.Drawing { + /// + /// Description of PathContainer. + /// + [Serializable()] + public class FreehandContainer : DrawableContainer { + private static readonly float [] POINT_OFFSET = new float[]{0.5f, 0.25f, 0.75f}; + + [NonSerialized] + private GraphicsPath freehandPath = new GraphicsPath(); + private Rectangle myBounds = Rectangle.Empty; + private Point lastMouse = Point.Empty; + private List capturePoints = new List(); + private bool isRecalculated = false; + + /// + /// Constructor + /// + public FreehandContainer(Surface parent) : base(parent) { + Init(); + AddField(GetType(), FieldType.LINE_THICKNESS, 3); + AddField(GetType(), FieldType.LINE_COLOR, Color.Red); + Width = parent.Width; + Height = parent.Height; + Top = 0; + Left = 0; + } + + protected void Init() { + for(int i=0; i + /// Destructor + /// + ~FreehandContainer() { + Dispose(false); + } + + /// + /// The public accessible Dispose + /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + /// + public new void Dispose() { + Dispose(true); + base.Dispose(); + GC.SuppressFinalize(this); + } + + /// + /// This Dispose is called from the Dispose and the Destructor. + /// + /// When disposing==true all non-managed resources should be freed too! + protected virtual void Dispose(bool disposing) { + if (disposing) { + if (freehandPath != null) { + freehandPath.Dispose(); + } + } + freehandPath = null; + } + + /// + /// Called from Surface (the parent) when the drawing begins (mouse-down) + /// + /// true if the surface doesn't need to handle the event + public override bool HandleMouseDown(int mouseX, int mouseY) { + lastMouse = new Point(mouseX, mouseY); + capturePoints.Add(lastMouse); + return true; + } + + /// + /// Called from Surface (the parent) if a mouse move is made while drawing + /// + /// true if the surface doesn't need to handle the event + public override bool HandleMouseMove(int mouseX, int mouseY) { + Point previousPoint = capturePoints[capturePoints.Count-1]; + + if (GeometryHelper.Distance2D(previousPoint.X, previousPoint.Y, mouseX, mouseY ) > 5) { + capturePoints.Add(new Point(mouseX, mouseY)); + } + if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) > 2 ) { + //path.AddCurve(new Point[]{lastMouse, new Point(mouseX, mouseY)}); + freehandPath.AddLine(lastMouse, new Point(mouseX, mouseY)); + lastMouse = new Point(mouseX, mouseY); + // Only re-calculate the bounds & redraw when we added something to the path + myBounds = Rectangle.Round(freehandPath.GetBounds()); + Invalidate(); + } + return true; + } + + /// + /// Called when the surface finishes drawing the element + /// + public override void HandleMouseUp(int mouseX, int mouseY) { + // Make sure we don't loose the ending point + if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) > 2) { + capturePoints.Add(new Point(mouseX, mouseY)); + } + RecalculatePath(); + } + + /// + /// Here we recalculate the freehand path by smoothing out the lines with Beziers. + /// + private void RecalculatePath() { + isRecalculated = true; + // Dispose the previous path, if we have one + if (freehandPath != null) { + freehandPath.Dispose(); + } + freehandPath = new GraphicsPath(); + + // Here we can put some cleanup... like losing all the uninteresting points. + if (capturePoints.Count > 3) { + int index = 0; + while ((capturePoints.Count - 1) % 3 != 0) { + // duplicate points, first at 50% than 25% than 75% + capturePoints.Insert((int)(capturePoints.Count*POINT_OFFSET[index]), capturePoints[(int)(capturePoints.Count*POINT_OFFSET[index++])]); + } + freehandPath.AddBeziers(capturePoints.ToArray()); + } + + // Recalculate the bounds + myBounds = Rectangle.Round(freehandPath.GetBounds()); + } + + /// + /// Do the drawing of the freehand "stroke" + /// + /// + /// + public override void Draw(Graphics graphics, RenderMode renderMode) { + graphics.SmoothingMode = SmoothingMode.AntiAlias; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + using (Pen pen = new Pen(lineColor)) { + pen.Width = lineThickness; + if (pen.Width > 0) { + // Make sure the lines are nicely rounded + pen.EndCap = LineCap.Round; + pen.StartCap = LineCap.Round; + pen.LineJoin = LineJoin.Round; + + // Move to where we need to draw + graphics.TranslateTransform(Left,Top); + if (isRecalculated && Selected && renderMode == RenderMode.EDIT) { + DrawSelectionBorder(graphics, pen); + } + graphics.DrawPath(pen, freehandPath); + // Move back, otherwise everything is shifted + graphics.TranslateTransform(-Left,-Top); + } + } + } + + /// + /// Draw a selectionborder around the freehand path + /// + /// + /// + protected void DrawSelectionBorder(Graphics graphics, Pen linePen) { + using (Pen selectionPen = (Pen) linePen.Clone()) { + using (GraphicsPath selectionPath = (GraphicsPath) freehandPath.Clone()) { + selectionPen.Width += 5; + selectionPen.Color = Color.FromArgb(120, Color.LightSeaGreen); + graphics.DrawPath(selectionPen, selectionPath); + selectionPath.Widen(selectionPen); + selectionPen.DashPattern = new float[]{2,2}; + selectionPen.Color = Color.LightSeaGreen; + selectionPen.Width = 1; + graphics.DrawPath(selectionPen, selectionPath); + } + } + } + + /// + /// Get the bounds in which we have something drawn, plus safety margin, these are not the normal bounds... + /// + public override Rectangle DrawingBounds { + get { + if (!myBounds.IsEmpty) { + int lineThickness = Math.Max(10, GetFieldValueAsInt(FieldType.LINE_THICKNESS)); + int safetymargin = 10; + return new Rectangle((myBounds.Left + Left) - (safetymargin+lineThickness), (myBounds.Top + Top) - (safetymargin+lineThickness), myBounds.Width + (2*(lineThickness+safetymargin)), myBounds.Height + (2*(lineThickness+safetymargin))); + } else { + return parent.Bounds; + } + } + } + + // FreehandContainer are regarded equal if they are of the same type and their paths are equal. + public override bool Equals(object obj) { + bool ret = false; + if(obj != null && GetType().Equals(obj.GetType())) { + FreehandContainer other = obj as FreehandContainer; + if(freehandPath.Equals(other.freehandPath)) { + ret = true; + } + } + return ret; + } + + public override int GetHashCode() { + return freehandPath.GetHashCode(); + } + + protected override void DoLayout() { + } + + public override void ShowGrippers() { + this.ResumeLayout(); + } + + public override bool ClickableAt(int x, int y) { + bool returnValue = base.ClickableAt(x, y); + if (returnValue) { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + using (Pen pen = new Pen(Color.White)) { + pen.Width = lineThickness + 10; + returnValue = freehandPath.IsOutlineVisible(x-Left,y-Top, pen); + } + } + return returnValue; + } + } +} diff --git a/Greenshot/Drawing/Gripper.cs b/Greenshot/Drawing/Gripper.cs new file mode 100644 index 000000000..9c7f27779 --- /dev/null +++ b/Greenshot/Drawing/Gripper.cs @@ -0,0 +1,71 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Drawing; +using System.Windows.Forms; + +namespace Greenshot.Drawing +{ + /// + /// Description of Gripper. + /// + public class Gripper : Label { + /// + /// Constants for anchor/gripper position: + /// 0 1 2 + /// 7 3 + /// 6 5 4 + /// + public const int POSITION_TOP_LEFT = 0; + public const int POSITION_TOP_CENTER = 1; + public const int POSITION_TOP_RIGHT = 2; + public const int POSITION_MIDDLE_RIGHT = 3; + public const int POSITION_BOTTOM_RIGHT = 4; + public const int POSITION_BOTTOM_CENTER = 5; + public const int POSITION_BOTTOM_LEFT = 6; + public const int POSITION_MIDDLE_LEFT = 7; + + public int Position; + + public Gripper() { + Width = 5; + Height = 5; + BackColor = Color.Black; + + } + + public bool IsTop() { + return Position == 0 || Position == 1 || Position == 2; + } + public bool IsRight() { + return Position == 2 || Position == 3 || Position == 4; + } + public bool IsBottom() { + return Position == 4 || Position == 5 || Position == 6; + } + public bool IsLeft() { + return Position == 6 || Position == 7 || Position == 0; + } + public bool IsCorner() { + return Position == 0 || Position == 2 || Position == 4 || Position == 6; + } + } +} diff --git a/Greenshot/Drawing/IconContainer.cs b/Greenshot/Drawing/IconContainer.cs index 5b62a000f..7542a9d52 100644 --- a/Greenshot/Drawing/IconContainer.cs +++ b/Greenshot/Drawing/IconContainer.cs @@ -21,12 +21,8 @@ using System; using System.Drawing; using System.IO; -using System.Runtime.Serialization; using System.Windows.Forms; -using Greenshot.Configuration; -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; using Greenshot.Plugin.Drawing; namespace Greenshot.Drawing { @@ -104,5 +100,17 @@ namespace Greenshot.Drawing { graphics.DrawIcon(icon, Bounds); } } + + public override void AddContextMenuItems(ContextMenuStrip menu) { + base.AddContextMenuItems(menu); + ToolStripMenuItem resetItem = new ToolStripMenuItem("Reset size"); + resetItem.Click += delegate { + this.Invalidate(); + Width = icon.Size.Width; + Height = icon.Size.Height; + this.Invalidate(); + }; + menu.Items.Add(resetItem); + } } } diff --git a/Greenshot/Drawing/LineContainer.cs b/Greenshot/Drawing/LineContainer.cs index 0bdb20f35..0ad6099d0 100644 --- a/Greenshot/Drawing/LineContainer.cs +++ b/Greenshot/Drawing/LineContainer.cs @@ -19,13 +19,10 @@ * along with this program. If not, see . */ using System; -using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Runtime.Serialization; -using System.Windows.Forms; -using Greenshot.Configuration; using Greenshot.Drawing.Fields; using Greenshot.Helpers; using Greenshot.Plugin.Drawing; @@ -40,22 +37,27 @@ namespace Greenshot.Drawing { public LineContainer(Surface parent) : base(parent) { Init(); - AddField(GetType(), FieldType.LINE_THICKNESS, 1); + AddField(GetType(), FieldType.LINE_THICKNESS, 2); AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - AddField(GetType(), FieldType.SHADOW, false); + AddField(GetType(), FieldType.SHADOW, true); } - private void Init() { - grippers[1].Enabled = false; - grippers[2].Enabled = false; - grippers[3].Enabled = false; - grippers[5].Enabled = false; - grippers[6].Enabled = false; - grippers[7].Enabled = false; + [OnDeserializedAttribute()] + private void OnDeserialized(StreamingContext context) { + InitGrippers(); + DoLayout(); + Init(); + } + + protected void Init() { + foreach(int index in new int[]{1,2,3,5,6,7}) { + grippers[index].Enabled = false; + } } - public override void Draw(Graphics g, RenderMode rm) { - g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; + public override void Draw(Graphics graphics, RenderMode rm) { + graphics.SmoothingMode = SmoothingMode.AntiAlias; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); @@ -71,7 +73,7 @@ namespace Greenshot.Drawing { using (Pen shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))) { shadowCapPen.Width = lineThickness; - g.DrawLine(shadowCapPen, + graphics.DrawLine(shadowCapPen, this.Left + currentStep, this.Top + currentStep, this.Left + currentStep + this.Width, @@ -83,24 +85,32 @@ namespace Greenshot.Drawing { } } - using (Pen pen = new Pen(lineColor)) { pen.Width = lineThickness; - if(pen.Width > 0) { - g.DrawLine(pen, this.Left, this.Top, this.Left + this.Width, this.Top + this.Height); + graphics.DrawLine(pen, this.Left, this.Top, this.Left + this.Width, this.Top + this.Height); } } } public override bool ClickableAt(int x, int y) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - double distance = DrawingHelper.CalculateLinePointDistance(this.Left, this.Top, this.Left + this.Width, this.Top + this.Height, x, y); - if (distance < 0) { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) +5; + if (lineThickness > 0) { + using (Pen pen = new Pen(Color.White)) { + pen.Width = lineThickness; + GraphicsPath path = new GraphicsPath(); + path.AddLine(this.Left, this.Top, this.Left + this.Width, this.Top + this.Height); + return path.IsOutlineVisible(x,y, pen); + } + } else { return false; } - return distance <= Math.Max(lineThickness / 2, MAX_CLICK_DISTANCE_TOLERANCE); } + protected override ScaleHelper.IDoubleProcessor GetAngleRoundProcessor() { + return ScaleHelper.LineAngleRoundBehavior.Instance; + } + + } } diff --git a/Greenshot/Drawing/MetafileContainer.cs b/Greenshot/Drawing/MetafileContainer.cs index f5c89cc8e..8057c9b1e 100644 --- a/Greenshot/Drawing/MetafileContainer.cs +++ b/Greenshot/Drawing/MetafileContainer.cs @@ -22,12 +22,7 @@ using System; using System.Drawing; using System.Drawing.Imaging; using System.IO; -using System.Runtime.Serialization; -using System.Windows.Forms; -using Greenshot.Configuration; -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; using Greenshot.Plugin.Drawing; namespace Greenshot.Drawing { @@ -107,8 +102,8 @@ namespace Greenshot.Drawing { public void Load(string filename) { if (File.Exists(filename)) { - using (Metafile fileMetafile = new Metafile(filename)) { - Metafile = fileMetafile; + using (Stream imageFileStream = File.OpenRead(filename)) { + Metafile = (Metafile)Image.FromStream(imageFileStream, true, true); LOG.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); } } diff --git a/Greenshot/Drawing/RectangleContainer.cs b/Greenshot/Drawing/RectangleContainer.cs index cf6de2248..35c02c353 100644 --- a/Greenshot/Drawing/RectangleContainer.cs +++ b/Greenshot/Drawing/RectangleContainer.cs @@ -20,10 +20,7 @@ */ using System; using System.Drawing; -using System.Runtime.Serialization; -using System.Windows.Forms; - -using Greenshot.Configuration; +using System.Drawing.Drawing2D; using Greenshot.Drawing.Fields; using Greenshot.Helpers; using Greenshot.Plugin.Drawing; @@ -40,7 +37,7 @@ namespace Greenshot.Drawing { AddField(GetType(), FieldType.LINE_THICKNESS, 2); AddField(GetType(), FieldType.LINE_COLOR, Color.Red); AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); - AddField(GetType(), FieldType.SHADOW, false); + AddField(GetType(), FieldType.SHADOW, true); } @@ -73,8 +70,10 @@ namespace Greenshot.Drawing { Rectangle rect = GuiRectangle.GetGuiRectangle(this.Left, this.Top, this.Width, this.Height); - using (Brush brush = new SolidBrush(fillColor)) { - g.FillRectangle(brush, rect); + if (!Color.Transparent.Equals(fillColor)) { + using (Brush brush = new SolidBrush(fillColor)) { + g.FillRectangle(brush, rect); + } } if (lineThickness > 0) { @@ -85,5 +84,29 @@ namespace Greenshot.Drawing { } } + public override bool ClickableAt(int x, int y) { + Rectangle rect = GuiRectangle.GetGuiRectangle(this.Left, this.Top, this.Width, this.Height); + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + + // If we clicked inside the rectangle and it's visible we are clickable at. + if (!Color.Transparent.Equals(fillColor)) { + if (rect.Contains(x,y)) { + return true; + } + } + + // check the rest of the lines + if (lineThickness > 0) { + using (Pen pen = new Pen(Color.White)) { + pen.Width = lineThickness; + GraphicsPath path = new GraphicsPath(); + path.AddRectangle(rect); + return path.IsOutlineVisible(x, y, pen); + } + } else { + return false; + } + } } } diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index 5100f526d..86271c251 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -24,23 +24,22 @@ using System.ComponentModel; using System.Drawing; using System.Drawing.Imaging; using System.IO; -using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Windows.Forms; - using Greenshot.Configuration; using Greenshot.Drawing.Fields; -using Greenshot.Drawing.Filters; using Greenshot.Helpers; using Greenshot.Plugin; using Greenshot.Plugin.Drawing; using GreenshotPlugin.Core; +using Greenshot.Memento; +using IniFile; namespace Greenshot.Drawing { public delegate void SurfaceElementEventHandler(object source, DrawableContainerList element); public delegate void SurfaceDrawingModeEventHandler(object source, DrawingModes drawingMode); - public enum DrawingModes { None, Rect, Ellipse, Text, Line, Arrow, Crop, Highlight, Obfuscate, Bitmap } + public enum DrawingModes { None, Rect, Ellipse, Text, Line, Arrow, Crop, Highlight, Obfuscate, Bitmap, Path } /// /// Description of Surface. /// @@ -49,7 +48,14 @@ namespace Greenshot.Drawing { private static CoreConfiguration conf = IniConfig.GetIniSection(); public event SurfaceElementEventHandler MovingElementChanged; public event SurfaceDrawingModeEventHandler DrawingModeChanged; - + public event SurfaceSizeChangeEventHandler SurfaceSizeChanged; + public event SurfaceMessageEventHandler SurfaceMessage; + private bool inUndoRedo = false; + private bool isSurfaceMoveMadeUndoable = false; + private Stack undoStack = new Stack(); + private Stack redoStack = new Stack(); + private string lastSaveFullPath = null; + public FieldAggregator FieldAggregator = new FieldAggregator(); private ICaptureDetails captureDetails = null; @@ -99,6 +105,15 @@ namespace Greenshot.Drawing { CreateUndrawnElement(); } } + + public string LastSaveFullPath { + get { + return lastSaveFullPath; + } + set { + lastSaveFullPath = value; + } + } public ICaptureDetails CaptureDetails { get {return captureDetails;} @@ -125,22 +140,22 @@ namespace Greenshot.Drawing { /// /// Private method, the current image is disposed the new one will stay. /// - /// - private void SetImage(Image image) { + /// The new image + /// true if the old image needs to be disposed, when using undo this should not be true!! + private void SetImage(Image image, bool dispose) { // Dispose - if (Image != null) { + if (Image != null && dispose) { Image.Dispose(); } // Set new values Image = image; - modified = true; } public Surface(Image image) : this() { LOG.Debug("Got image with dimensions " + image.Width + "," + image.Height + " bpp: " + image.PixelFormat); - SetImage(image); + SetImage(image, true); } public Surface(ICapture capture) : this(capture.Image) { @@ -152,6 +167,110 @@ namespace Greenshot.Drawing { } captureDetails = capture.CaptureDetails; } + + /** + * The public accessible Dispose + * Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + */ + public new void Dispose() { + LOG.Debug("Disposing a surface!"); + if (buffer != null) { + buffer.Dispose(); + buffer = null; + } + if (transparencyBackgroundBrush != null) { + transparencyBackgroundBrush.Dispose(); + transparencyBackgroundBrush = null; + } + + // Cleanup undo/redo stacks + while(undoStack != null && undoStack.Count > 0) { + undoStack.Pop().Dispose(); + } + while(redoStack != null && redoStack.Count > 0) { + redoStack.Pop().Dispose(); + } + base.Dispose(); + GC.SuppressFinalize(this); + } + + /// + /// Undo the last action + /// + public void Undo() { + if (undoStack.Count > 0) { + inUndoRedo = true; + IMemento top = undoStack.Pop(); + redoStack.Push(top.Restore()); + inUndoRedo = false; + } + } + + /// + /// Undo an undo (=redo) + /// + public void Redo() { + if (redoStack.Count > 0) { + inUndoRedo = true; + IMemento top = redoStack.Pop(); + undoStack.Push(top.Restore()); + inUndoRedo = false; + } + } + + public bool CanUndo { + get { + return undoStack.Count > 0; + } + } + public bool CanRedo { + get { + return redoStack.Count > 0; + } + } + + public LangKey UndoActionKey { + get { + if (CanUndo) { + return undoStack.Peek().ActionKey; + } else { + return LangKey.none; + } + } + } + public LangKey RedoActionKey { + get { + if (CanRedo) { + return redoStack.Peek().ActionKey; + } else { + return LangKey.none; + } + } + } + + /// + /// Make an action undo-able + /// + /// The memento implementing the undo + public void MakeUndoable(IMemento memento, bool allowMerge) { + if (inUndoRedo) { + throw new InvalidOperationException("Involking do within an undo/redo action."); + } + if (memento != null) { + bool allowPush = true; + if (undoStack.Count > 0 && allowMerge) { + // Check if merge is possible + allowPush = !undoStack.Peek().Merge(memento); + } + if (allowPush) { + // Clear the redo-stack and dispose + while(redoStack.Count > 0) { + redoStack.Pop().Dispose(); + } + undoStack.Push(memento); + } + } + } public void SaveElementsToStream(Stream streamWrite) { try { @@ -211,6 +330,9 @@ namespace Greenshot.Drawing { case DrawingModes.Bitmap: undrawnElement = new BitmapContainer(this); break; + case DrawingModes.Path: + undrawnElement = new FreehandContainer(this); + break; case DrawingModes.None: undrawnElement = null; break; @@ -317,7 +439,7 @@ namespace Greenshot.Drawing { foreach(string filename in dropFileNames) { LOG.Debug("Found filename: " + filename); string ext=Path.GetExtension(filename).ToLower(); - if ((ext==".jpg") || (ext==".gif") || (ext==".png") || (ext==".bmp") || (ext==".wmf")) { + if ((ext==".jpg") || (ext==".jpeg") ||(ext==".tiff") || (ext==".gif") || (ext==".png") || (ext==".bmp") || (ext==".ico") ||(ext==".wmf")) { filenames.Add(filename); } } @@ -379,7 +501,28 @@ namespace Greenshot.Drawing { // } #endregion - bool ApplyCrop(Rectangle cropRectangle) { + /// + /// Auto crop the image + /// + /// true if cropped + public bool AutoCrop() { + Rectangle cropRectangle = ImageHelper.FindAutoCropRectangle(Image); + if (isCropPossible(ref cropRectangle)) { + DrawingMode = DrawingModes.Crop; + cropContainer = new CropContainer(this); + cropContainer.Left = cropRectangle.X; + cropContainer.Top = cropRectangle.Y; + cropContainer.Width = cropRectangle.Width; + cropContainer.Height = cropRectangle.Height; + DeselectAllElements(); + AddElement(cropContainer); + SelectElement(cropContainer); + return true; + } + return false; + } + + public bool isCropPossible(ref Rectangle cropRectangle) { cropRectangle = Helpers.GuiRectangle.GetGuiRectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, cropRectangle.Height); if (cropRectangle.Left < 0) cropRectangle = new Rectangle(0, cropRectangle.Top, cropRectangle.Width + cropRectangle.Left, cropRectangle.Height); if (cropRectangle.Top < 0) cropRectangle = new Rectangle(cropRectangle.Left, 0, cropRectangle.Width, cropRectangle.Height + cropRectangle.Top); @@ -387,34 +530,78 @@ namespace Greenshot.Drawing { if (cropRectangle.Top + cropRectangle.Height > Height) cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Height - cropRectangle.Top); if (cropRectangle.Height > 0 && cropRectangle.Width > 0) { + return true; + } + return false; + } + + public void SendMessageEvent(object source, SurfaceMessageTyp messageType, string message) { + if (SurfaceMessage != null) { + SurfaceMessageEventArgs eventArgs = new SurfaceMessageEventArgs(); + eventArgs.Message = message; + eventArgs.MessageType = messageType; + eventArgs.Surface = this; + SurfaceMessage(source, eventArgs); + } + } + + public bool ApplyCrop(Rectangle cropRectangle) { + if (isCropPossible(ref cropRectangle)) { // we should not forget to Dispose the images!! Bitmap tmpImage = ((Bitmap)Image).Clone(cropRectangle, Image.PixelFormat); tmpImage.SetResolution(Image.HorizontalResolution, Image.VerticalResolution); - SetImage(tmpImage); + + // Make undoable + MakeUndoable(new SurfaceCropMemento(this, cropRectangle), false); + + SetImage(tmpImage, false); elements.MoveBy(-cropRectangle.Left, -cropRectangle.Top); + if (SurfaceSizeChanged != null) { + SurfaceSizeChanged(this); + } Invalidate(); return true; } return false; } - private Point GetMouseCoordinates(MouseEventArgs e) { - //Point mouseLocation = new Point(e.X - AutoScrollPosition.X, e.Y - AutoScrollPosition.Y); - Point mouseLocation = new Point(e.X, e.Y); - return mouseLocation; + public void UndoCrop(Image previous, Rectangle cropRectangle) { + SetImage(previous, false); + elements.MoveBy(cropRectangle.Left, cropRectangle.Top); + if (SurfaceSizeChanged != null) { + SurfaceSizeChanged(this); + } + Invalidate(); } void SurfaceMouseDown(object sender, MouseEventArgs e) { - mouseStart = GetMouseCoordinates(e); + mouseStart = e.Location; + + // check contextmenu + if (e.Button == MouseButtons.Right) { + if (selectedElements != null && selectedElements.Count > 0) { + // ContainerList logik hier + } else { + // Single element + DrawableContainer rightClickedContainer = elements.ClickableElementAt(mouseStart.X, mouseStart.Y); + if (rightClickedContainer != null) { + SelectElement(rightClickedContainer); + rightClickedContainer.ShowContextMenu(e); + } + } + return; + } + mouseDown = true; + isSurfaceMoveMadeUndoable = false; if (cropContainer != null && ((undrawnElement == null) || (undrawnElement != null && DrawingMode != DrawingModes.Crop))) { - RemoveElement(cropContainer); + RemoveElement(cropContainer, false); cropContainer = null; drawingElement = null; } - if(drawingElement == null && DrawingMode != DrawingModes.None) { + if (drawingElement == null && DrawingMode != DrawingModes.None) { if (undrawnElement == null) { DeselectAllElements(); if(undrawnElement == null) { @@ -427,8 +614,10 @@ namespace Greenshot.Drawing { // if a new element has been drawn, set location and register it if (drawingElement != null) { drawingElement.PropertyChanged += ElementPropertyChanged; - drawingElement.Left = mouseStart.X; - drawingElement.Top = mouseStart.Y; + if (!drawingElement.HandleMouseDown(mouseStart.X, mouseStart.Y)) { + drawingElement.Left = mouseStart.X; + drawingElement.Top = mouseStart.Y; + } AddElement(drawingElement); drawingElement.Selected = true; } @@ -437,15 +626,16 @@ namespace Greenshot.Drawing { // we save mouse down element separately from selectedElements (checked on mouse up), // since it could be moved around before it is actually selected mouseDownElement = elements.ClickableElementAt(mouseStart.X, mouseStart.Y); - if(mouseDownElement != null) { + + if (mouseDownElement != null) { mouseDownElement.Status = EditStatus.MOVING; } } } void SurfaceMouseUp(object sender, MouseEventArgs e) { - Point currentMouse = GetMouseCoordinates(e); - + Point currentMouse = new Point(e.X, e.Y); + elements.Status = EditStatus.IDLE; if (mouseDownElement != null) { mouseDownElement.Status = EditStatus.IDLE; @@ -482,11 +672,12 @@ namespace Greenshot.Drawing { } if (drawingElement != null) { - drawingElement.Invalidate(); if (!drawingElement.InitContent()) { elements.Remove(drawingElement); drawingElement.Invalidate(); } else { + drawingElement.HandleMouseUp(currentMouse.X, currentMouse.Y); + drawingElement.Invalidate(); if (Math.Abs(drawingElement.Width) < 5 && Math.Abs(drawingElement.Height) < 5) { drawingElement.Width = 25; drawingElement.Height = 25; @@ -499,8 +690,8 @@ namespace Greenshot.Drawing { } void SurfaceMouseMove(object sender, MouseEventArgs e) { - Point currentMouse = GetMouseCoordinates(e); - + Point currentMouse = e.Location; + if (DrawingMode != DrawingModes.None) { Cursor = Cursors.Cross; } else { @@ -511,10 +702,21 @@ namespace Greenshot.Drawing { if(mouseDownElement != null) { // an element is currently dragged mouseDownElement.Invalidate(); selectedElements.HideGrippers(); + // Move the element if(mouseDownElement.Selected) { + if (!isSurfaceMoveMadeUndoable) { + // Only allow one undoable per mouse-down/move/up "cycle" + isSurfaceMoveMadeUndoable = true; + selectedElements.MakeBoundsChangeUndoable(false); + } // dragged element has been selected before -> move all selectedElements.MoveBy(currentMouse.X - mouseStart.X, currentMouse.Y - mouseStart.Y); } else { + if (!isSurfaceMoveMadeUndoable) { + // Only allow one undoable per mouse-down/move/up "cycle" + isSurfaceMoveMadeUndoable = true; + mouseDownElement.MakeBoundsChangeUndoable(false); + } // dragged element is not among selected elements -> just move dragged one mouseDownElement.MoveBy(currentMouse.X - mouseStart.X, currentMouse.Y - mouseStart.Y); } @@ -522,11 +724,7 @@ namespace Greenshot.Drawing { mouseDownElement.Invalidate(); modified = true; } else if(drawingElement != null) { - // an element is currently drawn - drawingElement.Invalidate(); - drawingElement.Width = currentMouse.X - drawingElement.Left; - drawingElement.Height = currentMouse.Y - drawingElement.Top; - drawingElement.Invalidate(); + drawingElement.HandleMouseMove(currentMouse.X, currentMouse.Y); modified = true; } } @@ -538,11 +736,10 @@ namespace Greenshot.Drawing { } private Image GetImage(RenderMode renderMode) { - Image clone = new Bitmap(Image); - // This actually generates a copy of the original image with a dpi equal to the default... + // Generate a copy of the original image with a dpi equal to the default... + Bitmap clone = ImageHelper.CloneImageToBitmap(Image); // otherwise we would have a problem drawing the image to the surface... :( using (Graphics graphics = Graphics.FromImage(clone)) { - graphics.DrawImage(Image, Point.Empty); elements.Draw(graphics, (Bitmap)clone, renderMode, new Rectangle(Point.Empty, clone.Size)); } return clone; @@ -560,6 +757,10 @@ namespace Greenshot.Drawing { void SurfacePaint(object sender, PaintEventArgs e) { Graphics targetGraphics = e.Graphics; Rectangle clipRectangle = e.ClipRectangle; + if (Rectangle.Empty.Equals(clipRectangle)) { + LOG.Debug("Empty cliprectangle??"); + return; + } if (elements.hasIntersectingFilters(clipRectangle)) { if (buffer != null) { @@ -569,6 +770,7 @@ namespace Greenshot.Drawing { } } if (buffer == null) { + LOG.DebugFormat("Created buffer with size: {0}x{1}", Image.Width, Image.Height); buffer = new Bitmap(Image.Width, Image.Height, Image.PixelFormat); } // Elements might need the bitmap, so we copy the part we need @@ -599,8 +801,20 @@ namespace Greenshot.Drawing { } } - + /// + /// Wrapper for makeUndoable flag which was introduced later, will call AddElement with makeundoable set to true + /// + /// the new element public void AddElement(DrawableContainer element) { + AddElement(element, true); + } + + /// + /// Add a new element to the surface + /// + /// the new element + /// true if the adding should be undoable + public void AddElement(DrawableContainer element, bool makeUndoable) { elements.Add(element); element.FieldChanged += element_FieldChanged; element.PropertyChanged += ElementPropertyChanged; @@ -608,30 +822,29 @@ namespace Greenshot.Drawing { element.Status = EditStatus.IDLE; } element.Invalidate(); + if (makeUndoable) { + MakeUndoable(new AddElementMemento(this, element), false); + } modified = true; } - public void RemoveElement(DrawableContainer element) { + public void RemoveElement(DrawableContainer element, bool makeUndoable) { DeselectElement(element); elements.Remove(element); element.FieldChanged -= element_FieldChanged; element.PropertyChanged -= ElementPropertyChanged; - element.Dispose(); + // Do not dispose, the memento should!! element.Dispose(); element.Invalidate(); + if (makeUndoable) { + MakeUndoable(new DeleteElementMemento(this, element), false); + } modified = true; } public void AddElements(DrawableContainerList elementsToAdd) { - elements.AddRange(elementsToAdd); foreach(DrawableContainer element in elementsToAdd) { - element.FieldChanged += element_FieldChanged; - element.PropertyChanged += ElementPropertyChanged; - if (element.Status == EditStatus.UNDRAWN) { - element.Status = EditStatus.IDLE; - } - element.Invalidate(); + AddElement(element, true); } - modified = true; } public bool HasSelectedElements() { @@ -649,7 +862,7 @@ namespace Greenshot.Drawing { } // Remove now foreach(DrawableContainer element in elementsToRemove) { - RemoveElement(element); + RemoveElement(element, true); } selectedElements.Clear(); MovingElementChanged(this, selectedElements); @@ -675,7 +888,8 @@ namespace Greenshot.Drawing { foreach(DrawableContainer dc in selectedDCs){ if(dc.Equals(cropContainer)){ DrawingMode = DrawingModes.None; - RemoveElement(cropContainer); + // No undo memento for the cropcontainer itself, only for the effect + RemoveElement(cropContainer, false); if(confirm) { ApplyCrop(cropContainer.Bounds); } @@ -706,20 +920,20 @@ namespace Greenshot.Drawing { DeselectAllElements(); SelectElements(dcs); } - } else if (Clipboard.ContainsImage()) { - using (Image image = Clipboard.GetImage()) { + } else if (ClipboardHelper.ContainsImage()) { + using (Image image = ClipboardHelper.GetImage()) { if (image != null) { DeselectAllElements(); IBitmapContainer bitmapContainer = AddBitmapContainer(image as Bitmap, 0, 0); SelectElement(bitmapContainer); } } - } else if (Clipboard.ContainsText()) { - string text = Clipboard.GetText(); + } else if (ClipboardHelper.ContainsText()) { + string text = ClipboardHelper.GetText(); if (text != null) { DeselectAllElements(); ITextContainer textContainer = AddTextContainer(text, HorizontalAlignment.Center, VerticalAlignment.CENTER, - FontFamily.GenericSansSerif, 12f, false, false, false, 2, Color.Black, Color.Transparent); + FontFamily.GenericSansSerif, 12f, false, false, false, 2, Color.Black, Color.Transparent); SelectElement(textContainer); } } @@ -727,7 +941,7 @@ namespace Greenshot.Drawing { public void DuplicateSelectedElements() { if(LOG.IsDebugEnabled) LOG.Debug("Duplicating "+selectedElements.Count+" selected elements"); - DrawableContainerList dcs = (DrawableContainerList)Objects.DeepClone(selectedElements); + DrawableContainerList dcs = selectedElements.Clone(); dcs.Parent = this; dcs.MoveBy(10,10); AddElements(dcs); @@ -785,34 +999,28 @@ namespace Greenshot.Drawing { SelectElement(element); } } - + public void ProcessCmdKey(Keys k) { if (selectedElements.Count > 0) { int px = (k == Keys.Shift) ? 10 : 1; + Point moveBy = Point.Empty; + switch (k) { case Keys.Left: - selectedElements.MoveBy(-1,0); - break; case Keys.Left | Keys.Shift: - selectedElements.MoveBy(-10,0); + moveBy = new Point(-px, 0); break; case Keys.Up: - selectedElements.MoveBy(0,-1); - break; case Keys.Up | Keys.Shift: - selectedElements.MoveBy(0,-10); + moveBy = new Point(0, -px); break; case Keys.Right: - selectedElements.MoveBy(1,0); - break; case Keys.Right | Keys.Shift: - selectedElements.MoveBy(10,0); + moveBy = new Point(px, 0); break; case Keys.Down: - selectedElements.MoveBy(0,1); - break; case Keys.Down | Keys.Shift: - selectedElements.MoveBy(0,10); + moveBy = new Point(0, px); break; case Keys.PageUp: PullElementsUp(); @@ -838,9 +1046,19 @@ namespace Greenshot.Drawing { default: return; } + if (!Point.Empty.Equals(moveBy)) { + selectedElements.MakeBoundsChangeUndoable(true); + selectedElements.MoveBy(moveBy.X, moveBy.Y); + } } } + public DrawableContainerList Elements { + get { + return elements; + } + } + /// /// pulls selected elements up one level in hierarchy /// @@ -889,19 +1107,6 @@ namespace Greenshot.Drawing { return elements.CanPushDown(selectedElements); } - public new void Dispose() { - LOG.Debug("Disposing a surface!"); - if (buffer != null) { - buffer.Dispose(); - buffer = null; - } - if (transparencyBackgroundBrush != null) { - transparencyBackgroundBrush.Dispose(); - transparencyBackgroundBrush = null; - } - base.Dispose(); - } - public void ElementPropertyChanged(object sender, PropertyChangedEventArgs e) { //Invalidate(); } diff --git a/Greenshot/Drawing/TextContainer.cs b/Greenshot/Drawing/TextContainer.cs index 050b41c60..8f9ebee21 100644 --- a/Greenshot/Drawing/TextContainer.cs +++ b/Greenshot/Drawing/TextContainer.cs @@ -19,18 +19,15 @@ * along with this program. If not, see . */ using System; -using System.Collections.Generic; using System.ComponentModel; using System.Drawing; -using System.Drawing.Imaging; -using System.Drawing.Text; using System.Runtime.Serialization; using System.Windows.Forms; -using Greenshot.Configuration; using Greenshot.Drawing.Fields; using Greenshot.Helpers; using Greenshot.Plugin.Drawing; +using Greenshot.Memento; namespace Greenshot.Drawing { /// @@ -39,16 +36,28 @@ namespace Greenshot.Drawing { [Serializable()] public class TextContainer : RectangleContainer, ITextContainer { private bool fontInvalidated = true; + // If makeUndoable is true the next text-change will make the change undoable. + // This is set to true AFTER the first change is made, as there is already a "add element" on the undo stack + private bool makeUndoable = false; private Font font; private string text; + // there is a binding on the following property! public string Text { get { return text; } set { - if((text == null && value != null) || !text.Equals(value)) { - text = value; - OnPropertyChanged("Text"); - } + ChangeText(value, true); + } + } + + internal void ChangeText(string newText, bool allowUndoable) { + if ((text == null && newText != null) || !text.Equals(newText)) { + if (makeUndoable && allowUndoable) { + makeUndoable = false; + parent.MakeUndoable(new TextChangeMemento(this), false); + } + text = newText; + OnPropertyChanged("Text"); } } @@ -57,9 +66,9 @@ namespace Greenshot.Drawing { public TextContainer(Surface parent) : base(parent) { Init(); - AddField(GetType(), FieldType.LINE_THICKNESS, 1); + AddField(GetType(), FieldType.LINE_THICKNESS, 2); AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - AddField(GetType(), FieldType.SHADOW, false); + AddField(GetType(), FieldType.SHADOW, true); AddField(GetType(), FieldType.FONT_ITALIC, false); AddField(GetType(), FieldType.FONT_BOLD, false); AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); @@ -96,8 +105,12 @@ namespace Greenshot.Drawing { */ protected virtual void Dispose(bool disposing) { if (disposing) { - if(textBox != null) textBox.Dispose(); - if(font != null) font.Dispose(); + if (textBox != null) { + textBox.Dispose(); + } + if (font != null) { + font.Dispose(); + } } textBox = null; font = null; @@ -118,23 +131,22 @@ namespace Greenshot.Drawing { } void TextContainer_PropertyChanged(object sender, PropertyChangedEventArgs e) { - if(e.PropertyName.Equals("Selected")) { - if(!Selected && textBox.Visible) HideTextBox(); - else if(Selected && Status==EditStatus.DRAWING) { + if (e.PropertyName.Equals("Selected")) { + if (!Selected && textBox.Visible) { + HideTextBox(); + } else if (Selected && Status==EditStatus.DRAWING) { ShowTextBox(); } - //else if(!textBox.Visible) ShowTextBox(); } - if(textBox.Visible) { + if (textBox.Visible) { UpdateTextBoxPosition(); UpdateTextBoxFormat(); textBox.Invalidate(); } } - void TextContainer_FieldChanged(object sender, FieldChangedEventArgs e) - { - if(textBox.Visible) { + void TextContainer_FieldChanged(object sender, FieldChangedEventArgs e) { + if (textBox.Visible) { UpdateTextBoxFormat(); textBox.Invalidate(); } else { @@ -148,6 +160,7 @@ namespace Greenshot.Drawing { public override void OnDoubleClick() { ShowTextBox(); + textBox.Focus(); } private void CreateTextBox() { @@ -189,34 +202,32 @@ namespace Greenshot.Drawing { bool hasStyle = false; using(FontFamily fam = new FontFamily(fontFamily)) { bool boldAvailable = fam.IsStyleAvailable(FontStyle.Bold); - if(fontBold && boldAvailable) { - fs |= FontStyle.Bold; + if (fontBold && boldAvailable) { + fs |= FontStyle.Bold; hasStyle = true; } bool italicAvailable = fam.IsStyleAvailable(FontStyle.Italic); - if(fontItalic && italicAvailable) { + if (fontItalic && italicAvailable) { fs |= FontStyle.Italic; hasStyle = true; } - if(!hasStyle) { + if (!hasStyle) { bool regularAvailable = fam.IsStyleAvailable(FontStyle.Regular); - if(regularAvailable) { + if (regularAvailable) { fs = FontStyle.Regular; } else { - if(boldAvailable) { + if (boldAvailable) { fs = FontStyle.Bold; } else if(italicAvailable) { fs = FontStyle.Italic; } } } - font = new Font(fam, fontSize, fs, GraphicsUnit.Pixel); } fontInvalidated = false; - } } @@ -243,6 +254,8 @@ namespace Greenshot.Drawing { } void textBox_LostFocus(object sender, EventArgs e) { + // next change will be made undoable + makeUndoable = true; HideTextBox(); } @@ -265,7 +278,7 @@ namespace Greenshot.Drawing { int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); int textOffset = (lineThickness>0) ? (int)Math.Ceiling(lineThickness/2d) : 0; // draw shadow before anything else - if ( shadow && (fillColor == Color.Transparent || fillColor == Color.Empty)) { + if (shadow && (fillColor == Color.Transparent || fillColor == Color.Empty)) { int basealpha = 100; int alpha = basealpha; int steps = 5; @@ -273,7 +286,7 @@ namespace Greenshot.Drawing { while (currentStep <= steps) { int offset = currentStep; Rectangle shadowRect = GuiRectangle.GetGuiRectangle(Left + offset, Top + offset, Width, Height); - if(lineThickness > 0) { + if (lineThickness > 0) { shadowRect.Inflate(-textOffset, -textOffset); } using (Brush fontBrush = new SolidBrush(Color.FromArgb(alpha, 100, 100, 100))) { @@ -286,12 +299,18 @@ namespace Greenshot.Drawing { Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); Rectangle fontRect = rect; - if(lineThickness > 0) { + if (lineThickness > 0) { fontRect.Inflate(-textOffset,-textOffset); } using (Brush fontBrush = new SolidBrush(lineColor)) { g.DrawString(text, font, fontBrush, fontRect); } } + + public override bool ClickableAt(int x, int y) { + Rectangle r = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + r.Inflate(5, 5); + return r.Contains(x, y); + } } } diff --git a/Greenshot/Forms/AboutForm.Designer.cs b/Greenshot/Forms/AboutForm.Designer.cs index fd6652325..cda019b9b 100644 --- a/Greenshot/Forms/AboutForm.Designer.cs +++ b/Greenshot/Forms/AboutForm.Designer.cs @@ -70,7 +70,7 @@ namespace Greenshot { this.lblTitle.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lblTitle.Location = new System.Drawing.Point(108, 12); this.lblTitle.Name = "lblTitle"; - this.lblTitle.Size = new System.Drawing.Size(227, 19); + this.lblTitle.Size = new System.Drawing.Size(263, 19); this.lblTitle.TabIndex = 2; this.lblTitle.Text = "Greenshot x.x.xxx"; // @@ -166,9 +166,9 @@ namespace Greenshot { // // linkLabel1 // - this.linkLabel1.Location = new System.Drawing.Point(304, 8); + this.linkLabel1.Location = new System.Drawing.Point(377, 8); this.linkLabel1.Name = "linkLabel1"; - this.linkLabel1.Size = new System.Drawing.Size(203, 23); + this.linkLabel1.Size = new System.Drawing.Size(130, 23); this.linkLabel1.TabIndex = 13; this.linkLabel1.TabStop = true; this.linkLabel1.Text = "http://getgreenshot.org"; @@ -247,7 +247,7 @@ namespace Greenshot { link.LinkVisited = true; System.Diagnostics.Process.Start(link.Text); } catch (Exception) { - MessageBox.Show(lang.GetString(LangKey.error_openlink),lang.GetString(LangKey.error)); + MessageBox.Show(lang.GetFormattedString(LangKey.error_openlink, link.Text),lang.GetString(LangKey.error)); } } } diff --git a/Greenshot/Forms/AboutForm.cs b/Greenshot/Forms/AboutForm.cs index ceaa13ba8..b0b5f431f 100644 --- a/Greenshot/Forms/AboutForm.cs +++ b/Greenshot/Forms/AboutForm.cs @@ -19,12 +19,14 @@ * along with this program. If not, see . */ using System; -using System.Drawing; using System.Reflection; using System.Windows.Forms; +using System.IO; +using Greenshot.Helpers; using Greenshot.Configuration; using GreenshotPlugin.Core; +using IniFile; namespace Greenshot { /// @@ -41,7 +43,7 @@ namespace Greenshot { Version v = Assembly.GetExecutingAssembly().GetName().Version; // Format is like this: AssemblyVersion("Major.Minor.Build.Revision")] - lblTitle.Text = "Greenshot " + v.Major + "." + v.Minor + "." + v.Build + " Build " + v.Revision; + lblTitle.Text = "Greenshot " + v.Major + "." + v.Minor + "." + v.Build + " Build " + v.Revision + (IniConfig.IsPortable?" Portable":"") + (" (" + OSInfo.Bits +" bit)"); lang = Language.GetInstance(); updateUI(); } @@ -58,14 +60,37 @@ namespace Greenshot { protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { try { - if (msg.WParam.ToInt32() == (int)Keys.Escape) { - this.Close(); - } else { - return base.ProcessCmdKey(ref msg, keyData); + switch (keyData) { + case Keys.Escape: + DialogResult = DialogResult.OK; + break; + case Keys.E: + MessageBox.Show(EnvironmentInfo.EnvironmentToString(true)); + break; + case Keys.L: + try { + if (File.Exists( MainForm.LogFileLocation)) { + System.Diagnostics.Process.Start("\"" + MainForm.LogFileLocation + "\""); + } else { + MessageBox.Show("Greenshot can't write to logfile, otherwise it would be here: " + MainForm.LogFileLocation); + } + } catch (Exception) { + MessageBox.Show("Couldn't open the greenshot.log, it's located here: " + MainForm.LogFileLocation, "Error opening greeenshot.log", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); + } + break; + case Keys.I: + try { + System.Diagnostics.Process.Start("\"" + IniFile.IniConfig.ConfigLocation + "\""); + } catch (Exception) { + MessageBox.Show("Couldn't open the greenshot.ini, it's located here: " + IniFile.IniConfig.ConfigLocation, "Error opening greeenshot.ini", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); + } + break; + default: + return base.ProcessCmdKey(ref msg, keyData); } } catch (Exception) { } - return base.ProcessCmdKey(ref msg,keyData); + return true; } } } diff --git a/Greenshot/Forms/BugReportForm.cs b/Greenshot/Forms/BugReportForm.cs index 40ddca20a..935eaddd3 100644 --- a/Greenshot/Forms/BugReportForm.cs +++ b/Greenshot/Forms/BugReportForm.cs @@ -19,11 +19,7 @@ * along with this program. If not, see . */ using System; -using System.Drawing; -using System.Net; -using System.Web; using System.Windows.Forms; - using Greenshot.Configuration; using Greenshot.Helpers; using GreenshotPlugin.Core; @@ -59,9 +55,9 @@ namespace Greenshot.Forms { private void openLink(LinkLabel link) { try { link.LinkVisited = true; - System.Diagnostics.Process.Start(link.Text); + System.Diagnostics.Process.Start(link.Text); } catch (Exception) { - MessageBox.Show(lang.GetString(LangKey.error_openlink),lang.GetString(LangKey.error)); + MessageBox.Show(lang.GetFormattedString(LangKey.error_openlink, link.Text),lang.GetString(LangKey.error)); } } } diff --git a/Greenshot/Forms/CaptureForm.Designer.cs b/Greenshot/Forms/CaptureForm.Designer.cs index dc6033d91..6421c07fb 100644 --- a/Greenshot/Forms/CaptureForm.Designer.cs +++ b/Greenshot/Forms/CaptureForm.Designer.cs @@ -75,8 +75,8 @@ namespace Greenshot.Forms { this.ShowIcon = false; this.ShowInTaskbar = false; this.TopMost = true; - this.VisibleChanged += new System.EventHandler(this.CaptureFormVisibleChanged); this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.CaptureFormKeyDown); + this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.CaptureFormKeyUp); ((System.ComponentModel.ISupportInitialize)(this.pictureBox)).EndInit(); this.Visible = false; this.ResumeLayout(false); diff --git a/Greenshot/Forms/CaptureForm.cs b/Greenshot/Forms/CaptureForm.cs index cf604ee93..18a0e1d9e 100644 --- a/Greenshot/Forms/CaptureForm.cs +++ b/Greenshot/Forms/CaptureForm.cs @@ -19,37 +19,38 @@ * along with this program. If not, see . */ using System; -using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Drawing; using System.Drawing.Drawing2D; -using System.Drawing.Imaging; using System.Drawing.Printing; using System.IO; -using System.Text; using System.Windows.Forms; using Greenshot.Configuration; using Greenshot.Drawing; using Greenshot.Helpers; using Greenshot.Plugin; -using Greenshot.UnmanagedHelpers; +using GreenshotPlugin.UnmanagedHelpers; using GreenshotPlugin.Core; +using IniFile; namespace Greenshot.Forms { /// /// Description of CaptureForm. /// - public partial class CaptureForm : Form, ICaptureHost { + public partial class CaptureForm : Form { + private enum FixMode {None, Initiated, Horizontal, Vertical}; + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(CaptureForm)); private static CoreConfiguration conf = IniConfig.GetIniSection(); + private static Brush GreenOverlayBrush = new SolidBrush(Color.FromArgb(50, Color.MediumSeaGreen)); + private static Brush RedOverlayBrush = new SolidBrush(Color.FromArgb(50, Color.DarkRed)); + private static Pen OverlayPen = new Pen(Color.FromArgb(50, Color.Black)); private int mX; private int mY; private Point cursorPos = Point.Empty; - // TODO: dispose Brush & Pen, not very important as we only instanciate this once - private Brush OverlayBrush = new SolidBrush(Color.FromArgb(50, Color.MediumSeaGreen)); - private Pen OverlayPen = new Pen(Color.FromArgb(50, Color.Black)); private CaptureMode captureMode = CaptureMode.None; private List windows = new List(); private WindowDetails selectedCaptureWindow; @@ -58,480 +59,80 @@ namespace Greenshot.Forms { private ICapture capture = null; private ILanguage lang = Language.GetInstance(); - public CaptureForm() { + private Point previousMousePos = Point.Empty; + private FixMode fixMode = FixMode.None; + + public Rectangle CaptureRectangle { + get { + return captureRect; + } + } + + public CaptureMode UsedCaptureMode { + get { + return captureMode; + } + } + + public WindowDetails SelectedCaptureWindow { + get { + return selectedCaptureWindow; + } + } + + public CaptureForm(ICapture capture, List windows) { + this.capture = capture; + this.windows = windows; + captureMode = capture.CaptureDetails.CaptureMode; + // // The InitializeComponent() call is required for Windows Forms designer support. // InitializeComponent(); this.Text = "Greenshot capture form"; - // Make sure the form is hidden (might be overdoing it...) - this.Hide(); - } + // Make sure we never capture the captureform + WindowDetails.RegisterIgnoreHandle(this.Handle); + // TODO: Need to call unregister at close - void DoCaptureFeedback() { - if(conf.PlayCameraSound) { - SoundHelper.Play(); - } - } + // set cursor location + cursorPos = WindowCapture.GetCursorLocation(); + // Offset to screen coordinates + cursorPos.Offset(-capture.ScreenBounds.X, -capture.ScreenBounds.Y); - /// - /// Make Capture with default destinations - /// - /// CaptureMode - /// bool false if the mouse should not be captured, true if the configuration should be checked - public void MakeCapture(CaptureMode mode, bool captureMouseCursor) { - Capture passingCapture = new Capture(); - MakeCapture(mode, captureMouseCursor, passingCapture); - } - - /// - /// Make capture of window - /// - /// WindowDetails of the window to capture - public void MakeCapture(WindowDetails window) { - MakeCapture(window, null); - } - - /// - /// Make capture of window - /// - /// WindowDetails of the window to capture - /// bool false if the mouse should not be captured, true if the configuration should be checked - public void MakeCapture(WindowDetails window, CaptureHandler captureHandler) { - Capture passingCapture = new Capture(); - passingCapture.CaptureDetails.CaptureHandler = captureHandler; - selectedCaptureWindow = window; - MakeCapture(CaptureMode.ActiveWindow, false, passingCapture); - } - - /// - /// Make Capture with default destinations - /// - /// CaptureMode - /// bool false if the mouse should not be captured, true if the configuration should be checked - public void MakeCapture(CaptureMode mode, bool captureMouseCursor, CaptureHandler captureHandler) { - Capture passingCapture = new Capture(); - passingCapture.CaptureDetails.CaptureHandler = captureHandler; - MakeCapture(mode, captureMouseCursor, passingCapture); - } - - - /// - /// Make Capture with specified destinations - /// - /// CaptureMode - /// bool false if the mouse should not be captured, true if the configuration should be checked - /// List with destinations - public void MakeCapture(CaptureMode mode, bool captureMouseCursor, List captureDestinations) { - Capture passingCapture = new Capture(); - passingCapture.CaptureDetails.CaptureDestinations = captureDestinations; - MakeCapture(mode, captureMouseCursor, passingCapture); - } - - /// - /// Make Capture with file name - /// - /// List with destinations - public void MakeCapture(string filename) { - Capture passingCapture = new Capture(); - passingCapture.CaptureDetails.Filename = filename; - MakeCapture(CaptureMode.File, false, passingCapture); - } - - /// - /// Make Capture with specified destinations - /// - /// CaptureMode - /// bool false if the mouse should not be captured, true if the configuration should be checked - /// List with destinations - private void MakeCapture(CaptureMode mode, bool captureMouseCursor, ICapture newCapture) { - if (captureMode != CaptureMode.None) { - LOG.Warn(String.Format("Capture started while capturing, current mode = {0} new capture was {1}.", captureMode, mode)); - return; - } else { - LOG.Debug(String.Format("MakeCapture({0}, {1})", mode, captureMouseCursor)); - } - captureMode = mode; + this.SuspendLayout(); + pictureBox.Image = capture.Image; + this.Bounds = capture.ScreenBounds; + this.ResumeLayout(); - // cleanup the previos information if there is still any - if (capture != null) { - LOG.Debug("Capture wasn't disposed yet, this would suggest a leak"); - capture.Dispose(); - capture = null; - } - // Use the supplied Capture information - capture = newCapture; - capture.CaptureDetails.CaptureMode = mode; + // Fix missing focus + WindowDetails.ToForeground(this.Handle); + } - // Workaround for proble with DPI retrieval, the FromHwnd activates the window... - WindowDetails previouslyActiveWindow = WindowDetails.GetActiveWindow(); - // Workaround for changed DPI settings in Windows 7 - using (Graphics graphics = Graphics.FromHwnd(this.Handle)) { - capture.CaptureDetails.DpiX = graphics.DpiX; - capture.CaptureDetails.DpiY = graphics.DpiY; - } - if (previouslyActiveWindow != null) { - // Set previouslyActiveWindow as foreground window - previouslyActiveWindow.ToForeground(); - } - - // Delay for the Context menu - if (conf.CaptureDelay > 0) { - System.Threading.Thread.Sleep(conf.CaptureDelay); - } else { - conf.CaptureDelay = 0; - } - - // Allways capture Mousecursor, only show when needed - capture = WindowCapture.CaptureCursor(capture); - capture.CursorVisible = false; - // Check if needed - if (captureMouseCursor && mode != CaptureMode.Clipboard && mode != CaptureMode.File) { - capture.CursorVisible = conf.CaptureMousepointer; - } - - switch(mode) { - case CaptureMode.Window: - capture = WindowCapture.CaptureScreen(capture); - capture.CaptureDetails.AddMetaData("source", "Screen"); - CaptureWithFeedback(); - break; - case CaptureMode.ActiveWindow: - if (CaptureActiveWindow()) { - // Capture worked, offset mouse according to screen bounds and capture location - capture.MoveMouseLocation(capture.ScreenBounds.Location.X-capture.Location.X, capture.ScreenBounds.Location.Y-capture.Location.Y); - capture.CaptureDetails.AddMetaData("source", "Window"); - } else { - captureMode = CaptureMode.FullScreen; - capture = WindowCapture.CaptureScreen(capture); - capture.CaptureDetails.AddMetaData("source", "Screen"); - capture.CaptureDetails.Title = "Screen"; - } - // Make sure capturing is stopped at any cost - StopCapturing(false); - HandleCapture(); - break; - case CaptureMode.IE: - if (IECaptureHelper.CaptureIE(capture) != null) { - capture.CaptureDetails.AddMetaData("source", "Internet Explorer"); - HandleCapture(); - } else { - StopCapturing(true); - } - break; - case CaptureMode.FullScreen: - capture = WindowCapture.CaptureScreen(capture); - HandleCapture(); - break; - case CaptureMode.Clipboard: - Image clipboardImage = null; - string text = "Clipboard"; - if (Clipboard.ContainsImage()) { - clipboardImage = Clipboard.GetImage(); - } - if (clipboardImage != null) { - if (capture != null) { - capture.Image = clipboardImage; - } else { - capture = new Capture(clipboardImage); - } - string title = Clipboard.GetText(); - if (title == null || title.Trim().Length == 0) { - title = "Clipboard"; - } - capture.CaptureDetails.Title = title; - capture.CaptureDetails.AddMetaData("source", "Clipboard"); - // Force Editor - capture.CaptureDetails.AddDestination(CaptureDestination.Editor); - HandleCapture(); - } else { - MessageBox.Show("Couldn't create bitmap from : " + text); - } - break; - case CaptureMode.File: - Bitmap fileBitmap = null; - try { - fileBitmap = new Bitmap(capture.CaptureDetails.Filename, true); - } catch (Exception e) { - LOG.Error(e.Message, e); - MessageBox.Show(lang.GetFormattedString(LangKey.error_openfile, capture.CaptureDetails.Filename)); - } - capture.CaptureDetails.Title = Path.GetFileNameWithoutExtension(capture.CaptureDetails.Filename); - capture.CaptureDetails.AddMetaData("file", capture.CaptureDetails.Filename); - capture.CaptureDetails.AddMetaData("source", "file"); - if (fileBitmap != null) { - if (capture != null) { - capture.Image = fileBitmap; - } else { - capture = new Capture(fileBitmap); - } - // Force Editor - capture.CaptureDetails.AddDestination(CaptureDestination.Editor); - HandleCapture(); - } - break; - case CaptureMode.LastRegion: - if (!RuntimeConfig.LastCapturedRegion.Equals(Rectangle.Empty)) { - capture = WindowCapture.CaptureRectangle(capture, RuntimeConfig.LastCapturedRegion); - capture.CaptureDetails.AddMetaData("source", "screen"); - HandleCapture(); - } - break; - case CaptureMode.Region: - capture = WindowCapture.CaptureScreen(capture); - capture.CaptureDetails.AddMetaData("source", "screen"); - CaptureWithFeedback(); - break; - default: - LOG.Warn("Unknown capture mode: " + mode); - break; + #region key handling + void CaptureFormKeyUp(object sender, KeyEventArgs e) { + if (e.KeyCode == Keys.ShiftKey) { + fixMode = FixMode.None; } } - private ICapture AddConfiguredDestination(ICapture capture) { - if (conf.OutputDestinations.Contains(Destination.FileDefault)) { - capture.CaptureDetails.AddDestination(CaptureDestination.File); - } - - if (conf.OutputDestinations.Contains(Destination.FileWithDialog)) { - capture.CaptureDetails.AddDestination(CaptureDestination.FileWithDialog); - } - - if (conf.OutputDestinations.Contains(Destination.Clipboard)) { - capture.CaptureDetails.AddDestination(CaptureDestination.Clipboard); - } - - if (conf.OutputDestinations.Contains(Destination.Printer)) { - capture.CaptureDetails.AddDestination(CaptureDestination.Printer); - } - - if (conf.OutputDestinations.Contains(Destination.Editor)) { - capture.CaptureDetails.AddDestination(CaptureDestination.Editor); - } - - if (conf.OutputDestinations.Contains(Destination.EMail)) { - capture.CaptureDetails.AddDestination(CaptureDestination.EMail); - } - return capture; - } - - /// - /// Process a bitmap like it was captured - /// - /// The bitmap to process - public void HandleCapture(Bitmap bitmap) { - Capture capture = new Capture(bitmap); - HandleCapture(capture); - } - - // This is also an ICapture Interface implementation - public void HandleCapture(Capture capture) { - this.capture = capture; - HandleCapture(); - } - - private void HandleCapture() { - string fullPath = null; - // Flag to see if the image was "exported" so the FileEditor doesn't - // ask to save the file as long as nothing is done. - bool outputMade = false; - - // Make sure the user sees that the capture is made - if (capture.CaptureDetails.CaptureMode != CaptureMode.File && capture.CaptureDetails.CaptureMode != CaptureMode.Clipboard) { - DoCaptureFeedback(); - } else { - // If File || Clipboard - // Maybe not "made" but the original is still there... somehow - outputMade = true; - } - - LOG.Debug("A capture of: " + capture.CaptureDetails.Title); - - // Create event OnCaptureTaken for all Plugins - PluginHelper.instance.CreateCaptureTakenEvent(capture); - - // check if someone has passed a handler - if (capture.CaptureDetails.CaptureHandler != null) { - CaptureTakenEventArgs eventArgs = new CaptureTakenEventArgs(capture); - capture.CaptureDetails.CaptureHandler(this, eventArgs); - } else if (capture.CaptureDetails.CaptureDestinations == null || capture.CaptureDetails.CaptureDestinations.Count == 0) { - AddConfiguredDestination(capture); - } - - // Create Surface with capture, this way elements can be added automatically (like the mouse cursor) - Surface surface = new Surface(capture); - - // As the surfaces copies the reference to the image, make sure the image is not being disposed (a trick to save memory) - capture.Image = null; - - // Call plugins to do something with the screenshot - PluginHelper.instance.CreateSurfaceFromCaptureEvent(capture, surface); - - // Disable capturing - captureMode = CaptureMode.None; - - // Retrieve important information from the Capture object - ICaptureDetails captureDetails = capture.CaptureDetails; - List captureDestinations = capture.CaptureDetails.CaptureDestinations; - - // Dispose the capture, we don't need it anymore (the surface copied all information and we got the title (if any)). - capture.Dispose(); - capture = null; - - // Want to add more stuff to the surface?? DO IT HERE! - int destinationsCount = captureDestinations.Count; - if (captureDestinations.Contains(CaptureDestination.Editor)) { - destinationsCount--; - } - if (destinationsCount > 0) { - // Create Image for writing/printing etc and use "using" as all code paths either output the image or copy the image - using (Image image = surface.GetImageForExport()) { - // Flag to detect if we need to create a temp file for the email - // or use the file that was written - bool fileWritten = false; - if (captureDestinations.Contains(CaptureDestination.File)) { - string pattern = conf.OutputFileFilenamePattern; - if (pattern == null || string.IsNullOrEmpty(pattern.Trim())) { - pattern = "greenshot ${capturetime}"; - } - string filename = FilenameHelper.GetFilenameFromPattern(pattern, conf.OutputFileFormat, captureDetails); - string filepath = FilenameHelper.FillVariables(conf.OutputFilePath); - fullPath = Path.Combine(filepath,filename); - - // Catching any exception to prevent that the user can't write in the directory. - // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218, #3004642 - try { - ImageOutput.Save(image, fullPath); - fileWritten = true; - outputMade = true; - } catch (Exception e) { - LOG.Error("Error saving screenshot!", e); - // Show the problem - MessageBox.Show(lang.GetString(LangKey.error_save), lang.GetString(LangKey.error)); - // when save failed we present a SaveWithDialog - fullPath = ImageOutput.SaveWithDialog(image, captureDetails); - fileWritten = (fullPath != null); - } - } - - if (captureDestinations.Contains(CaptureDestination.FileWithDialog)) { - fullPath = ImageOutput.SaveWithDialog(image, captureDetails); - fileWritten = (fullPath != null); - outputMade = outputMade || fileWritten; - } - - if (captureDestinations.Contains(CaptureDestination.Clipboard)) { - ClipboardHelper.SetClipboardData(image); - outputMade = true; - } - - if (captureDestinations.Contains(CaptureDestination.Printer)) { - PrinterSettings printerSettings = new PrintHelper(image, captureDetails).PrintWithDialog(); - outputMade = outputMade || printerSettings != null; - } - - if (captureDestinations.Contains(CaptureDestination.EMail)) { - if (!fileWritten) { - MapiMailMessage.SendImage(image, captureDetails); - } else { - MapiMailMessage.SendImage(fullPath, captureDetails.Title, false); - } - // Don't know how to handle a cancel in the email - outputMade = true; - } - } - } - // Make sure we don't have garbage before opening the screenshot - GC.Collect(); - GC.WaitForPendingFinalizers(); - - // If the editor is opened, let it Dispose the surface! - if (captureDestinations.Contains(CaptureDestination.Editor)) { - try { - ImageEditorForm editor = new ImageEditorForm(surface, outputMade); - - if (fullPath != null) { - editor.SetImagePath(fullPath); - } - editor.Show(); - editor.Activate(); - LOG.Debug("Finished opening Editor"); - } catch (Exception e) { - // Dispose the surface when an error is caught - surface.Dispose(); - throw e; - } - } else { - // Dispose the surface, we are done with it! - surface.Dispose(); - } - - // Make CaptureForm invisible - this.Visible = false; - // Hiding makes the editor (if any) get focus - this.Hide(); - } - - /** - * Finishing the whole Capture with Feedback flow, passing the result on to the HandleCapture - */ - private void finishCaptureWithFeedback() { - // Get title - if (selectedCaptureWindow != null) { - if (capture == null) { - capture = new Capture(); - } - capture.CaptureDetails.Title = selectedCaptureWindow.Text; - } - - if (captureRect.Height > 0 && captureRect.Width > 0) { - // Take the captureRect, this already is specified as bitmap coordinates - capture.Crop(captureRect); - // save for re-capturing later and show recapture context menu option - RuntimeConfig.LastCapturedRegion = captureRect; - - StopCapturing(false); - HandleCapture(); - } - } - - /** - * Stopping the whole Capture with Feedback flow - */ - private void StopCapturing(bool cleanupCapture) { - mouseDown = false; - // Disable the capture mode - captureMode = CaptureMode.None; - cursorPos.X = 0; - cursorPos.Y = 0; - captureRect = Rectangle.Empty; - if (cleanupCapture && capture != null) { - capture.Dispose(); - capture = null; - } - this.Hide(); - - // Example of how to capture a scrolling window... somewhat... -// if (selectedCaptureWindow.hasVScroll()) { -// using (Image captured = selectedCaptureWindow.PrintWithVScroll()) { -// Quantizer quantizer = new OctreeQuantizer(255,8); -// using (Image imageToSave = quantizer.Quantize(captured)) { -// imageToSave.Save(@"D:\BLA.PNG", ImageFormat.Png); -// } -// } -// } - selectedCaptureWindow = null; - } - - #region key handling void CaptureFormKeyDown(object sender, KeyEventArgs e) { + // Check fixmode + if (e.KeyCode == Keys.ShiftKey) { + if (fixMode == FixMode.None) { + fixMode = FixMode.Initiated; + return; + } + } if (e.KeyCode == Keys.Escape) { - StopCapturing(true); + DialogResult = DialogResult.Cancel; } else if (e.KeyCode == Keys.M) { // Toggle mouse cursor capture.CursorVisible = !capture.CursorVisible; - PictureBoxMouseMove(this, new MouseEventArgs(MouseButtons.None, 0, Cursor.Position.X, Cursor.Position.Y, 0)); + pictureBox.Invalidate(); + } else if (e.KeyCode == Keys.V && conf.isExperimentalFeatureEnabled("Video")) { + capture.CaptureDetails.CaptureMode = CaptureMode.Video; + pictureBox.Invalidate(); } else if (e.KeyCode == Keys.Space) { switch (captureMode) { case CaptureMode.Region: @@ -545,203 +146,11 @@ namespace Greenshot.Forms { selectedCaptureWindow = null; PictureBoxMouseMove(this, new MouseEventArgs(MouseButtons.None, 0, Cursor.Position.X, Cursor.Position.Y, 0)); } else if (e.KeyCode == Keys.Return && captureMode == CaptureMode.Window) { - finishCaptureWithFeedback(); + DialogResult = DialogResult.OK; } } #endregion - private bool CaptureActiveWindow() { - bool presupplied = false; - LOG.Debug("CaptureActiveWindow"); - if (selectedCaptureWindow != null) { - LOG.Debug("Using supplied window"); - presupplied = true; - } else { - selectedCaptureWindow = WindowDetails.GetActiveWindow(); - if (selectedCaptureWindow != null) { - LOG.DebugFormat("Capturing window: {0} with {1}", selectedCaptureWindow.Text, selectedCaptureWindow.ClientRectangle); - } - } - if (selectedCaptureWindow == null || (!presupplied && selectedCaptureWindow.Iconic)) { - LOG.Warn("No window to capture!"); - // Nothing to capture, code up in the stack will capture the full screen - return false; - } - if (selectedCaptureWindow.Iconic) { - // Restore the window making sure it's visible! - // This is done mainly for a screen capture, but some applications like Excel and TOAD have weird behaviour! - selectedCaptureWindow.Restore(); - } - selectedCaptureWindow = SelectCaptureWindow(selectedCaptureWindow); - if (selectedCaptureWindow == null) { - LOG.Warn("No window to capture, after SelectCaptureWindow!"); - // Nothing to capture, code up in the stack will capture the full screen - return false; - } - return CaptureWindow(selectedCaptureWindow, capture, conf.WindowCaptureMode) != null; - } - - /// - /// Select the window to capture, this has logic which takes care of certain special applications - /// like TOAD or Excel - /// - /// WindowDetails with the target Window - /// WindowDetails with the target Window OR a replacement - public static WindowDetails SelectCaptureWindow(WindowDetails windowToCapture) { - Rectangle windowRectangle = windowToCapture.ClientRectangle; - if (windowToCapture.Iconic || windowRectangle.Width == 0 || windowRectangle.Height == 0) { - LOG.WarnFormat("Window {0} has nothing to capture, using workaround to find other window of same process.", windowToCapture.Text); - // Trying workaround, the size 0 arrises with e.g. Toad.exe, has a different Window when minimized - WindowDetails linkedWindow = WindowDetails.GetLinkedWindow(windowToCapture); - if (linkedWindow != null) { - windowRectangle = linkedWindow.ClientRectangle; - windowToCapture = linkedWindow; - } else { - return null; - } - } - return windowToCapture; - } - - /// - /// Capture the supplied Window - /// - /// Window to capture - /// The capture to store the details - /// What WindowCaptureMode to use - /// - public static ICapture CaptureWindow(WindowDetails windowToCapture, ICapture captureForWindow, WindowCaptureMode windowCaptureMode) { - Rectangle windowRectangle = windowToCapture.ClientRectangle; - if (windowToCapture.Iconic) { - // Restore the window making sure it's visible! - windowToCapture.Restore(); - } - - // When Vista & DWM (Aero) enabled - bool dwmEnabled = DWM.isDWMEnabled(); - - // For WindowCaptureMode.Auto we check: - // 1) Is window IE, use IE Capture - // 2) Is Windows >= Vista & DWM enabled: use DWM - // 3) Otherwise use GDI (Screen might be also okay but might lose content) - if (windowCaptureMode == WindowCaptureMode.Auto) { - if (windowToCapture.ClassName == "IEFrame") { - ICapture ieCapture = IECaptureHelper.CaptureIE(captureForWindow); - if (ieCapture != null) { - return ieCapture; - } - } - - // Take default GDI - windowCaptureMode = WindowCaptureMode.GDI; - // Take DWM if enabled - if (dwmEnabled) { - windowCaptureMode = WindowCaptureMode.Aero; - } - } else if (windowCaptureMode == WindowCaptureMode.Aero || windowCaptureMode == WindowCaptureMode.AeroTransparent) { - if (!dwmEnabled) { - windowCaptureMode = WindowCaptureMode.GDI; - } - } - LOG.DebugFormat("Capturing window with mode {0}", windowCaptureMode); - switch(windowCaptureMode) { - case WindowCaptureMode.GDI: - // GDI - captureForWindow = windowToCapture.CaptureWindow(captureForWindow); - break; - case WindowCaptureMode.Aero: - case WindowCaptureMode.AeroTransparent: - // DWM - captureForWindow = windowToCapture.CaptureDWMWindow(captureForWindow, windowCaptureMode); - break; - case WindowCaptureMode.Screen: - default: - // Screen capture - windowRectangle.Intersect(captureForWindow.ScreenBounds); - try { - captureForWindow = WindowCapture.CaptureRectangle(captureForWindow, windowRectangle); - } catch (Exception e) { - LOG.Error("Problem capturing", e); - return null; - } - break; - } - captureForWindow.CaptureDetails.Title = windowToCapture.Text; - ((Bitmap)captureForWindow.Image).SetResolution(captureForWindow.CaptureDetails.DpiX, captureForWindow.CaptureDetails.DpiY); - return captureForWindow; - } - - #region capture with feedback - private void CaptureWithFeedback() { - windows.Clear(); - // Start Enumeration of "active" windows - foreach(WindowDetails window in WindowDetails.GetAllWindows()) { - // Window should be visible and not ourselves - if (!window.Visible) { - continue; - } - if (window.Handle.Equals(this.Handle)) { - continue; - } - // Skip empty - Size windowSize = window.ClientRectangle.Size; - if (windowSize.Width == 0 || windowSize.Height == 0) { - continue; - } - windows.Add(window); - } - - // Reset "previous" cursor location - cursorPos = WindowCapture.GetCursorLocation(); - // Offset to screen coordinates - cursorPos.Offset(-capture.ScreenBounds.X, -capture.ScreenBounds.Y); - - this.SuspendLayout(); - pictureBox.Image = capture.Image; - this.Bounds = capture.ScreenBounds; - this.ResumeLayout(); - this.Visible = true; - // Fix missing focus - WindowDetails.ToForeground(this.Handle); - } - - /// - /// Helper Method for finding the current Window in the available rectangles - /// - /// WindowDetails - private WindowDetails FindCurrentWindow() { - foreach(WindowDetails window in windows) { - Rectangle windowRectangle = window.ClientRectangle; - if (windowRectangle.Contains(Cursor.Position)) { - WindowDetails selectedChild = null; - Rectangle selectedChildRectangle = Rectangle.Empty; - // Check if Children need to be parsed (only if "pgdn" was used) - foreach(WindowDetails childWindow in window.Children) { - windowRectangle = childWindow.ClientRectangle; - if (windowRectangle.Contains(Cursor.Position)) { - if (selectedChild == null) { - selectedChild = childWindow; - selectedChildRectangle = selectedChild.ClientRectangle; - } else { - Rectangle childRectangle = childWindow.ClientRectangle; - int sizeCurrent = childRectangle.Height * childRectangle.Width; - int sizeSelected = selectedChildRectangle.Height * selectedChildRectangle.Width; - if (sizeCurrent < sizeSelected) { - selectedChild = childWindow; - } - } - } - } - if (selectedChild != null) { - return selectedChild; - } - return window; - } - } - return null; - } - #endregion - #region pictureBox events void PictureBoxMouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { @@ -759,13 +168,12 @@ namespace Greenshot.Forms { void PictureBoxMouseUp(object sender, MouseEventArgs e) { if (mouseDown) { - pictureBox.Invalidate(); // If the mouse goes up we set down to false (nice logic!) mouseDown = false; // Check if anything is selected if (captureMode == CaptureMode.Window && selectedCaptureWindow != null) { // Go and process the capture - finishCaptureWithFeedback(); + DialogResult = DialogResult.OK; } else if (captureRect.Height > 0 && captureRect.Width > 0) { // correct the GUI width to real width if Region mode if (captureMode == CaptureMode.Region) { @@ -773,14 +181,34 @@ namespace Greenshot.Forms { captureRect.Height += 1; } // Go and process the capture - finishCaptureWithFeedback(); + DialogResult = DialogResult.OK; + } else { + pictureBox.Invalidate(); } } } + + private Point FixMouseCoordinates(Point currentMouse) { + if (fixMode == FixMode.Initiated) { + if (previousMousePos.X != currentMouse.X) { + fixMode = FixMode.Vertical; + } else if (previousMousePos.Y != currentMouse.Y) { + fixMode = FixMode.Horizontal; + } + } else if (fixMode == FixMode.Vertical) { + currentMouse = new Point(currentMouse.X, previousMousePos.Y); + } else if (fixMode == FixMode.Horizontal) { + currentMouse = new Point(previousMousePos.X, currentMouse.Y); + } + previousMousePos = currentMouse; + return currentMouse; + } void PictureBoxMouseMove(object sender, MouseEventArgs e) { Point lastPos = new Point(cursorPos.X, cursorPos.Y); cursorPos = WindowCapture.GetCursorLocation(); + // Make sure the mouse coordinates are fixed, when pressing shift + cursorPos = FixMouseCoordinates(cursorPos); // As the cursorPos is not in Bitmap coordinates, we need to correct. cursorPos.Offset(-capture.ScreenBounds.Location.X, -capture.ScreenBounds.Location.Y); Rectangle lastCaptureRect = new Rectangle(captureRect.Location, captureRect.Size); @@ -800,21 +228,30 @@ namespace Greenshot.Forms { } // Iterate over the found windows and check if the current location is inside a window - selectedCaptureWindow = FindCurrentWindow(); - if (selectedCaptureWindow != null && !selectedCaptureWindow.Equals(lastWindow)) { - if (capture == null) { - capture = new Capture(); + Point cursorPosition = Cursor.Position; + selectedCaptureWindow = null; + foreach (WindowDetails window in windows) { + if (window.Contains(cursorPosition)) { + // Only go over the children if we are in window mode + if (CaptureMode.Window == captureMode) { + selectedCaptureWindow = window.FindChildUnderPoint(cursorPosition); + } else { + selectedCaptureWindow = window; + } + break; } + } + if (selectedCaptureWindow != null && !selectedCaptureWindow.Equals(lastWindow)) { capture.CaptureDetails.Title = selectedCaptureWindow.Text; capture.CaptureDetails.AddMetaData("windowtitle", selectedCaptureWindow.Text); if (captureMode == CaptureMode.Window) { // Here we want to capture the window which is under the mouse - captureRect = selectedCaptureWindow.ClientRectangle; + captureRect = selectedCaptureWindow.WindowRectangle; // As the ClientRectangle is not in Bitmap coordinates, we need to correct. captureRect.Offset(-capture.ScreenBounds.Location.X, -capture.ScreenBounds.Location.Y); } } - if (mouseDown) { + if (mouseDown && (CaptureMode.Window != captureMode)) { int x1 = Math.Min(mX, lastPos.X); int x2 = Math.Max(mX, lastPos.X); int y1 = Math.Min(mY, lastPos.Y); @@ -845,34 +282,36 @@ namespace Greenshot.Forms { pictureBox.Invalidate(invalidateRectangle); } else { if (captureMode == CaptureMode.Window) { - if (!selectedCaptureWindow.Equals(lastWindow)) { + if (selectedCaptureWindow != null && !selectedCaptureWindow.Equals(lastWindow)) { // Using a 50 Pixel offset to the left, top, to make sure the text is invalidated too const int SAFETY_SIZE = 50; Rectangle invalidateRectangle = new Rectangle(lastCaptureRect.Location, lastCaptureRect.Size); - invalidateRectangle.X -= SAFETY_SIZE; - invalidateRectangle.Y -= SAFETY_SIZE; + invalidateRectangle.X -= SAFETY_SIZE/2; + invalidateRectangle.Y -= SAFETY_SIZE/2; invalidateRectangle.Width += SAFETY_SIZE; invalidateRectangle.Height += SAFETY_SIZE; pictureBox.Invalidate(invalidateRectangle); invalidateRectangle = new Rectangle(captureRect.Location, captureRect.Size); - invalidateRectangle.X -= SAFETY_SIZE; - invalidateRectangle.Y -= SAFETY_SIZE; + invalidateRectangle.X -= SAFETY_SIZE/2; + invalidateRectangle.Y -= SAFETY_SIZE/2; invalidateRectangle.Width += SAFETY_SIZE; invalidateRectangle.Height += SAFETY_SIZE; pictureBox.Invalidate(invalidateRectangle); } } else { - if (verticalMove) { - Rectangle before = GuiRectangle.GetGuiRectangle(0, lastPos.Y - 2, this.Width, 45); - Rectangle after = GuiRectangle.GetGuiRectangle(0, cursorPos.Y - 2, this.Width, 45); - pictureBox.Invalidate(before); - pictureBox.Invalidate(after); - } - if (horizontalMove) { - Rectangle before = GuiRectangle.GetGuiRectangle(lastPos.X - 2, 0, 75, this.Height); - Rectangle after = GuiRectangle.GetGuiRectangle(cursorPos.X -2, 0, 75, this.Height); - pictureBox.Invalidate(before); - pictureBox.Invalidate(after); + if (!conf.OptimizeForRDP) { + if (verticalMove) { + Rectangle before = GuiRectangle.GetGuiRectangle(0, lastPos.Y - 2, this.Width+2, 45); + Rectangle after = GuiRectangle.GetGuiRectangle(0, cursorPos.Y - 2, this.Width+2, 45); + pictureBox.Invalidate(before); + pictureBox.Invalidate(after); + } + if (horizontalMove) { + Rectangle before = GuiRectangle.GetGuiRectangle(lastPos.X - 2, 0, 75, this.Height+2); + Rectangle after = GuiRectangle.GetGuiRectangle(cursorPos.X -2, 0, 75, this.Height+2); + pictureBox.Invalidate(before); + pictureBox.Invalidate(after); + } } } } @@ -889,7 +328,11 @@ namespace Greenshot.Forms { if (mouseDown || captureMode == CaptureMode.Window) { captureRect.Intersect(new Rectangle(Point.Empty, capture.ScreenBounds.Size)); // crop what is outside the screen Rectangle fixedRect = new Rectangle( captureRect.X, captureRect.Y, captureRect.Width, captureRect.Height ); - graphics.FillRectangle( OverlayBrush, fixedRect ); + if (capture.CaptureDetails.CaptureMode == CaptureMode.Video) { + graphics.FillRectangle( RedOverlayBrush, fixedRect ); + } else { + graphics.FillRectangle( GreenOverlayBrush, fixedRect ); + } graphics.DrawRectangle( OverlayPen, fixedRect ); // rulers @@ -909,11 +352,11 @@ namespace Greenshot.Forms { // horizontal ruler if (fixedRect.Width > hSpace + 3) { using (GraphicsPath p = Drawing.RoundedRectangle.Create2( - fixedRect.X + (fixedRect.Width / 2 - hSpace / 2) + 3, - fixedRect.Y - dist - 7, - measureWidth.Width - 3, - measureWidth.Height, - 3)) { + fixedRect.X + (fixedRect.Width / 2 - hSpace / 2) + 3, + fixedRect.Y - dist - 7, + measureWidth.Width - 3, + measureWidth.Height, + 3)) { graphics.FillPath(bgBrush, p); graphics.DrawPath(rulerPen, p); graphics.DrawString(captureWidth, rulerFont, rulerPen.Brush, fixedRect.X + (fixedRect.Width / 2 - hSpace / 2) + 3, fixedRect.Y - dist - 7); @@ -927,11 +370,11 @@ namespace Greenshot.Forms { // vertical ruler if (fixedRect.Height > vSpace + 3) { using (GraphicsPath p = Drawing.RoundedRectangle.Create2( - fixedRect.X - measureHeight.Width + 1, - fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2) + 2, - measureHeight.Width - 3, - measureHeight.Height - 1, - 3)) { + fixedRect.X - measureHeight.Width + 1, + fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2) + 2, + measureHeight.Width - 3, + measureHeight.Height - 1, + 3)) { graphics.FillPath(bgBrush, p); graphics.DrawPath(rulerPen, p); graphics.DrawString(captureHeight, rulerFont, rulerPen.Brush, fixedRect.X - measureHeight.Width + 1, fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2) + 2); @@ -979,29 +422,26 @@ namespace Greenshot.Forms { } } else { if (cursorPos.X >= 0 || cursorPos.Y >= 0) { - using (Pen pen = new Pen(Color.LightSeaGreen)) { - pen.DashStyle = DashStyle.Dot; - Rectangle screenBounds = capture.ScreenBounds; - graphics.DrawLine(pen, cursorPos.X, screenBounds.Y, cursorPos.X, screenBounds.Height); - graphics.DrawLine(pen, screenBounds.X, cursorPos.Y, screenBounds.Width, cursorPos.Y); - } - - string xy = cursorPos.X + " x " + cursorPos.Y; - using (Font f = new Font(FontFamily.GenericSansSerif, 8)) { - Size xySize = TextRenderer.MeasureText(xy, f); - using (GraphicsPath gp = Drawing.RoundedRectangle.Create2( - cursorPos.X + 5, - cursorPos.Y + 5, - xySize.Width - 3, - xySize.Height, - 3)) { - using (Brush bgBrush = new SolidBrush(Color.FromArgb(200, 217, 240, 227))) { - graphics.FillPath(bgBrush, gp); - } - using (Pen pen = new Pen(Color.SeaGreen)) { - graphics.DrawPath(pen, gp); - Point coordinatePosition = new Point(cursorPos.X + 5, cursorPos.Y + 5); - graphics.DrawString(xy, f, pen.Brush, coordinatePosition); + if (!conf.OptimizeForRDP) { + using (Pen pen = new Pen(Color.LightSeaGreen)) { + pen.DashStyle = DashStyle.Dot; + Rectangle screenBounds = capture.ScreenBounds; + graphics.DrawLine(pen, cursorPos.X, screenBounds.Y, cursorPos.X, screenBounds.Height); + graphics.DrawLine(pen, screenBounds.X, cursorPos.Y, screenBounds.Width, cursorPos.Y); + } + + string xy = cursorPos.X + " x " + cursorPos.Y; + using (Font f = new Font(FontFamily.GenericSansSerif, 8)) { + Size xySize = TextRenderer.MeasureText(xy, f); + using (GraphicsPath gp = Drawing.RoundedRectangle.Create2(cursorPos.X + 5, cursorPos.Y + 5, xySize.Width - 3, xySize.Height, 3)) { + using (Brush bgBrush = new SolidBrush(Color.FromArgb(200, 217, 240, 227))) { + graphics.FillPath(bgBrush, gp); + } + using (Pen pen = new Pen(Color.SeaGreen)) { + graphics.DrawPath(pen, gp); + Point coordinatePosition = new Point(cursorPos.X + 5, cursorPos.Y + 5); + graphics.DrawString(xy, f, pen.Brush, coordinatePosition); + } } } } @@ -1009,15 +449,5 @@ namespace Greenshot.Forms { } } #endregion - - #region Form Events - private void CaptureFormVisibleChanged( object sender, EventArgs e ) { - if ( !this.Visible && pictureBox.Image != null ) { - Image img = pictureBox.Image; - pictureBox.Image = null; - img.Dispose(); - } - } - #endregion } } diff --git a/Greenshot/Forms/ColorDialog.cs b/Greenshot/Forms/ColorDialog.cs index f9d720b0e..286e15519 100644 --- a/Greenshot/Forms/ColorDialog.cs +++ b/Greenshot/Forms/ColorDialog.cs @@ -20,13 +20,13 @@ */ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Drawing; using System.Threading; using System.Windows.Forms; using Greenshot.Configuration; using GreenshotPlugin.Core; +using IniFile; namespace Greenshot { /// diff --git a/Greenshot/Forms/DestinationPickerForm.Designer.cs b/Greenshot/Forms/DestinationPickerForm.Designer.cs deleted file mode 100644 index 1c540963a..000000000 --- a/Greenshot/Forms/DestinationPickerForm.Designer.cs +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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 . - */ -namespace Greenshot.Forms -{ - partial class DestinationPickerForm - { - /// - /// Designer variable used to keep track of non-visual components. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Disposes resources used by the form. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing) { - if (components != null) { - components.Dispose(); - } - } - base.Dispose(disposing); - } - - /// - /// This method is required for Windows Forms designer support. - /// Do not change the method contents inside the source code editor. The Forms designer might - /// not be able to load this method if it was changed manually. - /// - private void InitializeComponent() - { - this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); - this.buttonGo = new System.Windows.Forms.Button(); - this.SuspendLayout(); - // - // flowLayoutPanel1 - // - this.flowLayoutPanel1.AutoSize = true; - this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; - this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; - this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0); - this.flowLayoutPanel1.Name = "flowLayoutPanel1"; - this.flowLayoutPanel1.Size = new System.Drawing.Size(292, 273); - this.flowLayoutPanel1.TabIndex = 0; - // - // buttonGo - // - this.buttonGo.AutoSize = true; - this.buttonGo.Dock = System.Windows.Forms.DockStyle.Bottom; - this.buttonGo.Location = new System.Drawing.Point(0, 250); - this.buttonGo.Name = "buttonGo"; - this.buttonGo.Size = new System.Drawing.Size(292, 23); - this.buttonGo.TabIndex = 1; - this.buttonGo.Text = "GO"; - this.buttonGo.UseVisualStyleBackColor = true; - // - // DestinationPickerForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.AutoSize = true; - this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.ClientSize = new System.Drawing.Size(292, 273); - this.Controls.Add(this.buttonGo); - this.Controls.Add(this.flowLayoutPanel1); - this.Icon = GreenshotPlugin.Core.GreenshotResources.getGreenshotIcon(); - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "DestinationPickerForm"; - this.Text = "DestinationPickerForm"; - this.ResumeLayout(false); - this.PerformLayout(); - } - private System.Windows.Forms.Button buttonGo; - private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; - } -} diff --git a/Greenshot/Forms/DestinationPickerForm.cs b/Greenshot/Forms/DestinationPickerForm.cs deleted file mode 100644 index 6cec067a2..000000000 --- a/Greenshot/Forms/DestinationPickerForm.cs +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Drawing; -using System.Windows.Forms; - -using Greenshot.Configuration; -using GreenshotPlugin.Core; - -namespace Greenshot.Forms -{ - /// - /// Description of DestinationPickerForm. - /// - public partial class DestinationPickerForm : Form { - private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(DestinationPickerForm)); - private static CoreConfiguration config = IniConfig.GetIniSection(); - private static ILanguage lang = Language.GetInstance(); - public DestinationPickerForm() { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - this.Text = lang.GetString(LangKey.settings_destination); - AddCheckBox(flowLayoutPanel1, Destination.Clipboard, lang.GetString(LangKey.settings_destination_clipboard)); - AddCheckBox(flowLayoutPanel1, Destination.Editor, lang.GetString(LangKey.settings_destination_editor)); - AddCheckBox(flowLayoutPanel1, Destination.EMail, lang.GetString(LangKey.settings_destination_email)); - AddCheckBox(flowLayoutPanel1, Destination.FileDefault, lang.GetString(LangKey.settings_destination_file)); - AddCheckBox(flowLayoutPanel1, Destination.FileWithDialog, lang.GetString(LangKey.settings_destination_fileas)); - AddCheckBox(flowLayoutPanel1, Destination.Printer, lang.GetString(LangKey.settings_destination_printer)); - } - - public void ShowAtMouse(IWin32Window owner) { - this.Show(owner); - Point target = Cursor.Position; - target.X -= this.Width / 2; - target.Y -= this.Height / 2; - this.Location = target; - } - - private void AddCheckBox(Panel panel, Destination destination, string text) { - CheckBox checkbox = new CheckBox(); - checkbox.Text = text; - //checkbox.Width = 200; - //checkbox.Height = 20; - checkbox.AutoSize = true; - if (config.OutputDestinations.Contains(destination)) { - checkbox.Checked = true; - } - panel.Controls.Add(checkbox); - } - } -} diff --git a/Greenshot/Forms/FormWithoutActivation.cs b/Greenshot/Forms/FormWithoutActivation.cs new file mode 100644 index 000000000..364e38554 --- /dev/null +++ b/Greenshot/Forms/FormWithoutActivation.cs @@ -0,0 +1,33 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Windows.Forms; + +namespace Greenshot.Forms { + /// + /// FormWithoutActivation is exactly like a normal form, but doesn't activate (steal focus) + /// + public class FormWithoutActivation : Form { + protected override bool ShowWithoutActivation { + get { return true; } + } + } +} diff --git a/Greenshot/Forms/ImageEditorForm.Designer.cs b/Greenshot/Forms/ImageEditorForm.Designer.cs index d9d546ba3..0bfb49708 100644 --- a/Greenshot/Forms/ImageEditorForm.Designer.cs +++ b/Greenshot/Forms/ImageEditorForm.Designer.cs @@ -61,23 +61,23 @@ namespace Greenshot { this.btnArrow = new System.Windows.Forms.ToolStripButton(); this.btnText = new System.Windows.Forms.ToolStripButton(); this.toolStripSeparator14 = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripSeparator15 = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripSeparator16 = new System.Windows.Forms.ToolStripSeparator(); this.btnHighlight = new System.Windows.Forms.ToolStripButton(); this.btnObfuscate = new System.Windows.Forms.ToolStripButton(); + this.btnFreehand = new System.Windows.Forms.ToolStripButton(); this.toolStripSeparator13 = new System.Windows.Forms.ToolStripSeparator(); this.btnCrop = new System.Windows.Forms.ToolStripButton(); this.menuStrip1 = new System.Windows.Forms.MenuStrip(); this.fileStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.saveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.saveAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.copyImageToClipboardToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.printToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.emailToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator9 = new System.Windows.Forms.ToolStripSeparator(); this.closeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.cutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.copyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.pasteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.undoToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.redoToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); this.duplicateToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator12 = new System.Windows.Forms.ToolStripSeparator(); @@ -85,6 +85,7 @@ namespace Greenshot { this.objectToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.addRectangleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.addEllipseToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.drawFreehandToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.drawLineToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.drawArrowToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.addTextBoxToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -113,6 +114,8 @@ namespace Greenshot { this.btnCut = new System.Windows.Forms.ToolStripButton(); this.btnCopy = new System.Windows.Forms.ToolStripButton(); this.btnPaste = new System.Windows.Forms.ToolStripButton(); + this.btnUndo = new System.Windows.Forms.ToolStripButton(); + this.btnRedo = new System.Windows.Forms.ToolStripButton(); this.toolStripSeparator6 = new System.Windows.Forms.ToolStripSeparator(); this.btnSettings = new System.Windows.Forms.ToolStripButton(); this.toolStripSeparator11 = new System.Windows.Forms.ToolStripSeparator(); @@ -162,9 +165,10 @@ namespace Greenshot { this.fileSavedStatusContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); this.copyPathMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.openDirectoryMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.btnEmail = new System.Windows.Forms.ToolStripButton(); this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator(); this.insert_window_toolstripmenuitem = new System.Windows.Forms.ToolStripMenuItem(); + this.dimensionsLabel = new System.Windows.Forms.ToolStripStatusLabel(); + this.autoCropToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripContainer1.BottomToolStripPanel.SuspendLayout(); this.toolStripContainer1.ContentPanel.SuspendLayout(); this.toolStripContainer1.LeftToolStripPanel.SuspendLayout(); @@ -211,8 +215,7 @@ namespace Greenshot { // statusStrip1 // this.statusStrip1.Dock = System.Windows.Forms.DockStyle.None; - this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.statusLabel}); + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {this.dimensionsLabel, this.statusLabel}); this.statusStrip1.Location = new System.Drawing.Point(0, 0); this.statusStrip1.Name = "statusStrip1"; this.statusStrip1.Size = new System.Drawing.Size(785, 22); @@ -221,6 +224,11 @@ namespace Greenshot { // // statusLabel // + this.statusLabel.BorderSides = ((System.Windows.Forms.ToolStripStatusLabelBorderSides)((((System.Windows.Forms.ToolStripStatusLabelBorderSides.Left | System.Windows.Forms.ToolStripStatusLabelBorderSides.Top) + | System.Windows.Forms.ToolStripStatusLabelBorderSides.Right) + | System.Windows.Forms.ToolStripStatusLabelBorderSides.Bottom))); + this.statusLabel.BorderStyle = System.Windows.Forms.Border3DStyle.Sunken; + this.statusLabel.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; this.statusLabel.Name = "statusLabel"; this.statusLabel.Size = new System.Drawing.Size(0, 17); this.statusLabel.MouseDown += new System.Windows.Forms.MouseEventHandler(this.StatusLabelClicked); @@ -262,6 +270,7 @@ namespace Greenshot { this.btnEllipse, this.btnLine, this.btnArrow, + this.btnFreehand, this.btnText, this.toolStripSeparator14, this.btnHighlight, @@ -300,7 +309,6 @@ namespace Greenshot { this.btnRect.ImageTransparentColor = System.Drawing.Color.Magenta; this.btnRect.Name = "btnRect"; this.btnRect.Size = new System.Drawing.Size(22, 20); - this.btnRect.Text = "Draw rectangle"; this.btnRect.Click += new System.EventHandler(this.BtnRectClick); // // btnEllipse @@ -311,7 +319,6 @@ namespace Greenshot { this.btnEllipse.ImageTransparentColor = System.Drawing.Color.Magenta; this.btnEllipse.Name = "btnEllipse"; this.btnEllipse.Size = new System.Drawing.Size(22, 20); - this.btnEllipse.Text = "Draw ellipse"; this.btnEllipse.Click += new System.EventHandler(this.BtnEllipseClick); // // btnLine @@ -322,7 +329,6 @@ namespace Greenshot { this.btnLine.ImageTransparentColor = System.Drawing.Color.Magenta; this.btnLine.Name = "btnLine"; this.btnLine.Size = new System.Drawing.Size(22, 20); - this.btnLine.Text = "Draw line"; this.btnLine.Click += new System.EventHandler(this.BtnLineClick); // // btnArrow @@ -333,7 +339,6 @@ namespace Greenshot { this.btnArrow.ImageTransparentColor = System.Drawing.Color.Magenta; this.btnArrow.Name = "btnArrow"; this.btnArrow.Size = new System.Drawing.Size(22, 20); - this.btnArrow.Text = "Draw arrow"; this.btnArrow.Click += new System.EventHandler(this.BtnArrowClick); // // btnText @@ -344,7 +349,6 @@ namespace Greenshot { this.btnText.ImageTransparentColor = System.Drawing.Color.Magenta; this.btnText.Name = "btnText"; this.btnText.Size = new System.Drawing.Size(22, 20); - this.btnText.Text = "Add text"; this.btnText.Click += new System.EventHandler(this.BtnTextClick); // // toolStripSeparator14 @@ -352,6 +356,16 @@ namespace Greenshot { this.toolStripSeparator14.Name = "toolStripSeparator14"; this.toolStripSeparator14.Size = new System.Drawing.Size(22, 6); // + // toolStripSeparator15 + // + this.toolStripSeparator15.Name = "toolStripSeparator15"; + this.toolStripSeparator15.Size = new System.Drawing.Size(22, 6); + // + // toolStripSeparator16 + // + this.toolStripSeparator16.Name = "toolStripSeparator16"; + this.toolStripSeparator16.Size = new System.Drawing.Size(22, 6); + // // btnHighlight // this.btnHighlight.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; @@ -359,7 +373,6 @@ namespace Greenshot { this.btnHighlight.ImageTransparentColor = System.Drawing.Color.Magenta; this.btnHighlight.Name = "btnHighlight"; this.btnHighlight.Size = new System.Drawing.Size(22, 20); - this.btnHighlight.Text = "Highlight"; this.btnHighlight.Click += new System.EventHandler(this.BtnHighlightClick); // // btnObfuscate @@ -369,13 +382,21 @@ namespace Greenshot { this.btnObfuscate.ImageTransparentColor = System.Drawing.Color.Magenta; this.btnObfuscate.Name = "btnObfuscate"; this.btnObfuscate.Size = new System.Drawing.Size(22, 20); - this.btnObfuscate.Text = "Obfuscate"; this.btnObfuscate.Click += new System.EventHandler(this.BtnObfuscateClick); // + // btnFreehand + // + this.btnFreehand.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.btnFreehand.Image = ((System.Drawing.Image)(resources.GetObject("freehand.Image"))); + this.btnFreehand.ImageTransparentColor = System.Drawing.Color.Magenta; + this.btnFreehand.Name = "btnFreehand"; + this.btnFreehand.Size = new System.Drawing.Size(30, 20); + this.btnFreehand.Click += new System.EventHandler(this.BtnFreehandClick); + // // toolStripSeparator13 // this.toolStripSeparator13.Name = "toolStripSeparator13"; - this.toolStripSeparator13.Size = new System.Drawing.Size(22, 6); + this.toolStripSeparator13.Size = new System.Drawing.Size(30, 6); // // btnCrop // @@ -384,7 +405,6 @@ namespace Greenshot { this.btnCrop.ImageTransparentColor = System.Drawing.Color.Magenta; this.btnCrop.Name = "btnCrop"; this.btnCrop.Size = new System.Drawing.Size(22, 20); - this.btnCrop.Text = "Crop"; this.btnCrop.Click += new System.EventHandler(this.BtnCropClick); // // menuStrip1 @@ -400,69 +420,13 @@ namespace Greenshot { this.menuStrip1.Name = "menuStrip1"; this.menuStrip1.Size = new System.Drawing.Size(785, 24); this.menuStrip1.TabIndex = 1; - this.menuStrip1.Text = "menuStrip1"; // // fileStripMenuItem // - this.fileStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.saveToolStripMenuItem, - this.saveAsToolStripMenuItem, - this.copyImageToClipboardToolStripMenuItem, - this.printToolStripMenuItem, - this.emailToolStripMenuItem, - this.toolStripSeparator9, - this.closeToolStripMenuItem}); this.fileStripMenuItem.Name = "fileStripMenuItem"; this.fileStripMenuItem.Size = new System.Drawing.Size(35, 20); this.fileStripMenuItem.Text = "File"; - // - // saveToolStripMenuItem - // - this.saveToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("saveToolStripMenuItem.Image"))); - this.saveToolStripMenuItem.Name = "saveToolStripMenuItem"; - this.saveToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S))); - this.saveToolStripMenuItem.Size = new System.Drawing.Size(307, 22); - this.saveToolStripMenuItem.Text = "Save"; - this.saveToolStripMenuItem.Click += new System.EventHandler(this.SaveToolStripMenuItemClick); - // - // saveAsToolStripMenuItem - // - this.saveAsToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("saveToolStripMenuItem.Image"))); - this.saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem"; - this.saveAsToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) - | System.Windows.Forms.Keys.S))); - this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(307, 22); - this.saveAsToolStripMenuItem.Text = "Save as..."; - this.saveAsToolStripMenuItem.Click += new System.EventHandler(this.SaveAsToolStripMenuItemClick); - // - // copyImageToClipboardToolStripMenuItem - // - this.copyImageToClipboardToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("copyImageToClipboardToolStripMenuItem.Image"))); - this.copyImageToClipboardToolStripMenuItem.Name = "copyImageToClipboardToolStripMenuItem"; - this.copyImageToClipboardToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) - | System.Windows.Forms.Keys.C))); - this.copyImageToClipboardToolStripMenuItem.Size = new System.Drawing.Size(307, 22); - this.copyImageToClipboardToolStripMenuItem.Text = "Copy image to clipboard"; - this.copyImageToClipboardToolStripMenuItem.Click += new System.EventHandler(this.CopyImageToClipboardToolStripMenuItemClick); - // - // printToolStripMenuItem - // - this.printToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("printToolStripMenuItem.Image"))); - this.printToolStripMenuItem.Name = "printToolStripMenuItem"; - this.printToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.P))); - this.printToolStripMenuItem.Size = new System.Drawing.Size(307, 22); - this.printToolStripMenuItem.Text = "Print..."; - this.printToolStripMenuItem.Click += new System.EventHandler(this.PrintToolStripMenuItemClick); - // - // emailToolStripMenuItem - // - this.emailToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("emailToolStripMenuItem.Image"))); - this.emailToolStripMenuItem.Name = "emailToolStripMenuItem"; - this.emailToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.E))); - this.emailToolStripMenuItem.Size = new System.Drawing.Size(307, 22); - this.emailToolStripMenuItem.Text = "EMail"; - this.emailToolStripMenuItem.Click += new System.EventHandler(this.EmailToolStripMenuItemClick); - // + this.fileStripMenuItem.DropDownOpening += new System.EventHandler(this.FileMenuDropDownOpening); // toolStripSeparator9 // this.toolStripSeparator9.Name = "toolStripSeparator9"; @@ -477,9 +441,19 @@ namespace Greenshot { this.closeToolStripMenuItem.Text = "Close"; this.closeToolStripMenuItem.Click += new System.EventHandler(this.CloseToolStripMenuItemClick); // + // autoCropToolStripMenuItem + // + this.autoCropToolStripMenuItem.Name = "autoCropToolStripMenuItem"; + this.autoCropToolStripMenuItem.Size = new System.Drawing.Size(166, 22); + this.autoCropToolStripMenuItem.Text = "Auto Crop"; + this.autoCropToolStripMenuItem.Click += new System.EventHandler(this.AutoCropToolStripMenuItemClick); + // // editToolStripMenuItem // this.editToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.undoToolStripMenuItem, + this.redoToolStripMenuItem, + this.toolStripSeparator15, this.cutToolStripMenuItem, this.copyToolStripMenuItem, this.pasteToolStripMenuItem, @@ -488,6 +462,7 @@ namespace Greenshot { this.toolStripSeparator12, this.preferencesToolStripMenuItem, this.toolStripSeparator5, + this.autoCropToolStripMenuItem, this.insert_window_toolstripmenuitem}); this.editToolStripMenuItem.Name = "editToolStripMenuItem"; this.editToolStripMenuItem.Size = new System.Drawing.Size(37, 20); @@ -524,6 +499,26 @@ namespace Greenshot { this.pasteToolStripMenuItem.Text = "Paste"; this.pasteToolStripMenuItem.Click += new System.EventHandler(this.PasteToolStripMenuItemClick); // + // undoToolStripMenuItem + // + this.undoToolStripMenuItem.Enabled = false; + this.undoToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("btnUndo.Image"))); + this.undoToolStripMenuItem.Name = "undoToolStripMenuItem"; + this.undoToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Z))); + this.undoToolStripMenuItem.Size = new System.Drawing.Size(160, 22); + this.undoToolStripMenuItem.Text = "Undo"; + this.undoToolStripMenuItem.Click += new System.EventHandler(this.UndoToolStripMenuItemClick); + // + // redoToolStripMenuItem + // + this.redoToolStripMenuItem.Enabled = false; + this.redoToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("btnRedo.Image"))); + this.redoToolStripMenuItem.Name = "redoToolStripMenuItem"; + this.redoToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Y))); + this.redoToolStripMenuItem.Size = new System.Drawing.Size(160, 22); + this.redoToolStripMenuItem.Text = "Redo"; + this.redoToolStripMenuItem.Click += new System.EventHandler(this.RedoToolStripMenuItemClick); + // // toolStripSeparator4 // this.toolStripSeparator4.Name = "toolStripSeparator4"; @@ -558,6 +553,7 @@ namespace Greenshot { this.addEllipseToolStripMenuItem, this.drawLineToolStripMenuItem, this.drawArrowToolStripMenuItem, + this.drawFreehandToolStripMenuItem, this.addTextBoxToolStripMenuItem, this.toolStripSeparator8, this.selectAllToolStripMenuItem, @@ -586,6 +582,14 @@ namespace Greenshot { this.addEllipseToolStripMenuItem.Text = "Draw ellipse"; this.addEllipseToolStripMenuItem.Click += new System.EventHandler(this.AddEllipseToolStripMenuItemClick); // + // drawFreehandToolStripMenuItem + // + this.drawFreehandToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("freehand.Image"))); + this.drawFreehandToolStripMenuItem.Name = "drawFreehandToolStripMenuItem"; + this.drawFreehandToolStripMenuItem.Size = new System.Drawing.Size(189, 22); + this.drawFreehandToolStripMenuItem.Text = "Draw freehand"; + this.drawFreehandToolStripMenuItem.Click += new System.EventHandler(this.DrawFreehandToolStripMenuItemClick); + // // drawLineToolStripMenuItem // this.drawLineToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("drawLineToolStripMenuItem.Image"))); @@ -740,16 +744,18 @@ namespace Greenshot { this.btnSave, this.btnClipboard, this.btnPrint, - this.btnEmail, this.toolStripSeparator2, this.btnDelete, this.toolStripSeparator3, this.btnCut, this.btnCopy, this.btnPaste, + this.btnUndo, + this.btnRedo, this.toolStripSeparator6, this.btnSettings, this.toolStripSeparator11, + this.toolStripSeparator16, this.btnHelp}); this.toolStrip1.Location = new System.Drawing.Point(0, 24); this.toolStrip1.Name = "toolStrip1"; @@ -840,6 +846,25 @@ namespace Greenshot { this.btnPaste.Size = new System.Drawing.Size(23, 22); this.btnPaste.Text = "Paste element from clipboard"; this.btnPaste.Click += new System.EventHandler(this.BtnPasteClick); + // btnUndo + // + this.btnUndo.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.btnUndo.Enabled = false; + this.btnUndo.Image = ((System.Drawing.Image)(resources.GetObject("btnUndo.Image"))); + this.btnUndo.ImageTransparentColor = System.Drawing.Color.Magenta; + this.btnUndo.Name = "btnUndo"; + this.btnUndo.Size = new System.Drawing.Size(23, 22); + this.btnUndo.Click += new System.EventHandler(this.BtnUndoClick); + // + // btnRedo + // + this.btnRedo.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.btnRedo.Enabled = false; + this.btnRedo.Image = ((System.Drawing.Image)(resources.GetObject("btnRedo.Image"))); + this.btnRedo.ImageTransparentColor = System.Drawing.Color.Magenta; + this.btnRedo.Name = "btnRedo"; + this.btnRedo.Size = new System.Drawing.Size(23, 22); + this.btnRedo.Click += new System.EventHandler(this.BtnRedoClick); // // toolStripSeparator6 // @@ -1351,7 +1376,6 @@ namespace Greenshot { this.shadowButton.ImageTransparentColor = System.Drawing.Color.Magenta; this.shadowButton.Name = "shadowButton"; this.shadowButton.Size = new System.Drawing.Size(23, 20); - this.shadowButton.Text = "Shadow"; // // toolStripSeparator // @@ -1425,16 +1449,6 @@ namespace Greenshot { this.openDirectoryMenuItem.Text = "Open directory in Windows Explorer"; this.openDirectoryMenuItem.Click += new System.EventHandler(this.OpenDirectoryMenuItemClick); // - // btnEmail - // - this.btnEmail.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.btnEmail.Image = ((System.Drawing.Image)(resources.GetObject("btnEmail.Image"))); - this.btnEmail.ImageTransparentColor = System.Drawing.Color.Magenta; - this.btnEmail.Name = "btnEmail"; - this.btnEmail.Size = new System.Drawing.Size(23, 22); - this.btnEmail.Text = "Email"; - this.btnEmail.Click += new System.EventHandler(this.BtnEmailClick); - // // toolStripSeparator5 // this.toolStripSeparator5.Name = "toolStripSeparator5"; @@ -1447,6 +1461,15 @@ namespace Greenshot { this.insert_window_toolstripmenuitem.Text = "Insert window"; this.insert_window_toolstripmenuitem.MouseEnter += new System.EventHandler(this.Insert_window_toolstripmenuitemMouseEnter); // + // dimensionsLabel + // + this.dimensionsLabel.BorderSides = ((System.Windows.Forms.ToolStripStatusLabelBorderSides)((((System.Windows.Forms.ToolStripStatusLabelBorderSides.Left | System.Windows.Forms.ToolStripStatusLabelBorderSides.Top) | System.Windows.Forms.ToolStripStatusLabelBorderSides.Right) | System.Windows.Forms.ToolStripStatusLabelBorderSides.Bottom))); + this.dimensionsLabel.BorderStyle = System.Windows.Forms.Border3DStyle.Sunken; + this.dimensionsLabel.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.dimensionsLabel.Name = "dimensionsLabel"; + this.dimensionsLabel.Size = new System.Drawing.Size(48, 17); + this.dimensionsLabel.Text = "123x321"; + // // ImageEditorForm // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); @@ -1482,9 +1505,9 @@ namespace Greenshot { this.fileSavedStatusContextMenu.ResumeLayout(false); this.ResumeLayout(false); } + private System.Windows.Forms.ToolStripStatusLabel dimensionsLabel; private System.Windows.Forms.ToolStripMenuItem insert_window_toolstripmenuitem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator5; - private System.Windows.Forms.ToolStripButton btnEmail; private System.Windows.Forms.ToolStripMenuItem grayscaleHighlightMenuItem; private System.Windows.Forms.ToolStripMenuItem areaHighlightMenuItem; private System.Windows.Forms.ToolStripMenuItem textHighlightMenuItem; @@ -1501,7 +1524,6 @@ namespace Greenshot { private System.Windows.Forms.ToolStripMenuItem blurToolStripMenuItem; private Greenshot.Controls.BindableToolStripDropDownButton obfuscateModeButton; private System.Windows.Forms.ToolStripButton btnHighlight; - private System.Windows.Forms.ToolStripMenuItem emailToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem loadElementsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem saveElementsToolStripMenuItem; private Greenshot.Controls.FontFamilyComboBox fontFamilyComboBox; @@ -1531,6 +1553,9 @@ namespace Greenshot { private System.Windows.Forms.ToolStripLabel lineThicknessLabel; private Greenshot.Controls.ToolStripNumericUpDown lineThicknessUpDown; private System.Windows.Forms.ToolStripSeparator toolStripSeparator14; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator15; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator16; + private System.Windows.Forms.ToolStripButton btnFreehand; private System.Windows.Forms.ToolStripButton btnObfuscate; private System.Windows.Forms.ToolStripSeparator toolStripSeparator13; private System.Windows.Forms.ToolStripButton btnCrop; @@ -1546,6 +1571,7 @@ namespace Greenshot { private System.Windows.Forms.ToolStrip toolStrip2; private System.Windows.Forms.ToolStripButton btnArrow; private System.Windows.Forms.ToolStripMenuItem drawArrowToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem drawFreehandToolStripMenuItem; private System.Windows.Forms.ToolStripButton btnText; private System.Windows.Forms.ToolStripMenuItem drawLineToolStripMenuItem; private System.Windows.Forms.ToolStripButton btnLine; @@ -1563,29 +1589,29 @@ namespace Greenshot { private System.Windows.Forms.ToolStripSeparator toolStripSeparator8; private System.Windows.Forms.ToolStripSeparator toolStripSeparator6; private System.Windows.Forms.ToolStripButton btnPrint; - private System.Windows.Forms.ToolStripMenuItem printToolStripMenuItem; private System.Windows.Forms.PrintDialog printDialog1; private System.Windows.Forms.ToolStripMenuItem duplicateToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator4; private System.Windows.Forms.ToolStripMenuItem fileStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem removeObjectToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem addTextBoxToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem addEllipseToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem addRectangleToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem objectToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem undoToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem redoToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem pasteToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem copyToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem cutToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem editToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem copyImageToClipboardToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem saveAsToolStripMenuItem; private System.Windows.Forms.MenuStrip menuStrip1; private System.Windows.Forms.ToolStripStatusLabel statusLabel; private System.Windows.Forms.StatusStrip statusStrip1; private System.Windows.Forms.ToolStripButton btnCut; - private System.Windows.Forms.ToolStripButton btnPaste; private System.Windows.Forms.ToolStripButton btnCopy; + private System.Windows.Forms.ToolStripButton btnPaste; + private System.Windows.Forms.ToolStripButton btnUndo; + private System.Windows.Forms.ToolStripButton btnRedo; private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; private System.Windows.Forms.ToolStripButton btnClipboard; private System.Windows.Forms.ToolStripButton btnDelete; @@ -1600,5 +1626,6 @@ namespace Greenshot { private GreenshotPlugin.Controls.NonJumpingPanel panel1; private Greenshot.Controls.ToolStripColorButton btnFillColor; private Greenshot.Controls.ToolStripColorButton btnLineColor; + private System.Windows.Forms.ToolStripMenuItem autoCropToolStripMenuItem; } } diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index 5ef5a00d4..813012a76 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -19,29 +19,25 @@ * along with this program. If not, see . */ using System; -using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.Drawing.Drawing2D; -using System.Drawing.Imaging; using System.Drawing.Printing; using System.IO; -using System.Resources; -using System.Threading; using System.Windows.Forms; using Greenshot.Configuration; using Greenshot.Drawing; using Greenshot.Drawing.Fields; using Greenshot.Drawing.Fields.Binding; -using Greenshot.Experimental; using Greenshot.Forms; using Greenshot.Help; using Greenshot.Helpers; using Greenshot.Plugin; using GreenshotPlugin.Core; +using IniFile; namespace Greenshot { /// @@ -52,12 +48,12 @@ namespace Greenshot { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ImageEditorForm)); private static EditorConfiguration editorConfiguration = IniConfig.GetIniSection(); private static CoreConfiguration coreConf = IniConfig.GetIniSection(); + private static List ignoreDestinations = new List() {"Picker", "Editor"}; + private static List editorList = new List(); private ILanguage lang; - private string lastSaveFullPath; - - public Surface surface; + private Surface surface; private System.Windows.Forms.ToolStripButton[] toolbarButtons; private static string[] SUPPORTED_CLIPBOARD_FORMATS = {typeof(string).FullName, "Text", "DeviceIndependentBitmap", "Bitmap", typeof(DrawableContainerList).FullName}; @@ -75,8 +71,22 @@ namespace Greenshot { get { return this; } } - public ImageEditorForm(Surface surface, bool outputMade) { - + public Surface EditorSurface { + get { + return surface; + } + } + + public static List Editors { + get { + return editorList; + } + } + + public ImageEditorForm(ISurface iSurface, bool outputMade) { + // init surface + this.surface = iSurface as Surface; + editorList.Add(this); // // The InitializeComponent() call is required for Windows Forms designer support. // @@ -95,12 +105,12 @@ namespace Greenshot { // a smaller size than the initial panel size (as set by the forms designer) panel1.Height = 10; - // init surface - this.surface = surface; surface.TabStop = false; surface.MovingElementChanged += delegate { refreshEditorControls(); }; surface.DrawingModeChanged += new SurfaceDrawingModeEventHandler(surface_DrawingModeChanged); + surface.SurfaceSizeChanged += new SurfaceSizeChangeEventHandler(SurfaceSizeChanged); + surface.SurfaceMessage += new SurfaceMessageEventHandler(SurfaceMessageReceived); this.fontFamilyComboBox.PropertyChanged += new PropertyChangedEventHandler(FontPropertyChanged); @@ -116,34 +126,151 @@ namespace Greenshot { WindowDetails thisForm = new WindowDetails(this.Handle); thisForm.SetWindowPlacement(editorConfiguration.GetEditorPlacement()); - if (editorConfiguration.MatchSizeToCapture) { - // Set editor's initial size to the size of the surface plus the size of the chrome - Size imageSize = this.Surface.Image.Size; - Size currentFormSize = this.Size; - Size currentImageClientSize = this.panel1.ClientSize; - int minimumFormWidth = 480; - int minimumFormHeight = 360; - int newWidth = Math.Max(minimumFormWidth, (currentFormSize.Width - currentImageClientSize.Width) + imageSize.Width); - int newHeight = Math.Max(minimumFormHeight, (currentFormSize.Height - currentImageClientSize.Height) + imageSize.Height); - this.Size = new Size(newWidth, newHeight); - } + SurfaceSizeChanged(this.Surface); updateUI(); IniConfig.IniChanged += new FileSystemEventHandler(ReloadConfiguration); bindFieldControls(); refreshEditorControls(); - - toolbarButtons = new ToolStripButton[]{btnCursor,btnRect,btnEllipse,btnText,btnLine,btnArrow,btnHighlight, btnObfuscate, btnCrop}; + // Workaround: As the cursor is (mostly) selected on the surface a funny artifact is visible, this fixes it. + hideToolstripItems(); + + toolbarButtons = new ToolStripButton[]{btnCursor,btnRect,btnEllipse,btnText,btnLine,btnArrow, btnFreehand, btnHighlight, btnObfuscate, btnCrop}; //toolbarDropDownButtons = new ToolStripDropDownButton[]{btnBlur, btnPixeliate, btnTextHighlighter, btnAreaHighlighter, btnMagnifier}; - - PluginHelper.instance.CreateImageEditorOpenEvent(this); + pluginToolStripMenuItem.Visible = pluginToolStripMenuItem.DropDownItems.Count > 0; - emailToolStripMenuItem.Enabled = MapiMailMessage.HasMAPIorOutlook(); - - // This is a "work-around" for the MouseWheel event which doesn't get to the panel + // Workaround: for the MouseWheel event which doesn't get to the panel this.MouseWheel += new MouseEventHandler( PanelMouseWheel); + + // Create export buttons + foreach(IDestination destination in DestinationHelper.GetAllDestinations()) { + if (destination.Priority <= 2) { + continue; + } + if (!destination.isActive) { + continue; + } + if (destination.DisplayIcon == null) { + continue; + } + try { + AddDestinationButton(destination); + } catch (Exception addingException) { + LOG.WarnFormat("Problem adding destination {0}", destination.Designation); + LOG.Warn("Exception: ", addingException); + } + } + } + + void AddDestinationButton(IDestination toolstripDestination) { + if (toolstripDestination.isDynamic) { + ToolStripSplitButton destinationButton = new ToolStripSplitButton(); + //ToolStripDropDownButton destinationButton = new ToolStripDropDownButton(); + destinationButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + destinationButton.Size = new System.Drawing.Size(23, 22); + destinationButton.Text = toolstripDestination.Description; + destinationButton.Image = toolstripDestination.DisplayIcon; + + ToolStripMenuItem defaultItem = new ToolStripMenuItem(toolstripDestination.Description); + defaultItem.Tag = toolstripDestination; + defaultItem.Image = toolstripDestination.DisplayIcon; + defaultItem.Click += delegate { + toolstripDestination.ExportCapture(surface, surface.CaptureDetails); + }; + + // The ButtonClick, this is for the icon, gets the current default item + destinationButton.ButtonClick += delegate(object sender, EventArgs e) { + toolstripDestination.ExportCapture(surface, surface.CaptureDetails); + }; + + // Generate the entries for the drop down + destinationButton.DropDownOpening += delegate(object sender, EventArgs e) { + destinationButton.DropDownItems.Clear(); + destinationButton.DropDownItems.Add(defaultItem); + + List subDestinations = new List(); + subDestinations.AddRange(toolstripDestination.DynamicDestinations()); + if (subDestinations.Count > 0) { + subDestinations.Sort(); + foreach(IDestination subDestination in subDestinations) { + ToolStripMenuItem destinationMenuItem = new ToolStripMenuItem(subDestination.Description); + destinationMenuItem.Tag = subDestination; + destinationMenuItem.Image = subDestination.DisplayIcon; + destinationMenuItem.Click += delegate { + subDestination.ExportCapture(surface, surface.CaptureDetails); + }; + destinationButton.DropDownItems.Add(destinationMenuItem); + } + } + }; + + toolStrip1.Items.Insert(toolStrip1.Items.IndexOf(toolStripSeparator16), destinationButton); + + } else { + ToolStripButton destinationButton = new ToolStripButton(); + toolStrip1.Items.Insert(toolStrip1.Items.IndexOf(toolStripSeparator16), destinationButton); + destinationButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + destinationButton.Size = new System.Drawing.Size(23, 22); + destinationButton.Text = toolstripDestination.Description; + destinationButton.Image = toolstripDestination.DisplayIcon; + destinationButton.Click += delegate(object sender, EventArgs e) { + toolstripDestination.ExportCapture(surface, surface.CaptureDetails); + }; + } + } + + void FileMenuDropDownOpening(object sender, EventArgs eventArgs) { + this.fileStripMenuItem.DropDownItems.Clear(); + //this.fileStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + // this.saveToolStripMenuItem, + // this.saveAsToolStripMenuItem, + // this.copyImageToClipboardToolStripMenuItem, + // this.printToolStripMenuItem}); + + foreach(IDestination destination in DestinationHelper.GetAllDestinations()) { + if (ignoreDestinations.Contains(destination.Designation)) { + continue; + } + if (!destination.isActive) { + continue; + } + + ToolStripMenuItem item = destination.GetMenuItem(new EventHandler(DestinationToolStripMenuItemClick)); + item.ShortcutKeys = destination.EditorShortcutKeys; + if (item != null) { + fileStripMenuItem.DropDownItems.Add(item); + } + } + // add the elements after the destinations + this.fileStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripSeparator9, + this.closeToolStripMenuItem}); + } + + private void SurfaceMessageReceived(object sender, SurfaceMessageEventArgs eventArgs) { + string dateTime = DateTime.Now.ToLongTimeString(); + if (eventArgs.MessageType == SurfaceMessageTyp.FileSaved) { + updateStatusLabel(dateTime + " - " + eventArgs.Message, fileSavedStatusContextMenu); + } else { + updateStatusLabel(dateTime + " - " + eventArgs.Message); + } + } + + private void SurfaceSizeChanged(object source) { + if (editorConfiguration.MatchSizeToCapture) { + // Set editor's initial size to the size of the surface plus the size of the chrome + Size imageSize = this.Surface.Image.Size; + Size currentFormSize = this.Size; + Size currentImageClientSize = this.panel1.ClientSize; + int minimumFormWidth = 480; + int minimumFormHeight = 390; + int newWidth = Math.Max(minimumFormWidth, (currentFormSize.Width - currentImageClientSize.Width) + imageSize.Width); + int newHeight = Math.Max(minimumFormHeight, (currentFormSize.Height - currentImageClientSize.Height) + imageSize.Height); + this.Size = new Size(newWidth, newHeight); + } + dimensionsLabel.Text = this.Surface.Image.Width + "x" + this.Surface.Image.Height; } private void ReloadConfiguration(object source, FileSystemEventArgs e) { @@ -156,21 +283,15 @@ namespace Greenshot { private void updateUI() { string editorTitle = lang.GetString(LangKey.editor_title); if (surface != null && surface.CaptureDetails != null && surface.CaptureDetails.Title != null) { - editorTitle = editorTitle + " - " + surface.CaptureDetails.Title; + editorTitle = surface.CaptureDetails.Title + " - " + editorTitle; } this.Text = editorTitle; this.fileStripMenuItem.Text = lang.GetString(LangKey.editor_file); this.btnSave.Text = lang.GetString(LangKey.editor_save); - this.saveToolStripMenuItem.Text = lang.GetString(LangKey.editor_save); - this.saveAsToolStripMenuItem.Text = lang.GetString(LangKey.editor_saveas); this.btnClipboard.Text = lang.GetString(LangKey.editor_copyimagetoclipboard); - this.copyImageToClipboardToolStripMenuItem.Text = lang.GetString(LangKey.editor_copyimagetoclipboard); - this.emailToolStripMenuItem.Text = lang.GetString(LangKey.editor_email); - this.btnEmail.Text = lang.GetString(LangKey.editor_email); this.btnPrint.Text = lang.GetString(LangKey.editor_print); - this.printToolStripMenuItem.Text = lang.GetString(LangKey.editor_print)+"..."; this.closeToolStripMenuItem.Text = lang.GetString(LangKey.editor_close); this.editToolStripMenuItem.Text = lang.GetString(LangKey.editor_edit); @@ -183,25 +304,28 @@ namespace Greenshot { this.addTextBoxToolStripMenuItem.Text = lang.GetString(LangKey.editor_drawtextbox); this.btnLine.Text = lang.GetString(LangKey.editor_drawline); this.drawLineToolStripMenuItem.Text = lang.GetString(LangKey.editor_drawline); + this.drawFreehandToolStripMenuItem.Text = lang.GetString(LangKey.editor_drawfreehand); this.btnArrow.Text = lang.GetString(LangKey.editor_drawarrow); this.drawArrowToolStripMenuItem.Text = lang.GetString(LangKey.editor_drawarrow); this.btnHighlight.Text = lang.GetString(LangKey.editor_drawhighlighter); - this.selectAllToolStripMenuItem.Text = lang.GetString(LangKey.editor_selectall); + this.btnObfuscate.Text = lang.GetString(LangKey.editor_obfuscate); + this.btnFreehand.Text = lang.GetString(LangKey.editor_drawfreehand); this.btnCrop.Text = lang.GetString(LangKey.editor_crop); this.btnDelete.Text = lang.GetString(LangKey.editor_deleteelement); - this.removeObjectToolStripMenuItem.Text = lang.GetString(LangKey.editor_deleteelement); this.btnSettings.Text = lang.GetString(LangKey.contextmenu_settings); - this.preferencesToolStripMenuItem.Text = lang.GetString(LangKey.contextmenu_settings); - - this.objectToolStripMenuItem.Text = lang.GetString(LangKey.editor_object); this.btnCut.Text = lang.GetString(LangKey.editor_cuttoclipboard); - this.cutToolStripMenuItem.Text = lang.GetString(LangKey.editor_cuttoclipboard); this.btnCopy.Text = lang.GetString(LangKey.editor_copytoclipboard); - this.copyToolStripMenuItem.Text = lang.GetString(LangKey.editor_copytoclipboard); this.btnPaste.Text = lang.GetString(LangKey.editor_pastefromclipboard); + + this.selectAllToolStripMenuItem.Text = lang.GetString(LangKey.editor_selectall); + this.preferencesToolStripMenuItem.Text = lang.GetString(LangKey.contextmenu_settings); + this.removeObjectToolStripMenuItem.Text = lang.GetString(LangKey.editor_deleteelement); + this.copyToolStripMenuItem.Text = lang.GetString(LangKey.editor_copytoclipboard); this.pasteToolStripMenuItem.Text = lang.GetString(LangKey.editor_pastefromclipboard); + this.cutToolStripMenuItem.Text = lang.GetString(LangKey.editor_cuttoclipboard); this.duplicateToolStripMenuItem.Text = lang.GetString(LangKey.editor_duplicate); + this.objectToolStripMenuItem.Text = lang.GetString(LangKey.editor_object); this.arrangeToolStripMenuItem.Text = lang.GetString(LangKey.editor_arrange); this.upToTopToolStripMenuItem.Text = lang.GetString(LangKey.editor_uptotop); @@ -253,6 +377,7 @@ namespace Greenshot { this.saveElementsToolStripMenuItem.Text = lang.GetString(LangKey.editor_save_objects); this.loadElementsToolStripMenuItem.Text = lang.GetString(LangKey.editor_load_objects); + this.autoCropToolStripMenuItem.Text = lang.GetString(LangKey.editor_autocrop); } public ISurface Surface { @@ -260,7 +385,12 @@ namespace Greenshot { } public void SetImagePath(string fullpath) { - this.lastSaveFullPath = fullpath; + // Check if the editor supports the format + if (fullpath != null && (fullpath.EndsWith(".ico") || fullpath.EndsWith(".wmf"))) { + fullpath = null; + } + surface.LastSaveFullPath = fullpath; + if (fullpath == null) { return; } @@ -297,6 +427,9 @@ namespace Greenshot { case DrawingModes.Obfuscate: SetButtonChecked(btnObfuscate); break; + case DrawingModes.Path: + SetButtonChecked(btnFreehand); + break; } } @@ -330,94 +463,22 @@ namespace Greenshot { #endregion #region filesystem options - void SaveToolStripMenuItemClick(object sender, System.EventArgs e) { - // Use SaveAs if we didn't save before - if (lastSaveFullPath == null) { - SaveAsToolStripMenuItemClick(sender,e); - return; - } - try { - using (Image img = surface.GetImageForExport()) { - ImageOutput.Save(img, lastSaveFullPath); - surface.Modified = false; - } - updateStatusLabel(lang.GetFormattedString(LangKey.editor_imagesaved,lastSaveFullPath),fileSavedStatusContextMenu); - } catch(Exception) { - MessageBox.Show(lang.GetFormattedString(LangKey.error_nowriteaccess,lastSaveFullPath).Replace(@"\\",@"\"), lang.GetString(LangKey.error)); - } - } - void BtnSaveClick(object sender, EventArgs e) { - if (lastSaveFullPath != null) { - SaveToolStripMenuItemClick(sender,e); - } else { - SaveAsToolStripMenuItemClick(sender, e); + string destinationDesignation = Destinations.FileDestination.DESIGNATION; + if (surface.LastSaveFullPath == null) { + destinationDesignation = Destinations.FileWithDialogDestination.DESIGNATION; } + DestinationHelper.ExportCapture(destinationDesignation, surface, surface.CaptureDetails); } - void SaveAsToolStripMenuItemClick(object sender, EventArgs eventArgs) { - try { - using (Image img = surface.GetImageForExport()) { - // Bug #2918756 don't overwrite lastSaveFullPath if SaveWithDialog returns null! - string savedTo = ImageOutput.SaveWithDialog(img, surface.CaptureDetails); - if (savedTo != null) { - surface.Modified = false; - lastSaveFullPath = savedTo; - } - } - - if(lastSaveFullPath != null) { - SetImagePath(lastSaveFullPath); - updateStatusLabel(lang.GetFormattedString(LangKey.editor_imagesaved,lastSaveFullPath),fileSavedStatusContextMenu); - } else { - clearStatusLabel(); - } - } catch (Exception e) { - LOG.Error(lang.GetString(LangKey.error_save), e); - MessageBox.Show(lang.GetString(LangKey.error_save), lang.GetString(LangKey.error)); - } - } - - void CopyImageToClipboardToolStripMenuItemClick(object sender, System.EventArgs e) { - try { - using (Image img = surface.GetImageForExport()) { - ClipboardHelper.SetClipboardData(img); - surface.Modified = false; - } - updateStatusLabel(lang.GetString(LangKey.editor_storedtoclipboard)); - } catch (Exception) { - updateStatusLabel(lang.GetString(LangKey.editor_clipboardfailed)); - } - } - void BtnClipboardClick(object sender, EventArgs e) { - this.CopyImageToClipboardToolStripMenuItemClick(sender, e); - } - - void PrintToolStripMenuItemClick(object sender, EventArgs e) { - InvokePrint(); + DestinationHelper.ExportCapture(Destinations.ClipboardDestination.DESIGNATION, surface, surface.CaptureDetails); } void BtnPrintClick(object sender, EventArgs e) { - // commented for now: workaround seems to have issues on Vista :( - //new ShowPrintDialogDelegate(InvokePrint).BeginInvoke(null,null); - InvokePrint(); + DestinationHelper.ExportCapture(Destinations.PrinterDestination.DESIGNATION, surface, surface.CaptureDetails); } - void InvokePrint() { - using(Image img = surface.GetImageForExport()) { - PrintHelper ph = new PrintHelper(img, surface.CaptureDetails); - this.Hide(); - this.Show(); - PrinterSettings ps = ph.PrintWithDialog(); - - if(ps != null) { - surface.Modified = false; - updateStatusLabel(lang.GetFormattedString(LangKey.editor_senttoprinter,ps.PrinterName)); - } - } - } - void CloseToolStripMenuItemClick(object sender, System.EventArgs e) { this.Close(); } @@ -469,6 +530,11 @@ namespace Greenshot { surface.DrawingMode = DrawingModes.Obfuscate; refreshFieldControls(); } + + void BtnFreehandClick(object sender, EventArgs e) { + surface.DrawingMode = DrawingModes.Path; + refreshFieldControls(); + } void SetButtonChecked(ToolStripButton btn) { UncheckAllToolButtons(); @@ -486,6 +552,10 @@ namespace Greenshot { void AddRectangleToolStripMenuItemClick(object sender, System.EventArgs e) { BtnRectClick(sender, e); } + + void DrawFreehandToolStripMenuItemClick(object sender, System.EventArgs e) { + BtnFreehandClick(sender, e); + } void AddEllipseToolStripMenuItemClick(object sender, System.EventArgs e) { BtnEllipseClick(sender, e); @@ -547,7 +617,25 @@ namespace Greenshot { void BtnPasteClick(object sender, System.EventArgs e) { PasteToolStripMenuItemClick(sender, e); } - + + void UndoToolStripMenuItemClick(object sender, System.EventArgs e) { + surface.Undo(); + updateUndoRedoSurfaceDependencies(); + } + + void BtnUndoClick(object sender, System.EventArgs e) { + UndoToolStripMenuItemClick(sender, e); + } + + void RedoToolStripMenuItemClick(object sender, System.EventArgs e) { + surface.Redo(); + updateUndoRedoSurfaceDependencies(); + } + + void BtnRedoClick(object sender, System.EventArgs e) { + RedoToolStripMenuItemClick(sender, e); + } + void DuplicateToolStripMenuItemClick(object sender, System.EventArgs e) { surface.DuplicateSelectedElements(); updateClipboardSurfaceDependencies(); @@ -584,7 +672,7 @@ namespace Greenshot { } void PreferencesToolStripMenuItemClick(object sender, System.EventArgs e) { - new SettingsForm().Show(); + MainForm.instance.ShowSetting(); } void BtnSettingsClick(object sender, System.EventArgs e) { @@ -599,11 +687,12 @@ namespace Greenshot { #region image editor event handlers void ImageEditorFormActivated(object sender, EventArgs e) { updateClipboardSurfaceDependencies(); + updateUndoRedoSurfaceDependencies(); } void ImageEditorFormFormClosing(object sender, FormClosingEventArgs e) { IniConfig.IniChanged -= new FileSystemEventHandler(ReloadConfiguration); - if (surface.Modified) { + if (surface.Modified && !editorConfiguration.SuppressSaveDialogAtClose) { // Make sure the editor is visible WindowDetails.ToForeground(this.Handle); @@ -618,11 +707,7 @@ namespace Greenshot { return; } if (result.Equals(DialogResult.Yes)) { - if (lastSaveFullPath != null) { - SaveToolStripMenuItemClick(sender,e); - } else { - SaveAsToolStripMenuItemClick(sender, e); - } + BtnSaveClick(sender,e); // Check if the save was made, if not it was cancelled so we cancel the closing if (surface.Modified) { e.Cancel = true; @@ -633,6 +718,9 @@ namespace Greenshot { // persist our geometry string. editorConfiguration.SetEditorPlacement(new WindowDetails(this.Handle).GetWindowPlacement()); IniConfig.Save(); + + // remove from the editor list + editorList.Remove(this); surface.Dispose(); @@ -644,28 +732,55 @@ namespace Greenshot { // avoid conflict with other shortcuts and // make sure there's no selected element claiming input focus if(e.Modifiers.Equals(Keys.None) && !surface.KeysLocked) { - if (Keys.Escape.Equals(e.KeyCode)) { - BtnCursorClick(sender, e); - } else if (Keys.R.Equals(e.KeyCode)) { - BtnRectClick(sender, e); - } else if (Keys.E.Equals(e.KeyCode)) { - BtnEllipseClick(sender, e); - } else if (Keys.L.Equals(e.KeyCode)) { - BtnLineClick(sender, e); - } else if (Keys.A.Equals(e.KeyCode)) { - BtnArrowClick(sender, e); - } else if (Keys.T.Equals(e.KeyCode)) { - BtnTextClick(sender, e); - } else if(Keys.H.Equals(e.KeyCode)) { - BtnHighlightClick(sender, e); - } else if(Keys.O.Equals(e.KeyCode)) { - BtnObfuscateClick(sender, e); - } else if(Keys.C.Equals(e.KeyCode)) { - BtnCropClick(sender, e); + switch(e.KeyCode) { + case Keys.Escape: + BtnCursorClick(sender, e); + break; + case Keys.R: + BtnRectClick(sender, e); + break; + case Keys.E: + BtnEllipseClick(sender, e); + break; + case Keys.L: + BtnLineClick(sender, e); + break; + case Keys.F: + BtnFreehandClick(sender, e); + break; + case Keys.A: + BtnArrowClick(sender, e); + break; + case Keys.T: + BtnTextClick(sender, e); + break; + case Keys.H: + BtnHighlightClick(sender, e); + break; + case Keys.O: + BtnObfuscateClick(sender, e); + break; + case Keys.C: + BtnCropClick(sender, e); + break; + case Keys.P: + //surface.PreviewMode = !surface.PreviewMode; + break; + } + } else if (e.Modifiers.Equals(Keys.Control)) { + switch (e.KeyCode) { + case Keys.Z: + surface.Undo(); + updateUndoRedoSurfaceDependencies(); + break; + case Keys.Y: + surface.Redo(); + updateUndoRedoSurfaceDependencies(); + break; } } } - + /// /// This is a "work-around" for the MouseWheel event which doesn't get to the panel /// @@ -676,10 +791,18 @@ namespace Greenshot { } #endregion - #region cursor key strokes + #region key handling + protected override bool ProcessKeyPreview(ref Message msg) { + // disable default key handling if surface has requested a lock + if (!surface.KeysLocked) { + return base.ProcessKeyPreview(ref msg); + } + return false; + } + protected override bool ProcessCmdKey(ref Message msg, Keys k) { // disable default key handling if surface has requested a lock - if(!surface.KeysLocked) { + if (!surface.KeysLocked) { surface.ProcessCmdKey(k); return base.ProcessCmdKey(ref msg, k); } @@ -688,16 +811,46 @@ namespace Greenshot { #endregion #region helpers + + private void updateUndoRedoSurfaceDependencies() { + bool canUndo = surface.CanUndo; + this.btnUndo.Enabled = canUndo; + this.undoToolStripMenuItem.Enabled = canUndo; + string undoAction = ""; + if (canUndo) { + undoAction = lang.GetString(surface.UndoActionKey); + } + string undoText = lang.GetFormattedString(LangKey.editor_undo, undoAction); + this.btnUndo.Text = undoText; + this.undoToolStripMenuItem.Text = undoText; + + bool canRedo = surface.CanRedo; + this.btnRedo.Enabled = canRedo; + this.redoToolStripMenuItem.Enabled = canRedo; + string redoAction = ""; + if (canRedo) { + redoAction = lang.GetString(surface.RedoActionKey); + } + string redoText = lang.GetFormattedString(LangKey.editor_redo, redoAction); + this.btnRedo.Text = redoText; + this.redoToolStripMenuItem.Text = redoText; + + } + private void updateClipboardSurfaceDependencies() { // check dependencies for the Surface bool hasItems = surface.HasSelectedElements(); bool actionAllowedForSelection = hasItems && !controlsDisabledDueToConfirmable; - this.cutToolStripMenuItem.Enabled = actionAllowedForSelection; + + // buttons this.btnCut.Enabled = actionAllowedForSelection; - this.btnCopy.Enabled = actionAllowedForSelection; - this.copyToolStripMenuItem.Enabled = actionAllowedForSelection; + this.btnDelete.Enabled = actionAllowedForSelection; + // menus + this.removeObjectToolStripMenuItem.Enabled = actionAllowedForSelection; + this.copyToolStripMenuItem.Enabled = actionAllowedForSelection; + this.cutToolStripMenuItem.Enabled = actionAllowedForSelection; this.duplicateToolStripMenuItem.Enabled = actionAllowedForSelection; // check dependencies for the Clipboard @@ -729,12 +882,12 @@ namespace Greenshot { } void CopyPathMenuItemClick(object sender, EventArgs e) { - Clipboard.SetText(lastSaveFullPath); + ClipboardHelper.SetClipboardData(surface.LastSaveFullPath); } void OpenDirectoryMenuItemClick(object sender, EventArgs e) { ProcessStartInfo psi = new ProcessStartInfo("explorer"); - psi.Arguments = Path.GetDirectoryName(lastSaveFullPath); + psi.Arguments = Path.GetDirectoryName(surface.LastSaveFullPath); psi.UseShellExecute = false; Process p = new Process(); p.StartInfo = psi; @@ -787,13 +940,17 @@ namespace Greenshot { obfuscateModeButton.Visible = props.HasFieldValue(FieldType.PREPARED_FILTER_OBFUSCATE); highlightModeButton.Visible = props.HasFieldValue(FieldType.PREPARED_FILTER_HIGHLIGHT); } else { - foreach(ToolStripItem c in propertiesToolStrip.Items) { - c.Visible = false; - } + hideToolstripItems(); } propertiesToolStrip.ResumeLayout(); } + private void hideToolstripItems() { + foreach(ToolStripItem toolStripItem in propertiesToolStrip.Items) { + toolStripItem.Visible = false; + } + } + /// /// refreshes all editor controls depending on selected elements and their fields /// @@ -822,16 +979,11 @@ namespace Greenshot { } // en/disable controls depending on whether an element is selected at all - bool actionAllowedForSelection = surface.HasSelectedElements() && !controlsDisabledDueToConfirmable; - this.btnCopy.Enabled = actionAllowedForSelection; - this.btnCut.Enabled = actionAllowedForSelection; - this.btnDelete.Enabled = actionAllowedForSelection; - this.copyToolStripMenuItem.Enabled = actionAllowedForSelection; - this.cutToolStripMenuItem.Enabled = actionAllowedForSelection; - this.duplicateToolStripMenuItem.Enabled = actionAllowedForSelection; - this.removeObjectToolStripMenuItem.Enabled = actionAllowedForSelection; + updateClipboardSurfaceDependencies(); + updateUndoRedoSurfaceDependencies(); // en/disablearrage controls depending on hierarchy of selected elements + bool actionAllowedForSelection = surface.HasSelectedElements() && !controlsDisabledDueToConfirmable; bool push = actionAllowedForSelection && surface.CanPushSelectionDown(); bool pull = actionAllowedForSelection && surface.CanPullSelectionUp(); this.arrangeToolStripMenuItem.Enabled = (push || pull); @@ -853,6 +1005,7 @@ namespace Greenshot { void EditToolStripMenuItemClick(object sender, EventArgs e) { updateClipboardSurfaceDependencies(); + updateUndoRedoSurfaceDependencies(); } void FontPropertyChanged(object sender, EventArgs e) { @@ -928,21 +1081,30 @@ namespace Greenshot { surface.Refresh(); } } - - void EmailToolStripMenuItemClick(object sender, EventArgs e) { - using (Image img = surface.GetImageForExport()) { - MapiMailMessage.SendImage(img, surface.CaptureDetails); - surface.Modified = false; + + void DestinationToolStripMenuItemClick(object sender, EventArgs e) { + IDestination clickedDestination = null; + if (sender is Control) { + Control clickedControl = sender as Control; + if (clickedControl.ContextMenuStrip != null) { + clickedControl.ContextMenuStrip.Show(Cursor.Position); + return; + } + clickedDestination = (IDestination)clickedControl.Tag; + } else if (sender is ToolStripMenuItem) { + ToolStripMenuItem clickedMenuItem = sender as ToolStripMenuItem; + clickedDestination = (IDestination)clickedMenuItem.Tag; + } + if (clickedDestination != null) { + if (clickedDestination.ExportCapture(surface, surface.CaptureDetails)) { + surface.Modified = false; + } } - } - - void BtnEmailClick(object sender, EventArgs e) { - EmailToolStripMenuItemClick(sender, e); } protected void FilterPresetDropDownItemClicked(object sender, ToolStripItemClickedEventArgs e) { refreshFieldControls(); - + this.Invalidate(true); } void SelectAllToolStripMenuItemClick(object sender, EventArgs e) { @@ -962,7 +1124,7 @@ namespace Greenshot { void Insert_window_toolstripmenuitemMouseEnter(object sender, EventArgs e) { ToolStripMenuItem captureWindowMenuItem = (ToolStripMenuItem)sender; - MainForm.AddCaptureWindowMenuItems(captureWindowMenuItem, Contextmenu_window_Click); + MainForm.instance.AddCaptureWindowMenuItems(captureWindowMenuItem, Contextmenu_window_Click); } void Contextmenu_window_Click(object sender, EventArgs e) { @@ -975,9 +1137,9 @@ namespace Greenshot { capture.CaptureDetails.DpiY = graphics.DpiY; } windowToCapture.Restore(); - windowToCapture = CaptureForm.SelectCaptureWindow(windowToCapture); + windowToCapture = CaptureHelper.SelectCaptureWindow(windowToCapture); if (windowToCapture != null) { - capture = CaptureForm.CaptureWindow(windowToCapture, capture, coreConf.WindowCaptureMode); + capture = CaptureHelper.CaptureWindow(windowToCapture, capture, coreConf.WindowCaptureMode); this.Activate(); WindowDetails.ToForeground(this.Handle); if (capture!= null && capture.Image != null) { @@ -992,5 +1154,11 @@ namespace Greenshot { LOG.Error(exception); } } + + void AutoCropToolStripMenuItemClick(object sender, EventArgs e) { + if (surface.AutoCrop()) { + refreshFieldControls(); + } + } } } diff --git a/Greenshot/Forms/ImageEditorForm.resx b/Greenshot/Forms/ImageEditorForm.resx index 23f8e2d19..ebd96da97 100644 --- a/Greenshot/Forms/ImageEditorForm.resx +++ b/Greenshot/Forms/ImageEditorForm.resx @@ -834,9 +834,118 @@ - iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAACJJREFUKFNjZEAF - ////RxNB4QKlkQG6UupKU9c0TI+S7xMAKX+JeHFERhgAAAAASUVORK5CYII= + iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6 + JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAADAFBMVEWAgID///8AAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4OAdWAAAACXBIWXMAAA7CAAAOwgEVKEqAAAAAGXRF + WHRTb2Z0d2FyZQBQYWludC5ORVQgdjMuNS44NzuAXQAAABZJREFUGFdjYAABRhAAs4hlkq4DZDgACywA + M12jTsYAAAAASUVORK5CYII= + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAACH + DwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAAKOWlDQ1BQaG90b3Nob3AgSUNDIHByb2Zp + bGUAAEjHnZZ3VFTXFofPvXd6oc0wAlKG3rvAANJ7k15FYZgZYCgDDjM0sSGiAhFFRJoiSFDEgNFQJFZE + sRAUVLAHJAgoMRhFVCxvRtaLrqy89/Ly++Osb+2z97n77L3PWhcAkqcvl5cGSwGQyhPwgzyc6RGRUXTs + AIABHmCAKQBMVka6X7B7CBDJy82FniFyAl8EAfB6WLwCcNPQM4BOB/+fpFnpfIHomAARm7M5GSwRF4g4 + JUuQLrbPipgalyxmGCVmvihBEcuJOWGRDT77LLKjmNmpPLaIxTmns1PZYu4V8bZMIUfEiK+ICzO5nCwR + 3xKxRoowlSviN+LYVA4zAwAUSWwXcFiJIjYRMYkfEuQi4uUA4EgJX3HcVyzgZAvEl3JJS8/hcxMSBXQd + li7d1NqaQffkZKVwBALDACYrmcln013SUtOZvBwAFu/8WTLi2tJFRbY0tba0NDQzMv2qUP91829K3NtF + ehn4uWcQrf+L7a/80hoAYMyJarPziy2uCoDOLQDI3fti0zgAgKSobx3Xv7oPTTwviQJBuo2xcVZWlhGX + wzISF/QP/U+Hv6GvvmckPu6P8tBdOfFMYYqALq4bKy0lTcinZ6QzWRy64Z+H+B8H/nUeBkGceA6fwxNF + hImmjMtLELWbx+YKuGk8Opf3n5r4D8P+pMW5FonS+BFQY4yA1HUqQH7tBygKESDR+8Vd/6NvvvgwIH55 + 4SqTi3P/7zf9Z8Gl4iWDm/A5ziUohM4S8jMX98TPEqABAUgCKpAHykAd6ABDYAasgC1wBG7AG/iDEBAJ + VgMWSASpgA+yQB7YBApBMdgJ9oBqUAcaQTNoBcdBJzgFzoNL4Bq4AW6D+2AUTIBnYBa8BgsQBGEhMkSB + 5CEVSBPSh8wgBmQPuUG+UBAUCcVCCRAPEkJ50GaoGCqDqqF6qBn6HjoJnYeuQIPQXWgMmoZ+h97BCEyC + qbASrAUbwwzYCfaBQ+BVcAK8Bs6FC+AdcCXcAB+FO+Dz8DX4NjwKP4PnEIAQERqiihgiDMQF8UeikHiE + j6xHipAKpAFpRbqRPuQmMorMIG9RGBQFRUcZomxRnqhQFAu1BrUeVYKqRh1GdaB6UTdRY6hZ1Ec0Ga2I + 1kfboL3QEegEdBa6EF2BbkK3oy+ib6Mn0K8xGAwNo42xwnhiIjFJmLWYEsw+TBvmHGYQM46Zw2Kx8lh9 + rB3WH8vECrCF2CrsUexZ7BB2AvsGR8Sp4Mxw7rgoHA+Xj6vAHcGdwQ3hJnELeCm8Jt4G749n43PwpfhG + fDf+On4Cv0CQJmgT7AghhCTCJkIloZVwkfCA8JJIJKoRrYmBRC5xI7GSeIx4mThGfEuSIemRXEjRJCFp + B+kQ6RzpLuklmUzWIjuSo8gC8g5yM/kC+RH5jQRFwkjCS4ItsUGiRqJDYkjiuSReUlPSSXK1ZK5kheQJ + yeuSM1J4KS0pFymm1HqpGqmTUiNSc9IUaVNpf+lU6RLpI9JXpKdksDJaMm4ybJkCmYMyF2TGKQhFneJC + YVE2UxopFykTVAxVm+pFTaIWU7+jDlBnZWVkl8mGyWbL1sielh2lITQtmhcthVZKO04bpr1borTEaQln + yfYlrUuGlszLLZVzlOPIFcm1yd2WeydPl3eTT5bfJd8p/1ABpaCnEKiQpbBf4aLCzFLqUtulrKVFS48v + vacIK+opBimuVTyo2K84p6Ss5KGUrlSldEFpRpmm7KicpFyufEZ5WoWiYq/CVSlXOavylC5Ld6Kn0Cvp + vfRZVUVVT1Whar3qgOqCmrZaqFq+WpvaQ3WCOkM9Xr1cvUd9VkNFw08jT6NF454mXpOhmai5V7NPc15L + Wytca6tWp9aUtpy2l3audov2Ax2yjoPOGp0GnVu6GF2GbrLuPt0berCehV6iXo3edX1Y31Kfq79Pf9AA + bWBtwDNoMBgxJBk6GWYathiOGdGMfI3yjTqNnhtrGEcZ7zLuM/5oYmGSYtJoct9UxtTbNN+02/R3Mz0z + llmN2S1zsrm7+QbzLvMXy/SXcZbtX3bHgmLhZ7HVosfig6WVJd+y1XLaSsMq1qrWaoRBZQQwShiXrdHW + ztYbrE9Zv7WxtBHYHLf5zdbQNtn2iO3Ucu3lnOWNy8ft1OyYdvV2o/Z0+1j7A/ajDqoOTIcGh8eO6o5s + xybHSSddpySno07PnU2c+c7tzvMuNi7rXM65Iq4erkWuA24ybqFu1W6P3NXcE9xb3Gc9LDzWepzzRHv6 + eO7yHPFS8mJ5NXvNelt5r/Pu9SH5BPtU+zz21fPl+3b7wX7efrv9HqzQXMFb0ekP/L38d/s/DNAOWBPw + YyAmMCCwJvBJkGlQXlBfMCU4JvhI8OsQ55DSkPuhOqHC0J4wybDosOaw+XDX8LLw0QjjiHUR1yIVIrmR + XVHYqLCopqi5lW4r96yciLaILoweXqW9KnvVldUKq1NWn46RjGHGnIhFx4bHHol9z/RnNjDn4rziauNm + WS6svaxnbEd2OXuaY8cp40zG28WXxU8l2CXsTphOdEisSJzhunCruS+SPJPqkuaT/ZMPJX9KCU9pS8Wl + xqae5Mnwknm9acpp2WmD6frphemja2zW7Fkzy/fhN2VAGasyugRU0c9Uv1BHuEU4lmmfWZP5Jiss60S2 + dDYvuz9HL2d7zmSue+63a1FrWWt78lTzNuWNrXNaV78eWh+3vmeD+oaCDRMbPTYe3kTYlLzpp3yT/LL8 + V5vDN3cXKBVsLBjf4rGlpVCikF84stV2a9021DbutoHt5turtn8sYhddLTYprih+X8IqufqN6TeV33za + Eb9joNSydP9OzE7ezuFdDrsOl0mX5ZaN7/bb3VFOLy8qf7UnZs+VimUVdXsJe4V7Ryt9K7uqNKp2Vr2v + Tqy+XeNc01arWLu9dn4fe9/Qfsf9rXVKdcV17w5wD9yp96jvaNBqqDiIOZh58EljWGPft4xvm5sUmoqb + PhziHRo9HHS4t9mqufmI4pHSFrhF2DJ9NProje9cv+tqNWytb6O1FR8Dx4THnn4f+/3wcZ/jPScYJ1p/ + 0Pyhtp3SXtQBdeR0zHYmdo52RXYNnvQ+2dNt293+o9GPh06pnqo5LXu69AzhTMGZT2dzz86dSz83cz7h + /HhPTM/9CxEXbvUG9g5c9Ll4+ZL7pQt9Tn1nL9tdPnXF5srJq4yrndcsr3X0W/S3/2TxU/uA5UDHdavr + XTesb3QPLh88M+QwdP6m681Lt7xuXbu94vbgcOjwnZHokdE77DtTd1PuvriXeW/h/sYH6AdFD6UeVjxS + fNTws+7PbaOWo6fHXMf6Hwc/vj/OGn/2S8Yv7ycKnpCfVEyqTDZPmU2dmnafvvF05dOJZ+nPFmYKf5X+ + tfa5zvMffnP8rX82YnbiBf/Fp99LXsq/PPRq2aueuYC5R69TXy/MF72Rf3P4LeNt37vwd5MLWe+x7ys/ + 6H7o/ujz8cGn1E+f/gUDmPP8usTo0wAAAAlwSFlzAAALEgAACxIB0t1+/AAAAhFJREFUOE+V009Ik2Ec + B/Dfb0owoUMRkiSeyovUxYoOgQwHIwP37k1XEGiHNAPXi8pqzhU157RYDOqgRtFr5oo1jHTWxZIoOoQo + /qNTkIJpUdaxDuvp+4xe2eu2Q4cPz3hevt/nz/uOhBAkVZ0KbXJqMXJffEqvYkwulyttlVkqnsM4TpTO + SJs/ZEFT9/P94JThHAVHl5lHZ5l7ZYHH4zEXVDdEZEES3FsLFEUpt9ls2h+vV6w4HF9GiexZBQg2wyAU + ZBYY4VQqJRKJxFKc6O1Irh0g+B4q5bkNL0e4auwOJz+8U8VkvPKn1WrtC+AO9DwFn1Cwc2v493qXWHyt + fA1r9GZvWSGpFkvegn4UDOBsO4yVjXCPtm0W8yegBopy7qDWMywv8VowoHwbiu75LsMzk+qvq1pJ6t/x + 4hgnYA3qwPwW7nqJdB+V3fNvv7zxsVkkhw7/CGnWRaxYaG+MknSoRpOLlMMT2GX6Dm5dII62clBsTIt2 + N+vnFfZ3nWW60oJ3hnDn7Sl6kFwgfWxeljyGClNBuIkjn5diolXlRy1OPnaulqnjNNNUo52GJxbS4YyC + hyg4YCqQXyeCcQQrbqr7aLzOQeLkDRL1faYCBEvgWdYRMLEOYTgoLyiPIsz3QDDrEjFRCpfgBcyBDj44 + Aw3QDgm4D7tzFRirWvCwGI5DG/TCdQjAkcydme7A+Hv+7/gXya8DPW6boNQAAAAASUVORK5CYII= + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAACp0lEQVQ4T6WTa0iTcRTG/xTt + g5aG+aENuphoXog0DSoSR5JEMOliJMuUUIp0g9CKYWmpaWuYbVTSKsW8zFsz1EosvKWl2atvTO3mqyVr + zkWFSmvsUqfzH/GC1jc//NhznvOc5/1/GQEAshjcx1s1HNleMkmibptIdOm0SFxmkSE6hPkL1TK6i7oz + RVAnIlp6u7BAElNuZk+0zxnzDQ6rhvsNFKqpt6vM3IkfKUAYyvyCm58ksfdMhusTv6CAdcClIQcoh52g + GnXBZYMTCl874OpbJ+BLGa0J3L98QeS1D6KdJROsZswF2b0/4HTHjG1ftYmLVI8xlEMNU5xqxA5Zz+bw + RS6gmvp8QdiVEVlyk9mo6PgOaS3TNpyZcNWoNKL4PdmsHCY436CeeswJGa1foJC1Ap35gpC8wZrMzq/W + k/rPINaMcqH5Q1IMkKCLr0hwLpOIe/ez8wbm3BS/swP1+IKArOfM2a5vkFT9EajemN1PgnJeksDzfSTw + 3Ast9RZCfb5gXWYHk95mgYMV40D1mlNPiUjeSvzOdBE8JP6KHrI2o53gLgIzYsxG47yeLxCmP66Jr5u0 + 7qmahE15fZww7ZHUN/UB8U6uJ77HmwjV6G0JvdCrwIwsrmo8Hm8C+AIMyCKKBo07aqchts5kw5lZldIo + pQUU1HvRU+6uMWowIw9TDsThLOQLvJPqRD6penZbyyyE3J8BcaPFFpzbw3kdrWWQbtRPxHpLM+7UmJH7 + pOhj8EbAF6w4oiOeCZUSrxS9wa/ZBqsbf4J/iw3C2+yUWdRv0HuIO7XXsYZkzArpzbwCj8MVRHCgVCJI + qGQ9c/qNy8stVo9mFyCzqFnP7D6dIKFCgZkNNPvfgmX775KlcVrREsktGaJDGKQbKUIkuFtJM/8ULObv + /AfX+Vsh8ZRqjgAAAABJRU5ErkJggg== + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAACrUlEQVQ4T6WTa0iTYRTHH4r2 + QWuG+aENuphoXoi0GWQkjiSJYNLFSJYpoRTphNCKYWmpaUvMNipplWJepmYznJVYeEtLs1ffmK7bXi1Z + UxcVKq3htjqdZ8ik7Jsffu/+53/+5+x9njECAGQxuIbF5RY1khB5e5xElU0KUcsQDcLMQbWM9iJvmUlE + 6RjZquJcs64HmswcBTvLJzqOt82Y8vV2q4r7DRSqqRddMcFiTrJgARqM2gxAP6+8dUDhaztc0jugyOAE + xZADLg7aoYC1w7XRXxBz16yPuPFJ8tcbhCuNTNHwLH6bE7KezQDVBxvGOepT9taYuVPtU7bsnh+gMjph + R+koG371g9B9hNDLw0wha4WMli+gNDqA1sj1zYohIip5T8KKDFLqpTZP2uTt3yGpacKEtcy9IDhvgCl5 + Nwt5/TMu6HGoF5TLJAReeEUwTELyB6VilYE7of0MmR1frdivdS8IOPtC7Z/1nPkX6gec6yWBOS/Jxuw+ + QvuJNR/hTOc3oNq9YG1G2/q0VkvUgcoR8brMdhHWxE/eTQeI7+lOIkxvIWtOPiXYYzADmAWq3QsEaY/9 + Y6tH4nZXj8lCzvfIBamPtvikPCA+x5qIV9I9QjV60k15vRxmIK5+zIoz80fAgCBU0R+7vW4yfVetSYW1 + YlVy4x46TEEtRY+JqTfbMAOi4gET1vOX6JVYz/NO1kZva55OD74/pRRrLbqg3O4n/CN1XQheZjcnbrTY + sAeYAe8ULYsz8z/jisMa4hlfJeAfbUjy1dmUqxt/PvRrtr0Ja52dRgA1oAfYA36yVo9ZCZ1x3wEtPA5V + Et7+sg28+Eq5Z3avZnmFhfXQOacRQG31zOkz8eKrWMxIaPa/C5btu0OWxqpXLpHclCDFSBfCIBpEhj0h + zSxYsJi/8x/XGVshytjcjQAAAABJRU5ErkJggg== diff --git a/Greenshot/Forms/JpegQualityDialog.cs b/Greenshot/Forms/JpegQualityDialog.cs index d03f2b501..094749319 100644 --- a/Greenshot/Forms/JpegQualityDialog.cs +++ b/Greenshot/Forms/JpegQualityDialog.cs @@ -19,11 +19,10 @@ * along with this program. If not, see . */ using System; -using System.Drawing; using System.Windows.Forms; - using Greenshot.Configuration; using GreenshotPlugin.Core; +using IniFile; namespace Greenshot { /// diff --git a/Greenshot/Forms/LanguageDialog.Designer.cs b/Greenshot/Forms/LanguageDialog.Designer.cs index 87a09fd58..9483ce227 100644 --- a/Greenshot/Forms/LanguageDialog.Designer.cs +++ b/Greenshot/Forms/LanguageDialog.Designer.cs @@ -58,7 +58,7 @@ namespace Greenshot.Forms { this.comboBoxLanguage.FormattingEnabled = true; this.comboBoxLanguage.Location = new System.Drawing.Point(13, 15); this.comboBoxLanguage.Name = "comboBoxLanguage"; - this.comboBoxLanguage.Size = new System.Drawing.Size(299, 21); + this.comboBoxLanguage.Size = new System.Drawing.Size(360, 21); this.comboBoxLanguage.TabIndex = 3; // // btnOK @@ -76,17 +76,19 @@ namespace Greenshot.Forms { this.AcceptButton = this.btnOK; this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.ClientSize = new System.Drawing.Size(327, 77); - this.ControlBox = false; + this.ClientSize = new System.Drawing.Size(390, 77); + this.ControlBox = true; this.Controls.Add(this.btnOK); this.Controls.Add(this.comboBoxLanguage); this.Controls.Add(this.lblSelectLanguage); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Icon = GreenshotPlugin.Core.GreenshotResources.getGreenshotIcon(); this.MaximizeBox = false; this.MinimizeBox = false; this.Name = "LanguageDialog"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.Text = "Choose language / Sprache wählen / Taal kiezen"; + this.Text = "Greenshot: Choose language / Sprache wählen / Taal kiezen"; + this.TopMost = true; this.ResumeLayout(false); } private System.Windows.Forms.Label lblSelectLanguage; diff --git a/Greenshot/Forms/LanguageDialog.cs b/Greenshot/Forms/LanguageDialog.cs index f7e49b777..bd6b713ac 100644 --- a/Greenshot/Forms/LanguageDialog.cs +++ b/Greenshot/Forms/LanguageDialog.cs @@ -19,9 +19,6 @@ * along with this program. If not, see . */ using System; -using System.Collections.Generic; -using System.Drawing; -using System.Globalization; using System.Threading; using System.Windows.Forms; @@ -35,16 +32,26 @@ namespace Greenshot.Forms { public partial class LanguageDialog : Form { private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(LanguageDialog)); private static LanguageDialog uniqueInstance; - private ILanguage language = Language.GetInstance(); + private ILanguage language = Language.GetInstance(false); + private bool properOkPressed = false; + private LanguageDialog() { // // The InitializeComponent() call is required for Windows Forms designer support. // InitializeComponent(); this.Load += FormLoad; - + this.FormClosing += PreventFormClose; } + private void PreventFormClose(object sender, FormClosingEventArgs e) { + if(!properOkPressed) { + e.Cancel = true; + } else { + language.FreeResources(); + } + } + public string SelectedLanguage { get { return comboBoxLanguage.SelectedValue.ToString(); } } @@ -61,10 +68,15 @@ namespace Greenshot.Forms { if (language.CurrentLanguage != null) { LOG.DebugFormat("Selecting {0}", language.CurrentLanguage); this.comboBoxLanguage.SelectedValue = language.CurrentLanguage; + } else { + this.comboBoxLanguage.SelectedValue = Thread.CurrentThread.CurrentUICulture.Name; } } void BtnOKClick(object sender, EventArgs e) { + properOkPressed = true; + // Fix for Bug #3431100 + language.SetLanguage(SelectedLanguage); this.Close(); } diff --git a/Greenshot/Forms/MainForm.Designer.cs b/Greenshot/Forms/MainForm.Designer.cs index 070709d29..c2efeb8b5 100644 --- a/Greenshot/Forms/MainForm.Designer.cs +++ b/Greenshot/Forms/MainForm.Designer.cs @@ -123,7 +123,8 @@ namespace Greenshot { this.contextmenu_capturewindow.ShortcutKeyDisplayString = "Alt + Print"; this.contextmenu_capturewindow.Size = new System.Drawing.Size(242, 22); this.contextmenu_capturewindow.Text = "Capture window"; - this.contextmenu_capturewindow.MouseEnter += new System.EventHandler(EnterCaptureWindowMenuItem); + this.contextmenu_capturewindow.DropDownOpening += new System.EventHandler(CaptureWindowMenuDropDownOpening); + this.contextmenu_capturewindow.DropDownClosed += new System.EventHandler(CaptureWindowMenuDropDownClosed); // // contextmenu_capturefullscreen // @@ -226,7 +227,7 @@ namespace Greenshot { this.contextmenu_captureie.Size = new System.Drawing.Size(231, 22); this.contextmenu_captureie.Text = "Capture IE Tab"; this.contextmenu_captureie.ShortcutKeyDisplayString = "Ctrl + Shift + Print"; - this.contextmenu_captureie.MouseEnter += new System.EventHandler(EnterCaptureIEMenuItem); + this.contextmenu_captureie.DropDownOpening += new System.EventHandler(CaptureIEMenuDropDownOpening); // // backgroundWorkerTimer // @@ -277,7 +278,7 @@ namespace Greenshot { private System.Windows.Forms.ToolStripMenuItem contextmenu_capturefullscreen; private System.Windows.Forms.ToolStripMenuItem contextmenu_capturelastregion; private System.Windows.Forms.ToolStripMenuItem contextmenu_capturearea; - private System.Windows.Forms.NotifyIcon notifyIcon; + public System.Windows.Forms.NotifyIcon notifyIcon; private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; private System.Windows.Forms.ToolStripMenuItem contextmenu_exit; private System.Windows.Forms.ContextMenuStrip contextMenu; diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs index 150598978..e219b8547 100644 --- a/Greenshot/Forms/MainForm.cs +++ b/Greenshot/Forms/MainForm.cs @@ -19,12 +19,9 @@ * along with this program. If not, see . */ using System; -using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Printing; using System.IO; using System.Reflection; using System.Security.AccessControl; @@ -34,41 +31,27 @@ using System.Threading; using System.Windows.Forms; using Greenshot.Configuration; -using Greenshot.Drawing; using Greenshot.Experimental; using Greenshot.Forms; using Greenshot.Help; using Greenshot.Helpers; using Greenshot.Plugin; -using Greenshot.UnmanagedHelpers; +using GreenshotPlugin.UnmanagedHelpers; using GreenshotPlugin.Controls; using GreenshotPlugin.Core; +using IniFile; namespace Greenshot { /// /// Description of MainForm. /// public partial class MainForm : Form { - private const string LOG4NET_FILE = "log4net.xml"; private static log4net.ILog LOG = null; private static Mutex applicationMutex = null; private static CoreConfiguration conf; - - private static void InitializeLog4NET() { - // Setup log4j, currently the file is called log4net.xml - string log4netFilename = Path.Combine(Application.StartupPath, LOG4NET_FILE); - if (File.Exists(log4netFilename)) { - log4net.Config.XmlConfigurator.Configure(new FileInfo(log4netFilename)); - } else { - MessageBox.Show("Can't find file " + LOG4NET_FILE); - } - - // Setup the LOG - LOG = log4net.LogManager.GetLogger(typeof(MainForm)); - } + public static string LogFileLocation = null; - [STAThread] - public static void Main(string[] args) { + public static void Start(string[] args) { bool isAlreadyRunning = false; List filesToOpen = new List(); @@ -76,7 +59,9 @@ namespace Greenshot { Thread.CurrentThread.Name = Application.ProductName; // Init Log4NET - InitializeLog4NET(); + LogFileLocation = LogHelper.InitializeLog4NET(); + // Get logger + LOG = log4net.LogManager.GetLogger(typeof(MainForm)); Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); @@ -84,6 +69,7 @@ namespace Greenshot { // Log the startup LOG.Info("Starting: " + EnvironmentInfo.EnvironmentToString(false)); + IniConfig.Init(); AppConfig.UpgradeToIni(); // Read configuration conf = IniConfig.GetIniSection(); @@ -100,7 +86,7 @@ namespace Greenshot { mutexsecurity.AddAccessRule(new MutexAccessRule(sid, MutexRights.ChangePermissions, AccessControlType.Deny)); mutexsecurity.AddAccessRule(new MutexAccessRule(sid, MutexRights.Delete, AccessControlType.Deny)); - bool created = false; + bool created = false; // 1) Create Mutex applicationMutex = new Mutex(false, @"Local\F48E86D3-E34C-4DB7-8F8F-9A0EA55F0D08", out created, mutexsecurity); // 2) Get the right to it, this returns false if it's already locked @@ -223,8 +209,9 @@ namespace Greenshot { } } - ILanguage lang = Language.GetInstance(); if (isAlreadyRunning) { + // We didn't initialize the language yet, do it here just for the message box + ILanguage lang = Language.GetInstance(); if (filesToOpen.Count > 0) { SendData(transport); } else { @@ -240,21 +227,22 @@ namespace Greenshot { Application.SetCompatibleTextRenderingDefault(false); // if language is not set, show language dialog - if(conf.Language == null || conf.Language.Trim().Length == 0) { - LanguageDialog ld = LanguageDialog.GetInstance(); - ld.ShowDialog(); - conf.Language = ld.SelectedLanguage; + if(string.IsNullOrEmpty(conf.Language)) { + LanguageDialog languageDialog = LanguageDialog.GetInstance(); + languageDialog.ShowDialog(); + conf.Language = languageDialog.SelectedLanguage; IniConfig.Save(); } // Check if it's the first time launch? - if(conf.IsFirstLaunch) { + if(conf.IsFirstLaunch) { conf.IsFirstLaunch = false; IniConfig.Save(); transport.AddCommand(CommandEnum.FirstLaunch); } + MainForm mainForm = new MainForm(transport); - Application.Run(mainForm); + Application.Run(); } catch(Exception ex) { LOG.Error("Exception in startup.", ex); Application_ThreadException(MainForm.ActiveForm, new ThreadExceptionEventArgs(ex)); @@ -288,11 +276,24 @@ namespace Greenshot { private ILanguage lang; private ToolTip tooltip; - private CaptureForm captureForm = null; private CopyData copyData = null; + + // Thumbnail preview + private FormWithoutActivation thumbnailForm = null; + private IntPtr thumbnailHandle = IntPtr.Zero; + private Rectangle parentMenuBounds = Rectangle.Empty; + // Make sure we have only one settings form + private SettingsForm settingsForm = null; + // Make sure we have only one about form + private AboutForm aboutForm = null; + // Make sure we have only one help browser + private HelpBrowserForm helpBrowserForm = null; public MainForm(CopyDataTransport dataTransport) { instance = this; + + // Make sure we never capture the mainform + WindowDetails.RegisterIgnoreHandle(this.Handle); // // The InitializeComponent() call is required for Windows Forms designer support. // @@ -307,14 +308,35 @@ namespace Greenshot { tooltip = new ToolTip(); UpdateUI(); - InitializeQuickSettingsMenu(); + + // Do loading on a different Thread to shorten the startup + Thread pluginInitThread = new Thread (delegate() { + // Load all the plugins + PluginHelper.instance.LoadPlugins(this); + + // Check destinations, remove all that don't exist + foreach(string destination in conf.OutputDestinations.ToArray()) { + if (DestinationHelper.GetDestination(destination) == null) { + conf.OutputDestinations.Remove(destination); + } + } + + // we should have at least one! + if (conf.OutputDestinations.Count == 0) { + conf.OutputDestinations.Add(Destinations.EditorDestination.DESIGNATION); + } + BeginInvoke((MethodInvoker)delegate { + // Do after all plugins & finding the destination, otherwise they are missing! + InitializeQuickSettingsMenu(); + }); + }); + pluginInitThread.Name = "Initialize plug-ins"; + pluginInitThread.IsBackground = true; + pluginInitThread.Start(); - captureForm = new CaptureForm(); - - // Load all the plugins - PluginHelper.instance.LoadPlugins(this, captureForm); SoundHelper.Initialize(); + // Enable the Greenshot icon to be visible, this prevents Problems with the context menu notifyIcon.Visible = true; @@ -331,7 +353,6 @@ namespace Greenshot { if (dataTransport != null) { HandleDataTransport(dataTransport); } - ClipboardHelper.RegisterClipboardViewer(this.Handle); } /// @@ -344,25 +365,47 @@ namespace Greenshot { CopyDataTransport dataTransport = (CopyDataTransport)copyDataReceivedEventArgs.Data; HandleDataTransport(dataTransport); } - + private void HandleDataTransport(CopyDataTransport dataTransport) { foreach(KeyValuePair command in dataTransport.Commands) { LOG.Debug("Data received, Command = " + command.Key + ", Data: " + command.Value); switch(command.Key) { case CommandEnum.Exit: - exit(); + Exit(); break; case CommandEnum.FirstLaunch: - LOG.Info("FirstLaunch: Created new configuration."); + LOG.Info("FirstLaunch: Created new configuration, showing balloon."); + + try { + EventHandler balloonTipClickedHandler = null; + EventHandler balloonTipClosedHandler = null; + balloonTipClosedHandler = delegate(object sender, EventArgs e) { + notifyIcon.BalloonTipClicked -= balloonTipClickedHandler; + notifyIcon.BalloonTipClosed -= balloonTipClosedHandler; + }; + + balloonTipClickedHandler = delegate(object sender, EventArgs e) { + ShowSetting(); + notifyIcon.BalloonTipClicked -= balloonTipClickedHandler; + notifyIcon.BalloonTipClosed -= balloonTipClosedHandler; + }; + notifyIcon.BalloonTipClicked += balloonTipClickedHandler; + notifyIcon.BalloonTipClosed += balloonTipClosedHandler; + notifyIcon.ShowBalloonTip(2000, "Greenshot", lang.GetFormattedString(LangKey.tooltip_firststart, HotkeyControl.GetLocalizedHotkeyStringFromString(conf.RegionHotkey)), ToolTipIcon.Info); + } catch {} break; case CommandEnum.ReloadConfig: - IniConfig.Reload(); - ReloadConfiguration(null, null); + try { + IniConfig.Reload(); + ReloadConfiguration(null, null); + } catch {} break; case CommandEnum.OpenFile: string filename = command.Value; if (File.Exists(filename)) { - captureForm.MakeCapture(filename); + BeginInvoke((MethodInvoker)delegate { + CaptureHelper.CaptureFile(filename); + }); } else { LOG.Warn("No such file: " + filename); } @@ -374,8 +417,15 @@ namespace Greenshot { } } + /// + /// This is called when the ini-file changes + /// + /// + /// private void ReloadConfiguration(object source, FileSystemEventArgs e) { + lang.Load(); lang.SetLanguage(conf.Language); + lang.FreeResources(); this.Invoke((MethodInvoker) delegate { // Even update language when needed UpdateUI(); @@ -392,9 +442,6 @@ namespace Greenshot { #region hotkeys protected override void WndProc(ref Message m) { - if (ClipboardHelper.HandleClipboardMessages(ref m)) { - return; - } if (HotkeyControl.HandleMessages(ref m)) { return; } @@ -503,8 +550,9 @@ namespace Greenshot { #region mainform events void MainFormFormClosing(object sender, FormClosingEventArgs e) { + LOG.DebugFormat("Mainform closing, reason: {0}", e.CloseReason); instance = null; - exit(); + Exit(); } void MainFormActivated(object sender, EventArgs e) { @@ -515,98 +563,103 @@ namespace Greenshot { #region key handlers void CaptureRegion() { - captureForm.MakeCapture(CaptureMode.Region, true); + CaptureHelper.CaptureRegion(true); } void CaptureClipboard() { - captureForm.MakeCapture(CaptureMode.Clipboard, false); + CaptureHelper.CaptureClipboard(); } + void CaptureFile() { OpenFileDialog openFileDialog = new OpenFileDialog(); - openFileDialog.Filter = "Image files (*.png, *.jpg, *.gif, *.bmp, *.ico)|*.png; *.jpg; *.jpeg; *.gif; *.bmp; *.ico"; + openFileDialog.Filter = "Image files (*.png, *.jpg, *.gif, *.bmp, *.ico, *.tiff, *.wmf)|*.png; *.jpg; *.jpeg; *.gif; *.bmp; *.ico; *.tiff; *.tif; *.wmf"; if (openFileDialog.ShowDialog() == DialogResult.OK) { if (File.Exists(openFileDialog.FileName)) { - captureForm.MakeCapture(openFileDialog.FileName); + CaptureHelper.CaptureFile(openFileDialog.FileName); } } } void CaptureFullScreen() { - captureForm.MakeCapture(CaptureMode.FullScreen, true); + CaptureHelper.CaptureFullscreen(true); } void CaptureLastRegion() { - captureForm.MakeCapture(CaptureMode.LastRegion, true); + CaptureHelper.CaptureLastRegion(true); } void CaptureIE() { - captureForm.MakeCapture(CaptureMode.IE, true); + CaptureHelper.CaptureIE(true); } void CaptureWindow() { - CaptureMode captureMode = CaptureMode.None; if (conf.CaptureWindowsInteractive) { - captureMode = CaptureMode.Window; + CaptureHelper.CaptureWindowInteractive(true); } else { - captureMode = CaptureMode.ActiveWindow; + CaptureHelper.CaptureWindow(true); } - captureForm.MakeCapture(captureMode, true); } #endregion - + + #region contextmenu void ContextMenuOpening(object sender, System.ComponentModel.CancelEventArgs e) { - if (Clipboard.ContainsImage()) { - contextmenu_captureclipboard.Enabled = true; - } else { - contextmenu_captureclipboard.Enabled = false; - } + contextmenu_captureclipboard.Enabled = ClipboardHelper.ContainsImage(); contextmenu_capturelastregion.Enabled = RuntimeConfig.LastCapturedRegion != Rectangle.Empty; // IE context menu code - if (conf.IECapture && IECaptureHelper.IsIERunning()) { - this.contextmenu_captureie.Enabled = true; - } else { - this.contextmenu_captureie.Enabled = false; + try { + if (conf.IECapture && IECaptureHelper.IsIERunning()) { + this.contextmenu_captureie.Enabled = true; + } else { + this.contextmenu_captureie.Enabled = false; + } + } catch (Exception ex) { + LOG.WarnFormat("Problem accessing IE information: {0}", ex.Message); } } void ContextMenuClosing(object sender, EventArgs e) { this.contextmenu_captureie.DropDownItems.Clear(); this.contextmenu_capturewindow.DropDownItems.Clear(); + cleanupThumbnail(); } /// /// Build a selectable list of IE tabs when we enter the menu item /// - void EnterCaptureIEMenuItem(object sender, EventArgs e) { - List> tabs = IECaptureHelper.GetTabList(); - this.contextmenu_captureie.DropDownItems.Clear(); - if (tabs.Count > 0) { - this.contextmenu_captureie.Enabled = true; - Dictionary counter = new Dictionary(); - - foreach(KeyValuePair tabData in tabs) { - ToolStripMenuItem captureIETabItem = new ToolStripMenuItem(tabData.Value); - int index; - if (counter.ContainsKey(tabData.Key)) { - index = counter[tabData.Key]; - } else { - index = 0; + void CaptureIEMenuDropDownOpening(object sender, EventArgs e) { + try { + List> tabs = IECaptureHelper.GetTabList(); + this.contextmenu_captureie.DropDownItems.Clear(); + if (tabs.Count > 0) { + this.contextmenu_captureie.Enabled = true; + Dictionary counter = new Dictionary(); + + foreach(KeyValuePair tabData in tabs) { + ToolStripMenuItem captureIETabItem = new ToolStripMenuItem(tabData.Value); + int index; + if (counter.ContainsKey(tabData.Key)) { + index = counter[tabData.Key]; + } else { + index = 0; + } + captureIETabItem.Tag = new KeyValuePair(tabData.Key, index++); + captureIETabItem.Click += new System.EventHandler(Contextmenu_captureIE_Click); + this.contextmenu_captureie.DropDownItems.Add(captureIETabItem); + if (counter.ContainsKey(tabData.Key)) { + counter[tabData.Key] = index; + } else { + counter.Add(tabData.Key, index); + } } - captureIETabItem.Tag = new KeyValuePair(tabData.Key, index++); - captureIETabItem.Click += new System.EventHandler(Contextmenu_captureIE_Click); - this.contextmenu_captureie.DropDownItems.Add(captureIETabItem); - if (counter.ContainsKey(tabData.Key)) { - counter[tabData.Key] = index; - } else { - counter.Add(tabData.Key, index); - } + } else { + this.contextmenu_captureie.Enabled = false; } - } else { - this.contextmenu_captureie.Enabled = false; + } catch (Exception ex) { + LOG.WarnFormat("Problem accessing IE information: {0}", ex.Message); } } - + /// /// Build a selectable list of windows when we enter the menu item /// - void EnterCaptureWindowMenuItem(object sender, EventArgs e) { + private void CaptureWindowMenuDropDownOpening(object sender, EventArgs e) { // The Capture window context menu item used to go to the following code: // captureForm.MakeCapture(CaptureMode.Window, false); // Now we check which windows are there to capture @@ -614,46 +667,146 @@ namespace Greenshot { AddCaptureWindowMenuItems(captureWindowMenuItem, Contextmenu_window_Click); } - public static void AddCaptureWindowMenuItems(ToolStripMenuItem menuItem, EventHandler eventHandler) { + private void CaptureWindowMenuDropDownClosed(object sender, EventArgs e) { + cleanupThumbnail(); + } + + private void ShowThumbnailOnEnter(object sender, EventArgs e) { + ToolStripMenuItem captureWindowItem = sender as ToolStripMenuItem; + WindowDetails window = captureWindowItem.Tag as WindowDetails; + parentMenuBounds = captureWindowItem.GetCurrentParent().TopLevelControl.Bounds; + if (thumbnailForm == null) { + thumbnailForm = new FormWithoutActivation(); + thumbnailForm.ShowInTaskbar = false; + thumbnailForm.FormBorderStyle = FormBorderStyle.None; + thumbnailForm.TopMost = false; + thumbnailForm.Enabled = false; + if (conf.WindowCaptureMode == WindowCaptureMode.Auto || conf.WindowCaptureMode == WindowCaptureMode.Aero) { + thumbnailForm.BackColor = Color.FromArgb(255, conf.DWMBackgroundColor.R, conf.DWMBackgroundColor.G, conf.DWMBackgroundColor.B); + } else { + thumbnailForm.BackColor = Color.White; + } + } + if (thumbnailHandle != IntPtr.Zero) { + DWM.DwmUnregisterThumbnail(thumbnailHandle); + thumbnailHandle = IntPtr.Zero; + } + DWM.DwmRegisterThumbnail(thumbnailForm.Handle, window.Handle, out thumbnailHandle); + if (thumbnailHandle != IntPtr.Zero) { + Rectangle windowRectangle = window.WindowRectangle; + int thumbnailHeight = 200; + int thumbnailWidth = (int)(thumbnailHeight * ((float)windowRectangle.Width / (float)windowRectangle.Height)); + if (thumbnailWidth > parentMenuBounds.Width) { + thumbnailWidth = parentMenuBounds.Width; + thumbnailHeight = (int)(thumbnailWidth * ((float)windowRectangle.Height / (float)windowRectangle.Width)); + } + thumbnailForm.Width = thumbnailWidth; + thumbnailForm.Height = thumbnailHeight; + // Prepare the displaying of the Thumbnail + DWM_THUMBNAIL_PROPERTIES props = new DWM_THUMBNAIL_PROPERTIES(); + props.Opacity = (byte)255; + props.Visible = true; + props.SourceClientAreaOnly = false; + props.Destination = new RECT(0, 0, thumbnailWidth, thumbnailHeight); + DWM.DwmUpdateThumbnailProperties(thumbnailHandle, ref props); + if (!thumbnailForm.Visible) { + thumbnailForm.Show(); + } + // Make sure it's on "top"! + User32.SetWindowPos(thumbnailForm.Handle,captureWindowItem.GetCurrentParent().TopLevelControl.Handle, 0,0,0,0, WindowPos.SWP_NOMOVE | WindowPos.SWP_NOSIZE | WindowPos.SWP_NOACTIVATE); + + // Align to menu + Rectangle screenBounds = WindowCapture.GetScreenBounds(); + if (screenBounds.Contains(parentMenuBounds.Left, parentMenuBounds.Top - thumbnailHeight)) { + thumbnailForm.Location = new Point(parentMenuBounds.Left + (parentMenuBounds.Width/2) - (thumbnailWidth/2), parentMenuBounds.Top - thumbnailHeight); + } else { + thumbnailForm.Location = new Point(parentMenuBounds.Left + (parentMenuBounds.Width/2) - (thumbnailWidth/2), parentMenuBounds.Bottom); + } + } + } + + private void HideThumbnailOnLeave(object sender, EventArgs e) { + hideThumbnail(); + } + + private void hideThumbnail() { + if (thumbnailHandle != IntPtr.Zero) { + DWM.DwmUnregisterThumbnail(thumbnailHandle); + thumbnailHandle = IntPtr.Zero; + thumbnailForm.Hide(); + } + } + + private void cleanupThumbnail() { + hideThumbnail(); + + if (thumbnailForm != null) { + thumbnailForm.Close(); + thumbnailForm = null; + } + } + + public void AddCaptureWindowMenuItems(ToolStripMenuItem menuItem, EventHandler eventHandler) { ILanguage lang = Language.GetInstance(); menuItem.DropDownItems.Clear(); + // check if thumbnailPreview is enabled and DWM is enabled + bool thumbnailPreview = conf.ThumnailPreview && DWM.isDWMEnabled(); + List windows = WindowDetails.GetVisibleWindows(); foreach(WindowDetails window in windows) { ToolStripMenuItem captureWindowItem = new ToolStripMenuItem(window.Text); captureWindowItem.Tag = window; + captureWindowItem.Image = window.DisplayIcon; captureWindowItem.Click += new System.EventHandler(eventHandler); + // Only show preview when enabled + if (thumbnailPreview) { + captureWindowItem.MouseEnter += new System.EventHandler(ShowThumbnailOnEnter); + captureWindowItem.MouseLeave += new System.EventHandler(HideThumbnailOnLeave); + } menuItem.DropDownItems.Add(captureWindowItem); } } void CaptureAreaToolStripMenuItemClick(object sender, EventArgs e) { - captureForm.MakeCapture(CaptureMode.Region, false); + BeginInvoke((MethodInvoker)delegate { + CaptureHelper.CaptureRegion(false); + }); } void CaptureClipboardToolStripMenuItemClick(object sender, EventArgs e) { - CaptureClipboard(); + BeginInvoke((MethodInvoker)delegate { + CaptureHelper.CaptureClipboard(); + }); } void OpenFileToolStripMenuItemClick(object sender, EventArgs e) { - CaptureFile(); + BeginInvoke((MethodInvoker)delegate { + CaptureFile(); + }); } void CaptureFullScreenToolStripMenuItemClick(object sender, EventArgs e) { - captureForm.MakeCapture(CaptureMode.FullScreen, false); + BeginInvoke((MethodInvoker)delegate { + CaptureHelper.CaptureFullscreen(false); + }); } void Contextmenu_capturelastregionClick(object sender, EventArgs e) { - captureForm.MakeCapture(CaptureMode.LastRegion, false); + BeginInvoke((MethodInvoker)delegate { + CaptureHelper.CaptureLastRegion(false); + }); } void Contextmenu_window_Click(object sender,EventArgs e) { ToolStripMenuItem clickedItem = (ToolStripMenuItem)sender; - try { - WindowDetails windowToCapture = (WindowDetails)clickedItem.Tag; - captureForm.MakeCapture(windowToCapture); - } catch (Exception exception) { - LOG.Error(exception); - } + BeginInvoke((MethodInvoker)delegate { + try { + WindowDetails windowToCapture = (WindowDetails)clickedItem.Tag; + CaptureHelper.CaptureWindow(windowToCapture); + } catch (Exception exception) { + LOG.Error(exception); + } + }); } void Contextmenu_captureIE_Click(object sender, EventArgs e) { @@ -663,109 +816,187 @@ namespace Greenshot { } ToolStripMenuItem clickedItem = (ToolStripMenuItem)sender; KeyValuePair tabData = (KeyValuePair)clickedItem.Tag; - try { - IECaptureHelper.ActivateIETab(tabData.Key, tabData.Value); - } catch (Exception exception) { - LOG.Error(exception); - } - try { - captureForm.MakeCapture(CaptureMode.IE, false); - } catch (Exception exception) { - LOG.Error(exception); - } + BeginInvoke((MethodInvoker)delegate { + try { + IECaptureHelper.ActivateIETab(tabData.Key, tabData.Value); + } catch (Exception exception) { + LOG.Error(exception); + } + try { + CaptureHelper.CaptureIE(false); + } catch (Exception exception) { + LOG.Error(exception); + } + }); } void Contextmenu_donateClick(object sender, EventArgs e) { - Process.Start("http://getgreenshot.org/support/"); + BeginInvoke((MethodInvoker)delegate { + Process.Start("http://getgreenshot.org/support/"); + }); } void Contextmenu_settingsClick(object sender, EventArgs e) { - SettingsForm settings = new SettingsForm(); - settings.ShowDialog(); - InitializeQuickSettingsMenu(); - this.Hide(); + BeginInvoke((MethodInvoker)delegate { + ShowSetting(); + }); + } + + public void ShowSetting() { + if (settingsForm != null) { + WindowDetails.ToForeground(settingsForm.Handle); + } else { + try { + using (settingsForm = new SettingsForm()) { + if (settingsForm.ShowDialog() == DialogResult.OK) { + InitializeQuickSettingsMenu(); + } + } + } finally { + settingsForm = null; + } + } } void Contextmenu_aboutClick(object sender, EventArgs e) { - new AboutForm().Show(); + if (aboutForm != null) { + WindowDetails.ToForeground(aboutForm.Handle); + } else { + try { + using (aboutForm = new AboutForm()) { + aboutForm.ShowDialog(); + } + } finally { + aboutForm = null; + } + } } void Contextmenu_helpClick(object sender, EventArgs e) { - HelpBrowserForm hpf = new HelpBrowserForm(conf.Language); - hpf.Show(); + if (helpBrowserForm != null) { + WindowDetails.ToForeground(helpBrowserForm.Handle); + } else { + try { + using (helpBrowserForm = new HelpBrowserForm(conf.Language)) { + helpBrowserForm.ShowDialog(); + } + } finally { + helpBrowserForm = null; + } + } } void Contextmenu_exitClick(object sender, EventArgs e) { - exit(); + Exit(); } private void InitializeQuickSettingsMenu() { this.contextmenu_quicksettings.DropDownItems.Clear(); // screenshot destination - ToolStripMenuSelectList selectList = new ToolStripMenuSelectList("destination",true); + ToolStripMenuSelectList selectList = new ToolStripMenuSelectList("destinations",true); selectList.Text = lang.GetString(LangKey.settings_destination); - selectList.AddItem(lang.GetString(LangKey.settings_destination_editor), Destination.Editor, conf.OutputDestinations.Contains(Destination.Editor)); - selectList.AddItem(lang.GetString(LangKey.settings_destination_clipboard), Destination.Clipboard, conf.OutputDestinations.Contains(Destination.Clipboard)); - selectList.AddItem(lang.GetString(LangKey.quicksettings_destination_file), Destination.FileDefault, conf.OutputDestinations.Contains(Destination.FileDefault)); - selectList.AddItem(lang.GetString(LangKey.settings_destination_fileas), Destination.FileWithDialog, conf.OutputDestinations.Contains(Destination.FileWithDialog)); - selectList.AddItem(lang.GetString(LangKey.settings_destination_printer), Destination.Printer, conf.OutputDestinations.Contains(Destination.Printer)); - selectList.AddItem(lang.GetString(LangKey.settings_destination_email), Destination.EMail, conf.OutputDestinations.Contains(Destination.EMail)); - selectList.CheckedChanged += new EventHandler(this.QuickSettingItemChanged); + // Working with IDestination: + foreach(IDestination destination in DestinationHelper.GetAllDestinations()) { + selectList.AddItem(destination.Description, destination, conf.OutputDestinations.Contains(destination.Designation)); + } + selectList.CheckedChanged += new EventHandler(this.QuickSettingDestinationChanged); this.contextmenu_quicksettings.DropDownItems.Add(selectList); + + // Capture Modes + selectList = new ToolStripMenuSelectList("capturemodes", false); + selectList.Text = lang.GetString(LangKey.settings_window_capture_mode); + string enumTypeName = typeof(WindowCaptureMode).Name; + foreach(WindowCaptureMode captureMode in Enum.GetValues(typeof(WindowCaptureMode))) { + selectList.AddItem(lang.GetString(enumTypeName + "." + captureMode.ToString()), captureMode, conf.WindowCaptureMode == captureMode); + } + selectList.CheckedChanged += new EventHandler(this.QuickSettingCaptureModeChanged); + this.contextmenu_quicksettings.DropDownItems.Add(selectList); + // print options selectList = new ToolStripMenuSelectList("printoptions",true); selectList.Text = lang.GetString(LangKey.settings_printoptions); - selectList.AddItem(lang.GetString(LangKey.printoptions_allowshrink), "AllowPrintShrink", conf.OutputPrintAllowShrink); - selectList.AddItem(lang.GetString(LangKey.printoptions_allowenlarge), "AllowPrintEnlarge", conf.OutputPrintAllowEnlarge); - selectList.AddItem(lang.GetString(LangKey.printoptions_allowrotate), "AllowPrintRotate", conf.OutputPrintAllowRotate); - selectList.AddItem(lang.GetString(LangKey.printoptions_allowcenter), "AllowPrintCenter", conf.OutputPrintCenter); - selectList.CheckedChanged += new EventHandler(this.QuickSettingItemChanged); + + IniValue iniValue; + foreach(string propertyName in conf.Values.Keys) { + if (propertyName.StartsWith("OutputPrint")) { + iniValue = conf.Values[propertyName]; + selectList.AddItem(lang.GetString(iniValue.Attributes.LanguageKey), iniValue, (bool)iniValue.Value); + } + } + selectList.CheckedChanged += new EventHandler(this.QuickSettingBoolItemChanged); this.contextmenu_quicksettings.DropDownItems.Add(selectList); + // effects selectList = new ToolStripMenuSelectList("effects",true); selectList.Text = lang.GetString(LangKey.settings_visualization); - selectList.AddItem(lang.GetString(LangKey.settings_playsound), "PlaySound", conf.PlayCameraSound); - selectList.CheckedChanged += new EventHandler(this.QuickSettingItemChanged); + + iniValue = conf.Values["PlayCameraSound"]; + selectList.AddItem(lang.GetString(iniValue.Attributes.LanguageKey), iniValue, (bool)iniValue.Value); + iniValue = conf.Values["ShowTrayNotification"]; + selectList.AddItem(lang.GetString(iniValue.Attributes.LanguageKey), iniValue, (bool)iniValue.Value); + selectList.CheckedChanged += new EventHandler(this.QuickSettingBoolItemChanged); this.contextmenu_quicksettings.DropDownItems.Add(selectList); } - void QuickSettingItemChanged(object sender, EventArgs e) { - ToolStripMenuSelectList selectList = (ToolStripMenuSelectList)sender; + void QuickSettingCaptureModeChanged(object sender, EventArgs e) { ToolStripMenuSelectListItem item = ((ItemCheckedChangedEventArgs)e).Item; - if(selectList.Identifier.Equals("destination")) { - Destination selectedDestination = (Destination)item.Data; - if (item.Checked && !conf.OutputDestinations.Contains(selectedDestination)) { - conf.OutputDestinations.Add(selectedDestination); - } - if (!item.Checked && conf.OutputDestinations.Contains(selectedDestination)) { - conf.OutputDestinations.Remove(selectedDestination); - } - IniConfig.Save(); - } else if(selectList.Identifier.Equals("printoptions")) { - if(item.Data.Equals("AllowPrintShrink")) conf.OutputPrintAllowShrink = item.Checked; - else if(item.Data.Equals("AllowPrintEnlarge")) conf.OutputPrintAllowEnlarge = item.Checked; - else if(item.Data.Equals("AllowPrintRotate")) conf.OutputPrintAllowRotate = item.Checked; - else if(item.Data.Equals("AllowPrintCenter")) conf.OutputPrintCenter = item.Checked; - IniConfig.Save(); - } else if(selectList.Identifier.Equals("effects")) { - if(item.Data.Equals("PlaySound")) { - conf.PlayCameraSound = item.Checked; - } - IniConfig.Save(); - + WindowCaptureMode windowsCaptureMode = (WindowCaptureMode)item.Data; + if (item.Checked) { + conf.WindowCaptureMode = windowsCaptureMode; } } + + void QuickSettingBoolItemChanged(object sender, EventArgs e) { + ToolStripMenuSelectListItem item = ((ItemCheckedChangedEventArgs)e).Item; + IniValue iniValue = item.Data as IniValue; + if (iniValue != null) { + iniValue.Value = item.Checked; + IniConfig.Save(); + } + } + + void QuickSettingDestinationChanged(object sender, EventArgs e) { + ToolStripMenuSelectListItem item = ((ItemCheckedChangedEventArgs)e).Item; + IDestination selectedDestination = (IDestination)item.Data; + if (item.Checked && selectedDestination.Designation.Equals("Picker")) { + foreach(ToolStripMenuSelectList ddi in contextmenu_quicksettings.DropDownItems) { + if (ddi.Identifier.Equals("destinations")) { + foreach(ToolStripMenuSelectListItem dropDownItem in ddi.DropDownItems) { + IDestination destination = dropDownItem.Data as IDestination; + if (!destination.Designation.Equals("Picker")) { + if (dropDownItem.CheckState == CheckState.Checked) { + dropDownItem.CheckState = CheckState.Unchecked; + } + } + } + + } + } + conf.OutputDestinations.Clear(); + conf.OutputDestinations.Add(selectedDestination.Designation); + } else { + if (item.Checked && !conf.OutputDestinations.Contains(selectedDestination.Designation)) { + conf.OutputDestinations.Add(selectedDestination.Designation); + } + if (!item.Checked && conf.OutputDestinations.Contains(selectedDestination.Designation)) { + conf.OutputDestinations.Remove(selectedDestination.Designation); + } + } + IniConfig.Save(); + } #endregion private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { - string exceptionText = EnvironmentInfo.BuildReport(e.ExceptionObject as Exception); - LOG.Error(exceptionText); + Exception exceptionToLog = e.ExceptionObject as Exception; + string exceptionText = EnvironmentInfo.BuildReport(exceptionToLog); + LOG.Error(EnvironmentInfo.ExceptionToString(exceptionToLog)); new BugReportForm(exceptionText).ShowDialog(); } private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) { - string exceptionText = EnvironmentInfo.BuildReport(e.Exception); - LOG.Error(exceptionText); + Exception exceptionToLog = e.Exception; + string exceptionText = EnvironmentInfo.BuildReport(exceptionToLog); + LOG.Error(EnvironmentInfo.ExceptionToString(exceptionToLog)); new BugReportForm(exceptionText).ShowDialog(); } @@ -779,7 +1010,7 @@ namespace Greenshot { /// private void Contextmenu_OpenRecent(object sender, EventArgs eventArgs) { string path; - string configPath = FilenameHelper.FillVariables(conf.OutputFilePath); + string configPath = FilenameHelper.FillVariables(conf.OutputFilePath, false); string lastFilePath = Path.GetDirectoryName(conf.OutputFileAsFullpath); if (Directory.Exists(lastFilePath)) { path = lastFilePath; @@ -802,9 +1033,7 @@ namespace Greenshot { /// /// Shutdown / cleanup /// - public void exit() { - ClipboardHelper.DeregisterClipboardViewer(this.Handle); - + public void Exit() { LOG.Info("Exit: " + EnvironmentInfo.EnvironmentToString(false)); // Close all open forms (except this), use a separate List to make sure we don't get a "InvalidOperationException: Collection was modified" @@ -852,6 +1081,8 @@ namespace Greenshot { LOG.Error("Error closing application!", e); } + ImageOutput.RemoveTmpFiles(); + // Store any open configuration changes try { IniConfig.Save(); @@ -876,9 +1107,8 @@ namespace Greenshot { /// /// private void BackgroundWorkerTimerTick(object sender, EventArgs e) { - LOG.Debug("BackgroundWorkerTimerTick"); - if (UpdateHelper.IsUpdateCheckNeeded()) { + LOG.Debug("BackgroundWorkerTimerTick checking for update"); // Start update check in the background Thread backgroundTask = new Thread (new ThreadStart(UpdateHelper.CheckAndAskForUpdate)); backgroundTask.IsBackground = true; diff --git a/Greenshot/Forms/PrintOptionsDialog.cs b/Greenshot/Forms/PrintOptionsDialog.cs index 714504a1e..d2b8cd6e1 100644 --- a/Greenshot/Forms/PrintOptionsDialog.cs +++ b/Greenshot/Forms/PrintOptionsDialog.cs @@ -19,11 +19,10 @@ * along with this program. If not, see . */ using System; -using System.Drawing; using System.Windows.Forms; - using Greenshot.Configuration; using GreenshotPlugin.Core; +using IniFile; namespace Greenshot.Forms { /// diff --git a/Greenshot/Forms/SaveImageFileDialog.cs b/Greenshot/Forms/SaveImageFileDialog.cs index 4d59b0173..98252c73c 100644 --- a/Greenshot/Forms/SaveImageFileDialog.cs +++ b/Greenshot/Forms/SaveImageFileDialog.cs @@ -19,17 +19,13 @@ * along with this program. If not, see . */ using System; -using System.Collections; -using System.Drawing; using System.IO; -using System.Reflection; -using System.Text.RegularExpressions; using System.Windows.Forms; -using Greenshot.Configuration; using Greenshot.Helpers; using Greenshot.Plugin; using GreenshotPlugin.Core; +using IniFile; namespace Greenshot.Forms { /// @@ -168,7 +164,7 @@ namespace Greenshot.Forms { private string GetRootDirFromConfig() { string rootDir = conf.OutputFilePath; - rootDir = FilenameHelper.FillVariables(rootDir); + rootDir = FilenameHelper.FillVariables(rootDir, false); return rootDir; } @@ -178,10 +174,14 @@ namespace Greenshot.Forms { } private void CleanUp() { - if(eagerlyCreatedDirectory!=null - && eagerlyCreatedDirectory.GetFiles().Length==0 - && eagerlyCreatedDirectory.GetDirectories().Length==0) { - eagerlyCreatedDirectory.Delete(); + // fix for bug #3379053 + try { + if(eagerlyCreatedDirectory != null && eagerlyCreatedDirectory.GetFiles().Length == 0 && eagerlyCreatedDirectory.GetDirectories().Length == 0) { + eagerlyCreatedDirectory.Delete(); + eagerlyCreatedDirectory = null; + } + } catch (Exception e) { + LOG.WarnFormat("Couldn't cleanup directory due to: {0}", e.Message); eagerlyCreatedDirectory = null; } } diff --git a/Greenshot/Forms/SettingsForm.Designer.cs b/Greenshot/Forms/SettingsForm.Designer.cs index 4bcad39b8..6eacc5f1e 100644 --- a/Greenshot/Forms/SettingsForm.Designer.cs +++ b/Greenshot/Forms/SettingsForm.Designer.cs @@ -64,19 +64,13 @@ namespace Greenshot { this.checkbox_copypathtoclipboard = new System.Windows.Forms.CheckBox(); this.groupbox_applicationsettings = new System.Windows.Forms.GroupBox(); this.checkbox_autostartshortcut = new System.Windows.Forms.CheckBox(); - this.checkbox_editor = new System.Windows.Forms.CheckBox(); this.groupbox_jpegsettings = new System.Windows.Forms.GroupBox(); this.checkbox_alwaysshowjpegqualitydialog = new System.Windows.Forms.CheckBox(); this.label_jpegquality = new System.Windows.Forms.Label(); this.textBoxJpegQuality = new System.Windows.Forms.TextBox(); this.trackBarJpegQuality = new System.Windows.Forms.TrackBar(); - this.checkbox_clipboard = new System.Windows.Forms.CheckBox(); - this.checkbox_file = new System.Windows.Forms.CheckBox(); - this.checkbox_printer = new System.Windows.Forms.CheckBox(); this.groupbox_destination = new System.Windows.Forms.GroupBox(); - this.combobox_emailformat = new System.Windows.Forms.ComboBox(); - this.checkbox_email = new System.Windows.Forms.CheckBox(); - this.checkbox_fileas = new System.Windows.Forms.CheckBox(); + this.checkedDestinationsListBox = new System.Windows.Forms.CheckedListBox(); this.tabcontrol = new System.Windows.Forms.TabControl(); this.tab_general = new System.Windows.Forms.TabPage(); this.groupbox_network = new System.Windows.Forms.GroupBox(); @@ -299,17 +293,6 @@ namespace Greenshot { this.checkbox_autostartshortcut.Text = "Launch Greenshot on startup"; this.checkbox_autostartshortcut.UseVisualStyleBackColor = true; // - // checkbox_editor - // - this.checkbox_editor.CheckAlign = System.Drawing.ContentAlignment.TopLeft; - this.checkbox_editor.Location = new System.Drawing.Point(12, 19); - this.checkbox_editor.Name = "checkbox_editor"; - this.checkbox_editor.Size = new System.Drawing.Size(158, 24); - this.checkbox_editor.TabIndex = 14; - this.checkbox_editor.Text = "Open in editor"; - this.checkbox_editor.TextAlign = System.Drawing.ContentAlignment.TopLeft; - this.checkbox_editor.UseVisualStyleBackColor = true; - // // groupbox_jpegsettings // this.groupbox_jpegsettings.Controls.Add(this.checkbox_alwaysshowjpegqualitydialog); @@ -360,48 +343,9 @@ namespace Greenshot { this.trackBarJpegQuality.TickFrequency = 10; this.trackBarJpegQuality.Scroll += new System.EventHandler(this.TrackBarJpegQualityScroll); // - // checkbox_clipboard - // - this.checkbox_clipboard.CheckAlign = System.Drawing.ContentAlignment.TopLeft; - this.checkbox_clipboard.Location = new System.Drawing.Point(12, 41); - this.checkbox_clipboard.Name = "checkbox_clipboard"; - this.checkbox_clipboard.Size = new System.Drawing.Size(158, 24); - this.checkbox_clipboard.TabIndex = 15; - this.checkbox_clipboard.Text = "Copy to clipboard"; - this.checkbox_clipboard.TextAlign = System.Drawing.ContentAlignment.TopLeft; - this.checkbox_clipboard.UseVisualStyleBackColor = true; - // - // checkbox_file - // - this.checkbox_file.CheckAlign = System.Drawing.ContentAlignment.TopLeft; - this.checkbox_file.Location = new System.Drawing.Point(176, 42); - this.checkbox_file.Name = "checkbox_file"; - this.checkbox_file.Size = new System.Drawing.Size(230, 23); - this.checkbox_file.TabIndex = 16; - this.checkbox_file.Text = "Sofort speichern (mit nachstehend angegebenen Einstellungen)"; - this.checkbox_file.TextAlign = System.Drawing.ContentAlignment.TopLeft; - this.checkbox_file.UseVisualStyleBackColor = true; - // - // checkbox_printer - // - this.checkbox_printer.CheckAlign = System.Drawing.ContentAlignment.TopLeft; - this.checkbox_printer.Location = new System.Drawing.Point(12, 63); - this.checkbox_printer.Name = "checkbox_printer"; - this.checkbox_printer.Size = new System.Drawing.Size(158, 24); - this.checkbox_printer.TabIndex = 17; - this.checkbox_printer.Text = "Send to printer"; - this.checkbox_printer.TextAlign = System.Drawing.ContentAlignment.TopLeft; - this.checkbox_printer.UseVisualStyleBackColor = true; - // // groupbox_destination // - this.groupbox_destination.Controls.Add(this.combobox_emailformat); - this.groupbox_destination.Controls.Add(this.checkbox_email); - this.groupbox_destination.Controls.Add(this.checkbox_fileas); - this.groupbox_destination.Controls.Add(this.checkbox_printer); - this.groupbox_destination.Controls.Add(this.checkbox_editor); - this.groupbox_destination.Controls.Add(this.checkbox_file); - this.groupbox_destination.Controls.Add(this.checkbox_clipboard); + this.groupbox_destination.Controls.Add(this.checkedDestinationsListBox); this.groupbox_destination.Location = new System.Drawing.Point(2, 6); this.groupbox_destination.Name = "groupbox_destination"; this.groupbox_destination.Size = new System.Drawing.Size(412, 94); @@ -409,36 +353,15 @@ namespace Greenshot { this.groupbox_destination.TabStop = false; this.groupbox_destination.Text = "Screenshot Destination"; // - // combobox_emailformat + // checkedDestinationsListBox // - this.combobox_emailformat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.combobox_emailformat.FormattingEnabled = true; - this.combobox_emailformat.Location = new System.Drawing.Point(312, 61); - this.combobox_emailformat.Name = "combobox_emailformat"; - this.combobox_emailformat.Size = new System.Drawing.Size(94, 21); - this.combobox_emailformat.TabIndex = 20; - // - // checkbox_email - // - this.checkbox_email.CheckAlign = System.Drawing.ContentAlignment.TopLeft; - this.checkbox_email.Location = new System.Drawing.Point(176, 63); - this.checkbox_email.Name = "checkbox_email"; - this.checkbox_email.Size = new System.Drawing.Size(230, 23); - this.checkbox_email.TabIndex = 19; - this.checkbox_email.Text = "Email"; - this.checkbox_email.TextAlign = System.Drawing.ContentAlignment.TopLeft; - this.checkbox_email.UseVisualStyleBackColor = true; - // - // checkbox_fileas - // - this.checkbox_fileas.CheckAlign = System.Drawing.ContentAlignment.TopLeft; - this.checkbox_fileas.Location = new System.Drawing.Point(176, 19); - this.checkbox_fileas.Name = "checkbox_fileas"; - this.checkbox_fileas.Size = new System.Drawing.Size(230, 24); - this.checkbox_fileas.TabIndex = 18; - this.checkbox_fileas.Text = "Save as (displaying dialog)"; - this.checkbox_fileas.TextAlign = System.Drawing.ContentAlignment.TopLeft; - this.checkbox_fileas.UseVisualStyleBackColor = true; + this.checkedDestinationsListBox.FormattingEnabled = true; + this.checkedDestinationsListBox.Location = new System.Drawing.Point(5, 20); + this.checkedDestinationsListBox.Name = "checkedDestinationsListBox"; + this.checkedDestinationsListBox.ScrollAlwaysVisible = true; + this.checkedDestinationsListBox.Size = new System.Drawing.Size(401, 64); + this.checkedDestinationsListBox.TabIndex = 0; + this.checkedDestinationsListBox.SelectedValueChanged += new System.EventHandler(this.DestinationsCheckStateChanged); // // tabcontrol // @@ -639,7 +562,7 @@ namespace Greenshot { // this.checkbox_editor_match_capture_size.Location = new System.Drawing.Point(6, 19); this.checkbox_editor_match_capture_size.Name = "checkbox_editor_match_capture_size"; - this.checkbox_editor_match_capture_size.Size = new System.Drawing.Size(213, 24); + this.checkbox_editor_match_capture_size.Size = new System.Drawing.Size(397, 24); this.checkbox_editor_match_capture_size.TabIndex = 26; this.checkbox_editor_match_capture_size.Text = "Match capture size"; this.checkbox_editor_match_capture_size.UseVisualStyleBackColor = true; @@ -989,13 +912,13 @@ namespace Greenshot { this.groupbox_plugins.PerformLayout(); this.ResumeLayout(false); } + private System.Windows.Forms.CheckedListBox checkedDestinationsListBox; private System.Windows.Forms.GroupBox groupbox_editor; private System.Windows.Forms.CheckBox checkbox_editor_match_capture_size; private System.Windows.Forms.NumericUpDown numericUpDown_daysbetweencheck; private System.Windows.Forms.GroupBox groupbox_network; private System.Windows.Forms.CheckBox checkbox_usedefaultproxy; private System.Windows.Forms.Label label_checkperiod; - private System.Windows.Forms.ComboBox combobox_emailformat; private GreenshotPlugin.Controls.HotkeyControl fullscreen_hotkeyControl; private GreenshotPlugin.Controls.HotkeyControl window_hotkeyControl; private GreenshotPlugin.Controls.HotkeyControl region_hotkeyControl; @@ -1018,7 +941,6 @@ namespace Greenshot { private System.Windows.Forms.ComboBox combobox_window_capture_mode; private System.Windows.Forms.NumericUpDown numericUpDownWaitTime; private System.Windows.Forms.Label label_waittime; - private System.Windows.Forms.CheckBox checkbox_email; private System.Windows.Forms.CheckBox checkbox_capture_windows_interactive; private System.Windows.Forms.CheckBox checkbox_capture_mousepointer; private System.Windows.Forms.TabPage tab_printer; @@ -1027,7 +949,6 @@ namespace Greenshot { private System.Windows.Forms.GroupBox groupbox_plugins; private System.Windows.Forms.TabPage tab_plugins; private System.Windows.Forms.CheckBox checkboxTimestamp; - private System.Windows.Forms.CheckBox checkbox_fileas; private System.Windows.Forms.Button btnPatternHelp; private System.Windows.Forms.CheckBox checkbox_copypathtoclipboard; private System.Windows.Forms.CheckBox checkboxAllowShrink; @@ -1041,10 +962,6 @@ namespace Greenshot { private System.Windows.Forms.TabControl tabcontrol; private System.Windows.Forms.CheckBox checkbox_autostartshortcut; private System.Windows.Forms.GroupBox groupbox_destination; - private System.Windows.Forms.CheckBox checkbox_editor; - private System.Windows.Forms.CheckBox checkbox_clipboard; - private System.Windows.Forms.CheckBox checkbox_file; - private System.Windows.Forms.CheckBox checkbox_printer; private System.Windows.Forms.CheckBox checkbox_alwaysshowjpegqualitydialog; private System.Windows.Forms.TextBox textBoxJpegQuality; private System.Windows.Forms.Label label_jpegquality; diff --git a/Greenshot/Forms/SettingsForm.cs b/Greenshot/Forms/SettingsForm.cs index 718523b04..fd8999496 100644 --- a/Greenshot/Forms/SettingsForm.cs +++ b/Greenshot/Forms/SettingsForm.cs @@ -21,18 +21,16 @@ using System; using System.Collections.Generic; using System.Drawing; -using System.Globalization; using System.IO; -using System.Threading; using System.Windows.Forms; using Greenshot.Configuration; using Greenshot.Helpers; -using Greenshot.Helpers.OfficeInterop; -using Greenshot.Plugin; -using Greenshot.UnmanagedHelpers; using GreenshotPlugin.Controls; using GreenshotPlugin.Core; +using GreenshotPlugin.UnmanagedHelpers; +using Greenshot.Plugin; +using IniFile; namespace Greenshot { /// @@ -42,7 +40,7 @@ namespace Greenshot { private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(SettingsForm)); private static CoreConfiguration coreConfiguration = IniConfig.GetIniSection(); private static EditorConfiguration editorConfiguration = IniConfig.GetIniSection(); - ILanguage lang; + private ILanguage lang; private ToolTip toolTip; public SettingsForm() { @@ -60,17 +58,95 @@ namespace Greenshot { toolTip = new ToolTip(); AddPluginTab(); this.combobox_primaryimageformat.Items.AddRange(new object[]{OutputFormat.bmp, OutputFormat.gif, OutputFormat.jpg, OutputFormat.png, OutputFormat.tiff}); - this.combobox_emailformat.Items.AddRange(new object[]{EmailFormat.TXT, EmailFormat.HTML}); - this.combobox_window_capture_mode.Items.AddRange(new object[]{WindowCaptureMode.Auto, WindowCaptureMode.Screen, WindowCaptureMode.GDI}); - if (DWM.isDWMEnabled()) { - this.combobox_window_capture_mode.Items.Add(WindowCaptureMode.Aero); - this.combobox_window_capture_mode.Items.Add(WindowCaptureMode.AeroTransparent); - } UpdateUI(); DisplaySettings(); CheckSettings(); } + /// + /// This is a method to popululate the ComboBox + /// with the items from the enumeration + /// + /// ComboBox to populate + /// Enum to populate with + private void PopulateComboBox(ComboBox comboBox) { + ET[] availableValues = (ET[])Enum.GetValues(typeof(ET)); + PopulateComboBox(comboBox, availableValues, availableValues[0]); + } + + /// + /// This is a method to popululate the ComboBox + /// with the items from the enumeration + /// + /// ComboBox to populate + /// Enum to populate with + private void PopulateComboBox(ComboBox comboBox, ET[] availableValues, ET selectedValue) { + comboBox.Items.Clear(); + string enumTypeName = typeof(ET).Name; + foreach(ET enumValue in availableValues) { + string translation = lang.GetString(enumTypeName + "." + enumValue.ToString()); + comboBox.Items.Add(translation); + } + comboBox.SelectedItem = lang.GetString(enumTypeName + "." + selectedValue.ToString()); + } + + + /// + /// Get the selected enum value from the combobox, uses generics + /// + /// Combobox to get the value from + /// The generics value of the combobox + private ET GetSelected(ComboBox comboBox) { + string enumTypeName = typeof(ET).Name; + string selectedValue = comboBox.SelectedItem as string; + ET[] availableValues = (ET[])Enum.GetValues(typeof(ET)); + ET returnValue = availableValues[0]; + foreach(ET enumValue in availableValues) { + string translation = lang.GetString(enumTypeName + "." + enumValue.ToString()); + if (translation.Equals(selectedValue)) { + returnValue = enumValue; + break; + } + } + return returnValue; + } + + private void SetEmailFormat(EmailFormat selectedEmailFormat) { + // TODO: Fix!! + // Setup the email settings + EmailFormat [] availableValues; + if (EmailConfigHelper.HasMAPI()) { + //checkbox_email.Enabled = true; + //combobox_emailformat.Visible = true; + if (EmailConfigHelper.HasOutlook()) { + availableValues = new EmailFormat[]{EmailFormat.MAPI, EmailFormat.OUTLOOK_TXT, EmailFormat.OUTLOOK_HTML}; + } else { + // Force MAPI in configuration if no Outlook + coreConfiguration.OutputEMailFormat = EmailFormat.MAPI; + availableValues = new EmailFormat[]{EmailFormat.MAPI}; + } + //PopulateComboBox(combobox_emailformat, availableValues, selectedEmailFormat); + } else { + //checkbox_email.Enabled = false; + //checkbox_email.Checked = false; + //combobox_emailformat.Visible = false; + } + } + + private void SetWindowCaptureMode(WindowCaptureMode selectedWindowCaptureMode) { + WindowCaptureMode[] availableModes; + if (!DWM.isDWMEnabled()) { + // Remove DWM from configuration, as DWM is disabled! + if (coreConfiguration.WindowCaptureMode == WindowCaptureMode.Aero || coreConfiguration.WindowCaptureMode == WindowCaptureMode.AeroTransparent) { + coreConfiguration.WindowCaptureMode = WindowCaptureMode.GDI; + } + availableModes = new WindowCaptureMode[]{WindowCaptureMode.Auto, WindowCaptureMode.Screen, WindowCaptureMode.GDI}; + } else { + availableModes = new WindowCaptureMode[]{WindowCaptureMode.Auto, WindowCaptureMode.Screen, WindowCaptureMode.GDI, WindowCaptureMode.Aero, WindowCaptureMode.AeroTransparent}; + } + PopulateComboBox(combobox_window_capture_mode, availableModes, selectedWindowCaptureMode); + } + private void AddPluginTab() { if (PluginHelper.instance.HasPlugins()) { this.tabcontrol.TabPages.Add(tab_plugins); @@ -133,13 +209,7 @@ namespace Greenshot { this.checkbox_autostartshortcut.Text = lang.GetString(LangKey.settings_autostartshortcut); this.groupbox_destination.Text = lang.GetString(LangKey.settings_destination); - this.checkbox_clipboard.Text = lang.GetString(LangKey.settings_destination_clipboard); - this.checkbox_printer.Text = lang.GetString(LangKey.settings_destination_printer); - this.checkbox_file.Text = lang.GetString(LangKey.settings_destination_file); - this.checkbox_fileas.Text = lang.GetString(LangKey.settings_destination_fileas); - this.checkbox_editor.Text = lang.GetString(LangKey.settings_destination_editor); - this.checkbox_email.Text = lang.GetString(LangKey.settings_destination_email); - + this.groupbox_preferredfilesettings.Text = lang.GetString(LangKey.settings_preferredfilesettings); this.label_storagelocation.Text = lang.GetString(LangKey.settings_storagelocation); @@ -177,7 +247,9 @@ namespace Greenshot { // Initialize the Language ComboBox this.combobox_language.DisplayMember = "Description"; this.combobox_language.ValueMember = "Ietf"; - this.combobox_language.SelectedValue = lang.CurrentLanguage; + if (lang.CurrentLanguage != null) { + this.combobox_language.SelectedValue = lang.CurrentLanguage; + } // Set datasource last to prevent problems // See: http://www.codeproject.com/KB/database/scomlistcontrolbinding.aspx?fid=111644 this.combobox_language.DataSource = lang.SupportedLanguages; @@ -189,7 +261,7 @@ namespace Greenshot { // Check the settings and somehow visibly mark when something is incorrect private bool CheckSettings() { bool settingsOk = true; - if(!Directory.Exists(FilenameHelper.FillVariables(textbox_storagelocation.Text))) { + if(!Directory.Exists(FilenameHelper.FillVariables(textbox_storagelocation.Text, false))) { textbox_storagelocation.BackColor = Color.Red; settingsOk = false; } else { @@ -207,18 +279,15 @@ namespace Greenshot { colorButton_window_background.SelectedColor = coreConfiguration.DWMBackgroundColor; checkbox_ie_capture.Checked = coreConfiguration.IECapture; - combobox_language.SelectedValue = lang.CurrentLanguage; - textbox_storagelocation.Text = FilenameHelper.FillVariables(coreConfiguration.OutputFilePath); + if (lang.CurrentLanguage != null) { + combobox_language.SelectedValue = lang.CurrentLanguage; + } + textbox_storagelocation.Text = FilenameHelper.FillVariables(coreConfiguration.OutputFilePath, false); textbox_screenshotname.Text = coreConfiguration.OutputFileFilenamePattern; combobox_primaryimageformat.SelectedItem = coreConfiguration.OutputFileFormat; - combobox_emailformat.SelectedItem = coreConfiguration.OutputEMailFormat; - if (!DWM.isDWMEnabled()) { - // Remove DWM from configuration, as DWM is disabled! - if (coreConfiguration.WindowCaptureMode == WindowCaptureMode.Aero || coreConfiguration.WindowCaptureMode == WindowCaptureMode.AeroTransparent) { - coreConfiguration.WindowCaptureMode = WindowCaptureMode.GDI; - } - } - combobox_window_capture_mode.SelectedItem = coreConfiguration.WindowCaptureMode; + + SetEmailFormat(coreConfiguration.OutputEMailFormat); + SetWindowCaptureMode(coreConfiguration.WindowCaptureMode); checkbox_copypathtoclipboard.Checked = coreConfiguration.OutputFileCopyPathToClipboard; trackBarJpegQuality.Value = coreConfiguration.OutputFileJpegQuality; @@ -226,12 +295,16 @@ namespace Greenshot { checkbox_alwaysshowjpegqualitydialog.Checked = coreConfiguration.OutputFilePromptJpegQuality; checkbox_playsound.Checked = coreConfiguration.PlayCameraSound; - checkbox_clipboard.Checked = coreConfiguration.OutputDestinations.Contains(Destination.Clipboard); - checkbox_file.Checked = coreConfiguration.OutputDestinations.Contains(Destination.FileDefault); - checkbox_fileas.Checked = coreConfiguration.OutputDestinations.Contains(Destination.FileWithDialog); - checkbox_printer.Checked = coreConfiguration.OutputDestinations.Contains(Destination.Printer); - checkbox_editor.Checked = coreConfiguration.OutputDestinations.Contains(Destination.Editor); - checkbox_email.Checked = coreConfiguration.OutputDestinations.Contains(Destination.EMail); + checkedDestinationsListBox.Items.Clear(); + foreach(IDestination destination in DestinationHelper.GetAllDestinations()) { + checkedDestinationsListBox.Items.Add(destination, coreConfiguration.OutputDestinations.Contains(destination.Designation)); + } +// checkbox_clipboard.Checked = coreConfiguration.OutputDestinations.Contains("Clipboard"); +// checkbox_file.Checked = coreConfiguration.OutputDestinations.Contains("File"); +// checkbox_fileas.Checked = coreConfiguration.OutputDestinations.Contains("FileWithDialog"); +// checkbox_printer.Checked = coreConfiguration.OutputDestinations.Contains("Printer"); +// checkbox_editor.Checked = coreConfiguration.OutputDestinations.Contains("Editor"); +// checkbox_email.Checked = coreConfiguration.OutputDestinations.Contains("EMail"); checkboxPrintInverted.Checked = coreConfiguration.OutputPrintInverted; checkboxAllowCenter.Checked = coreConfiguration.OutputPrintCenter; @@ -257,46 +330,43 @@ namespace Greenshot { checkbox_autostartshortcut.Checked = StartupHelper.checkRunUser(); } - if (!MapiMailMessage.HasMAPIorOutlook()) { - // Disable MAPI functionality as it's not available - checkbox_email.Enabled = false; - checkbox_email.Checked = false; - combobox_emailformat.Visible = false; - } else { - // Enable MAPI functionality - checkbox_email.Enabled = true; - if (OutlookExporter.HasOutlook()) { - combobox_emailformat.Visible = true; - } - } - checkbox_usedefaultproxy.Checked = coreConfiguration.UseProxy; numericUpDown_daysbetweencheck.Value = coreConfiguration.UpdateCheckInterval; + CheckDestinationSettings(); } private void SaveSettings() { - coreConfiguration.Language = combobox_language.SelectedValue.ToString(); + if (combobox_language.SelectedItem != null) { + coreConfiguration.Language = combobox_language.SelectedValue.ToString(); + } - coreConfiguration.WindowCaptureMode = (WindowCaptureMode)combobox_window_capture_mode.SelectedItem; + coreConfiguration.WindowCaptureMode = GetSelected(combobox_window_capture_mode); coreConfiguration.OutputFileFilenamePattern = textbox_screenshotname.Text; - if (!FilenameHelper.FillVariables(coreConfiguration.OutputFilePath).Equals(textbox_storagelocation.Text)) { + if (!FilenameHelper.FillVariables(coreConfiguration.OutputFilePath, false).Equals(textbox_storagelocation.Text)) { coreConfiguration.OutputFilePath = textbox_storagelocation.Text; } - coreConfiguration.OutputFileFormat = (OutputFormat)combobox_primaryimageformat.SelectedItem; - coreConfiguration.OutputEMailFormat = (EmailFormat)combobox_emailformat.SelectedItem; + if (combobox_primaryimageformat.SelectedItem != null) { + coreConfiguration.OutputFileFormat = (OutputFormat)combobox_primaryimageformat.SelectedItem; + } else { + coreConfiguration.OutputFileFormat = OutputFormat.png; + } + + // TODO: Fix + //coreConfiguration.OutputEMailFormat = GetSelected(combobox_emailformat); + coreConfiguration.OutputEMailFormat = EmailFormat.OUTLOOK_HTML; coreConfiguration.OutputFileCopyPathToClipboard = checkbox_copypathtoclipboard.Checked; coreConfiguration.OutputFileJpegQuality = trackBarJpegQuality.Value; coreConfiguration.OutputFilePromptJpegQuality = checkbox_alwaysshowjpegqualitydialog.Checked; coreConfiguration.PlayCameraSound = checkbox_playsound.Checked; - List destinations = new List(); - if (checkbox_clipboard.Checked) destinations.Add(Destination.Clipboard); - if (checkbox_file.Checked) destinations.Add(Destination.FileDefault); - if (checkbox_fileas.Checked) destinations.Add(Destination.FileWithDialog); - if (checkbox_printer.Checked) destinations.Add(Destination.Printer); - if (checkbox_editor.Checked) destinations.Add(Destination.Editor); - if (checkbox_email.Checked) destinations.Add(Destination.EMail); + List destinations = new List(); + foreach(int index in checkedDestinationsListBox.CheckedIndices) { + IDestination destination = (IDestination)checkedDestinationsListBox.Items[index]; + if (checkedDestinationsListBox.GetItemCheckState(index) == CheckState.Checked) { + destinations.Add(destination.Designation); + } + } coreConfiguration.OutputDestinations = destinations; coreConfiguration.OutputPrintInverted = checkboxPrintInverted.Checked; @@ -348,24 +418,26 @@ namespace Greenshot { } void Settings_cancelClick(object sender, System.EventArgs e) { - this.Close(); + DialogResult = DialogResult.Cancel; + lang.FreeResources(); } void Settings_okayClick(object sender, System.EventArgs e) { if (CheckSettings()) { SaveSettings(); - this.Close(); + DialogResult = DialogResult.OK; } else { this.tabcontrol.SelectTab(this.tab_output); } + lang.FreeResources(); } void BrowseClick(object sender, System.EventArgs e) { // Get the storage location and replace the environment variables - this.folderBrowserDialog1.SelectedPath = FilenameHelper.FillVariables(this.textbox_storagelocation.Text); + this.folderBrowserDialog1.SelectedPath = FilenameHelper.FillVariables(this.textbox_storagelocation.Text, false); if (this.folderBrowserDialog1.ShowDialog() == DialogResult.OK) { // Only change if there is a change, otherwise we might overwrite the environment variables - if (this.folderBrowserDialog1.SelectedPath != null && !this.folderBrowserDialog1.SelectedPath.Equals(FilenameHelper.FillVariables(this.textbox_storagelocation.Text))) { + if (this.folderBrowserDialog1.SelectedPath != null && !this.folderBrowserDialog1.SelectedPath.Equals(FilenameHelper.FillVariables(this.textbox_storagelocation.Text, false))) { this.textbox_storagelocation.Text = this.folderBrowserDialog1.SelectedPath; } } @@ -390,23 +462,33 @@ namespace Greenshot { } void Combobox_languageSelectedIndexChanged(object sender, EventArgs e) { - LOG.Debug("Setting language to: " + (string)combobox_language.SelectedValue); - lang.SetLanguage((string)combobox_language.SelectedValue); + // Get the combobox values BEFORE changing the language + //EmailFormat selectedEmailFormat = GetSelected(combobox_emailformat); + WindowCaptureMode selectedWindowCaptureMode = GetSelected(combobox_window_capture_mode); + if (combobox_language.SelectedItem != null) { + LOG.Debug("Setting language to: " + (string)combobox_language.SelectedValue); + lang.SetLanguage((string)combobox_language.SelectedValue); + } // Reflect language changes to the settings form UpdateUI(); + + // Update the email & windows capture mode + //SetEmailFormat(selectedEmailFormat); + SetWindowCaptureMode(selectedWindowCaptureMode); } void Combobox_window_capture_modeSelectedIndexChanged(object sender, EventArgs e) { int windowsVersion = Environment.OSVersion.Version.Major; - string modeText = combobox_window_capture_mode.Text; - string dwmMode = WindowCaptureMode.Aero.ToString(); - string autoMode = WindowCaptureMode.Auto.ToString(); - if (modeText.Equals(dwmMode, StringComparison.CurrentCultureIgnoreCase) - || (modeText.Equals(autoMode, StringComparison.CurrentCultureIgnoreCase) && windowsVersion >= 6) ) { - colorButton_window_background.Visible = true; - } else { - colorButton_window_background.Visible = false; + WindowCaptureMode mode = GetSelected(combobox_window_capture_mode); + if (windowsVersion >= 6) { + switch (mode) { + case WindowCaptureMode.Aero: + case WindowCaptureMode.Auto: + colorButton_window_background.Visible = true; + return; + } } + colorButton_window_background.Visible = false; } void SettingsFormFormClosing(object sender, FormClosingEventArgs e) { @@ -416,5 +498,46 @@ namespace Greenshot { void SettingsFormShown(object sender, EventArgs e) { HotkeyControl.UnregisterHotkeys(); } + + /// + /// Check the destination settings + /// + void CheckDestinationSettings() { + bool clipboardDestinationChecked = false; + bool pickerSelected = false; + foreach(IDestination destination in checkedDestinationsListBox.CheckedItems) { + if (destination.Designation.Equals("Clipboard")) { + clipboardDestinationChecked = true; + } + if (destination.Designation.Equals("Picker")) { + pickerSelected = true; + } + } + if (pickerSelected) { + foreach(int index in checkedDestinationsListBox.CheckedIndices) { + IDestination destination = (IDestination)checkedDestinationsListBox.Items[index]; + if (!destination.Designation.Equals("Picker")) { + checkedDestinationsListBox.SetItemCheckState(index, CheckState.Indeterminate); + } + } + } else { + foreach(int index in checkedDestinationsListBox.CheckedIndices) { + if (checkedDestinationsListBox.GetItemCheckState(index) == CheckState.Indeterminate) { + checkedDestinationsListBox.SetItemCheckState(index, CheckState.Checked); + } + } + // Prevent multiple clipboard settings at once, see bug #3435056 + if (clipboardDestinationChecked) { + checkbox_copypathtoclipboard.Checked = false; + checkbox_copypathtoclipboard.Enabled = false; + } else { + checkbox_copypathtoclipboard.Enabled = true; + } + } + } + + void DestinationsCheckStateChanged(object sender, EventArgs e) { + CheckDestinationSettings(); + } } } diff --git a/Greenshot/Greenshot.csproj b/Greenshot/Greenshot.csproj index 0ef6268b6..503159ddf 100644 --- a/Greenshot/Greenshot.csproj +++ b/Greenshot/Greenshot.csproj @@ -1,4 +1,5 @@ - + + {CD642BF4-D815-4D67-A0B5-C69F0B8231AF} Debug @@ -21,8 +22,13 @@ true Full True - DEBUG;TRACE False + DEBUG;TRACE + False + Auto + 4194304 + x86 + 4096 bin\Release\ @@ -30,23 +36,19 @@ None False True - - False Auto 4194304 - x86 + AnyCPU 4096 - Lib\log4net.dll - @@ -63,8 +65,17 @@ + + + + + + + + + + - @@ -83,13 +94,13 @@ - + @@ -100,6 +111,7 @@ + @@ -112,10 +124,7 @@ CaptureForm.cs - - - DestinationPickerForm.cs - + ImageEditorForm.cs @@ -142,14 +151,17 @@ BugReportForm.cs + + - + + - + @@ -160,7 +172,6 @@ - @@ -173,19 +184,29 @@ - + + + + + + + + + + + + - + + - - @@ -193,13 +214,7 @@ - - - - - - - + ImageEditorForm.cs @@ -221,6 +236,9 @@ Always + + Always + Always @@ -230,6 +248,9 @@ Always + + Always + Always @@ -242,6 +263,9 @@ Always + + Always + Always @@ -287,6 +311,9 @@ Always + + Always + Always @@ -304,6 +331,9 @@ + + Always + Never @@ -320,8 +350,6 @@ ColorDialog.cs - - @@ -334,11 +362,13 @@ + - + + {5B924697-4DCD-4F98-85F1-105CB84B7341} GreenshotPlugin @@ -346,15 +376,22 @@ - "$(MSBuildProjectDirectory)\tools\TortoiseSVN\SubWCRev.exe" "$(MSBuildProjectDirectory)\." "$(MSBuildProjectDirectory)\releases\innosetup\setup.iss" "$(MSBuildProjectDirectory)\releases\innosetup\setup-SVN.iss" -cd "$(MSBuildProjectDirectory)\bin\Release" -"$(MSBuildProjectDirectory)\tools\FileVerifier++\fvc.exe" -c -a MD5 -r -o "checksum.MD5" *.dll *.exe -"$(MSBuildProjectDirectory)\tools\7zip\7za.exe" a -x!.SVN -r "$(MSBuildProjectDirectory)\releases\Greenshot-NO-INSTALLER.zip" "$(MSBuildProjectDirectory)\bin\Release\*" "$(MSBuildProjectDirectory)\releases\additional_files\*" -cd "$(MSBuildProjectDirectory)\releases\innosetup" -"$(MSBuildProjectDirectory)\tools\innosetup\ISCC.exe" "$(MSBuildProjectDirectory)\releases\innosetup\setup-SVN.iss" - "$(MSBuildProjectDirectory)\tools\TortoiseSVN\SubWCRev.exe" "$(MSBuildProjectDirectory)\." "$(MSBuildProjectDirectory)\AssemblyInfo.cs.template" "$(MSBuildProjectDirectory)\AssemblyInfo.cs" copy "$(ProjectDir)log4net.xml" "$(SolutionDir)bin\$(Configuration)\log4net.xml" + "$(MSBuildProjectDirectory)\tools\TortoiseSVN\SubWCRev.exe" "$(MSBuildProjectDirectory)\." "$(MSBuildProjectDirectory)\releases\innosetup\setup.iss" "$(MSBuildProjectDirectory)\releases\innosetup\setup-SVN.iss" +cd "$(MSBuildProjectDirectory)\bin\Release" +del *.config +del *.log +"$(MSBuildProjectDirectory)\tools\FileVerifier++\fvc.exe" -c -a MD5 -r -o "checksum.MD5" *.dll *.exe +cd "$(MSBuildProjectDirectory)\releases\innosetup" +"$(MSBuildProjectDirectory)\tools\innosetup\ISCC.exe" "$(MSBuildProjectDirectory)\releases\innosetup\setup-SVN.iss" +cd "$(MSBuildProjectDirectory)\bin\Release" +echo dummy config, used to make greenshot store the configuration in this directory > greenshot.ini +move log4net-portable.xml log4net.xml +del installer.txt +del "$(MSBuildProjectDirectory)\releases\Greenshot-NO-INSTALLER.zip" +"$(MSBuildProjectDirectory)\tools\7zip\7za.exe" a -x!.SVN -r "$(MSBuildProjectDirectory)\releases\Greenshot-NO-INSTALLER.zip" "$(MSBuildProjectDirectory)\bin\Release\*" "$(MSBuildProjectDirectory)\releases\additional_files\*" +del greenshot.ini "$(MSBuildProjectDirectory)\tools\TortoiseSVN\SubWCRev.exe" "$(MSBuildProjectDirectory)\." "$(MSBuildProjectDirectory)\AssemblyInfo.cs.template" "$(MSBuildProjectDirectory)\AssemblyInfo.cs" diff --git a/Greenshot/Greenshot.sln b/Greenshot/Greenshot.sln index 3a3b76bd9..583131783 100644 --- a/Greenshot/Greenshot.sln +++ b/Greenshot/Greenshot.sln @@ -1,13 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 -# SharpDevelop 3.2.0.5777 +# SharpDevelop 4.1.0.8000 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GreenshotPlugin", "..\GreenshotPlugin\GreenshotPlugin.csproj", "{5B924697-4DCD-4F98-85F1-105CB84B7341}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Greenshot-OCR-Plugin", "..\Greenshot-OCR-Plugin\Greenshot-OCR-Plugin.csproj", "{C6988EE8-2FEE-4349-9F09-F9628A0D8965}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Greenshot-TitleFix-Plugin", "..\Greenshot-TitleFix-Plugin\Greenshot-TitleFix-Plugin.csproj", "{0A07500E-7404-48D7-8789-7EB2A23E0DD5}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GreenshotJiraPlugin", "..\GreenshotJiraPlugin\GreenshotJiraPlugin.csproj", "{19FEEF09-313F-43C7-819D-F1BCA782B08B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GreenshotImgurPlugin", "..\GreenshotImgurPlugin\GreenshotImgurPlugin.csproj", "{80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}" @@ -23,10 +21,18 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Greenshot", "Greenshot.cspr EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GreenshotTest", "..\GreenshotTest\GreenshotTest.csproj", "{EFD01BC7-15E5-48AD-BE68-D7B62FEEED2D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GreenshotConfluencePlugin", "..\GreenshotConfluencePlugin\GreenshotConfluencePlugin.csproj", "{C3052651-598A-44E2-AAB3-2E41311D50F9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GreenshotExternalCommandPlugin", "..\GreenshotExternalCommandPlugin\GreenshotExternalCommandPlugin.csproj", "{47F23C86-604E-4CC3-8767-B3D4088F30BB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginExample", "..\PluginExample\PluginExample.csproj", "{6BD38118-B27F-43A1-951C-FB6464D39260}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -41,10 +47,6 @@ Global {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Debug|Any CPU.ActiveCfg = Debug|x86 {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Release|Any CPU.Build.0 = Release|x86 {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Release|Any CPU.ActiveCfg = Release|x86 - {0A07500E-7404-48D7-8789-7EB2A23E0DD5}.Debug|Any CPU.Build.0 = Debug|x86 - {0A07500E-7404-48D7-8789-7EB2A23E0DD5}.Debug|Any CPU.ActiveCfg = Debug|x86 - {0A07500E-7404-48D7-8789-7EB2A23E0DD5}.Release|Any CPU.Build.0 = Release|x86 - {0A07500E-7404-48D7-8789-7EB2A23E0DD5}.Release|Any CPU.ActiveCfg = Release|x86 {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|Any CPU.Build.0 = Debug|x86 {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|Any CPU.ActiveCfg = Debug|x86 {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|Any CPU.Build.0 = Release|x86 @@ -57,5 +59,49 @@ Global {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|Any CPU.ActiveCfg = Debug|x86 {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|Any CPU.Build.0 = Release|x86 {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|Any CPU.ActiveCfg = Release|x86 + {EFD01BC7-15E5-48AD-BE68-D7B62FEEED2D}.Debug|x86.Build.0 = Debug|x86 + {EFD01BC7-15E5-48AD-BE68-D7B62FEEED2D}.Debug|x86.ActiveCfg = Debug|x86 + {EFD01BC7-15E5-48AD-BE68-D7B62FEEED2D}.Release|x86.Build.0 = Release|x86 + {EFD01BC7-15E5-48AD-BE68-D7B62FEEED2D}.Release|x86.ActiveCfg = Release|x86 + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|x86.Build.0 = Debug|x86 + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|x86.ActiveCfg = Debug|x86 + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|x86.Build.0 = Release|x86 + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|x86.ActiveCfg = Release|x86 + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|x86.Build.0 = Debug|x86 + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|x86.ActiveCfg = Debug|x86 + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|x86.Build.0 = Release|x86 + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|x86.ActiveCfg = Release|x86 + {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Debug|x86.Build.0 = Debug|x86 + {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Debug|x86.ActiveCfg = Debug|x86 + {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Release|x86.Build.0 = Release|x86 + {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Release|x86.ActiveCfg = Release|x86 + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|x86.Build.0 = Debug|x86 + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|x86.ActiveCfg = Debug|x86 + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|x86.Build.0 = Release|x86 + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|x86.ActiveCfg = Release|x86 + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|Any CPU.Build.0 = Debug|x86 + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|Any CPU.ActiveCfg = Debug|x86 + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|x86.Build.0 = Debug|x86 + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|x86.ActiveCfg = Debug|x86 + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|Any CPU.Build.0 = Release|x86 + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|Any CPU.ActiveCfg = Release|x86 + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|x86.Build.0 = Release|x86 + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|x86.ActiveCfg = Release|x86 + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|Any CPU.Build.0 = Debug|x86 + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|Any CPU.ActiveCfg = Debug|x86 + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|x86.Build.0 = Debug|x86 + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|x86.ActiveCfg = Debug|x86 + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|Any CPU.Build.0 = Release|x86 + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|Any CPU.ActiveCfg = Release|x86 + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|x86.Build.0 = Release|x86 + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|x86.ActiveCfg = Release|x86 + {6BD38118-B27F-43A1-951C-FB6464D39260}.Debug|Any CPU.Build.0 = Debug|x86 + {6BD38118-B27F-43A1-951C-FB6464D39260}.Debug|Any CPU.ActiveCfg = Debug|x86 + {6BD38118-B27F-43A1-951C-FB6464D39260}.Debug|x86.Build.0 = Debug|x86 + {6BD38118-B27F-43A1-951C-FB6464D39260}.Debug|x86.ActiveCfg = Debug|x86 + {6BD38118-B27F-43A1-951C-FB6464D39260}.Release|Any CPU.Build.0 = Release|x86 + {6BD38118-B27F-43A1-951C-FB6464D39260}.Release|Any CPU.ActiveCfg = Release|x86 + {6BD38118-B27F-43A1-951C-FB6464D39260}.Release|x86.Build.0 = Release|x86 + {6BD38118-B27F-43A1-951C-FB6464D39260}.Release|x86.ActiveCfg = Release|x86 EndGlobalSection EndGlobal diff --git a/Greenshot/GreenshotMain.cs b/Greenshot/GreenshotMain.cs new file mode 100644 index 000000000..b22929c03 --- /dev/null +++ b/Greenshot/GreenshotMain.cs @@ -0,0 +1,57 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Reflection; + +// Remove AppendPrivatePath warning: +#pragma warning disable 0618 +namespace Greenshot { + /// + /// Description of Main. + /// + public class GreenshotMain { + private const string PAF_PATH = @"App\Greenshot"; + + static GreenshotMain() { + AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); + } + + static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { + Assembly ayResult = null; + string sShortAssemblyName = args.Name.Split(',')[0]; + Assembly[] ayAssemblies = AppDomain.CurrentDomain.GetAssemblies(); + foreach (Assembly ayAssembly in ayAssemblies) { + if (sShortAssemblyName == ayAssembly.FullName.Split(',')[0]) { + ayResult = ayAssembly; + break; + } + } + return ayResult; + } + + [STAThread] + public static void Main(string[] args) { + // Needed to make Greenshot portable, the path should be appended before the DLL's are loaded!! + AppDomain.CurrentDomain.AppendPrivatePath(PAF_PATH); + MainForm.Start(args); + } + } +} diff --git a/Greenshot/Help/HelpBrowserForm.Designer.cs b/Greenshot/Help/HelpBrowserForm.Designer.cs index e8f04992a..4b6004ae3 100644 --- a/Greenshot/Help/HelpBrowserForm.Designer.cs +++ b/Greenshot/Help/HelpBrowserForm.Designer.cs @@ -67,7 +67,7 @@ namespace Greenshot.Help this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.ClientSize = new System.Drawing.Size(412, 560); this.Controls.Add(this.webBrowser1); - this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Icon = GreenshotPlugin.Core.GreenshotResources.getGreenshotIcon(); this.Name = "HelpBrowserForm"; this.Text = "Greenshot Help"; this.ResumeLayout(false); diff --git a/Greenshot/Helpers/AccessibleHelper.cs b/Greenshot/Helpers/AccessibleHelper.cs deleted file mode 100644 index fe38727e8..000000000 --- a/Greenshot/Helpers/AccessibleHelper.cs +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Diagnostics; -using System.Runtime.InteropServices; - -using Accessibility; -using Greenshot.Helpers.IEInterop; - -namespace Greenshot.Helpers { - - /// - /// See: http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/03a8c835-e9e4-405b-8345-6c3d36bc8941 - /// This should really be cleaned up, there is little OO behind this class! - /// Maybe move the basic Accessible functions to WindowDetails!? - /// - public class Accessible { - private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(Accessible)); - - #region Interop - private static int AccessibleObjectFromWindow(WindowDetails windowDetails, OBJID idObject, ref IAccessible acc) { - Guid guid = new Guid("{618736e0-3c3d-11cf-810c-00aa00389b71}"); // IAccessible - object obj = null; - int num = AccessibleObjectFromWindow(windowDetails.Handle, (uint)idObject, ref guid, ref obj); - acc = (IAccessible)obj; - return num; - } - [DllImport("oleacc.dll")] - public static extern int AccessibleObjectFromWindow(IntPtr hwnd, uint id, ref Guid iid, [In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object ppvObject); - [DllImport("oleacc.dll")] - public static extern int AccessibleChildren(IAccessible paccContainer, int iChildStart, int cChildren, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] object[] rgvarChildren, out int pcObtained); - [DllImport("oleacc.dll")] - public static extern int ObjectFromLresult(int lResult, ref Guid riid, int wParam, ref IHTMLDocument2 ppvObject); - #endregion - - private enum OBJID : uint { - OBJID_WINDOW = 0x00000000, - } - - private const int IE_ACTIVE_TAB = 2097154; - private const int CHILDID_SELF = 0; - private IAccessible accessible; - private Accessible[] Children { - get { - int num = 0; - object[] res = GetAccessibleChildren(accessible, out num); - if (res == null) { - return new Accessible[0]; - } - - List list = new List(res.Length); - foreach (object obj in res) { - IAccessible acc = obj as IAccessible; - if (acc != null) { - list.Add(new Accessible(acc)); - } - } - return list.ToArray(); - } - } - - private string Name { - get { - return accessible.get_accName(CHILDID_SELF); - } - } - - private int ChildCount { - get { - return accessible.accChildCount; - } - } - - public Accessible(WindowDetails windowDetails) { - AccessibleObjectFromWindow(windowDetails, OBJID.OBJID_WINDOW, ref accessible); - if (accessible == null) { - throw new Exception(); - } - } - - public void ActivateIETab(string tabCaptionToActivate) { - foreach (Accessible accessor in Children) { - foreach (var child in accessor.Children) { - foreach (var tab in child.Children) { - if (tab.Name == tabCaptionToActivate) { - tab.Activate(); - return; - } - } - } - } - } - - public void CloseIETab(string tabCaptionToClose) { - foreach (Accessible accessor in Children) { - foreach (var child in accessor.Children) { - foreach (var tab in child.Children) { - if (tab.Name == tabCaptionToClose) { - foreach (var CloseTab in tab.Children) { - CloseTab.Activate(); - } - return; - } - } - } - } - } - - public void ActivateIETab(int tabIndexToActivate) { - var index = 0; - foreach (Accessible accessor in Children) { - foreach (var child in accessor.Children) { - foreach (var tab in child.Children) { - if (tabIndexToActivate >= child.ChildCount -1) { - return; - } - - if (index == tabIndexToActivate) { - tab.Activate(); - return; - } - index++; - } - } - } - } - - public string IEActiveTabUrl { - get { - foreach (Accessible accessor in Children) { - foreach (var child in accessor.Children) { - foreach (var tab in child.Children) { - object tabIndex = tab.accessible.get_accState(CHILDID_SELF); - - if ((int)tabIndex == IE_ACTIVE_TAB) { - var description = tab.accessible.get_accDescription(CHILDID_SELF); - - if (!string.IsNullOrEmpty(description)) { - if (description.Contains(Environment.NewLine)) { - var url = description.Substring(description.IndexOf(Environment.NewLine)).Trim(); - return url; - } - } - } - } - } - } - return String.Empty; - } - } - - public int IEActiveTabIndex { - get { - var index = 0; - foreach (Accessible accessor in Children) { - foreach (var child in accessor.Children) { - foreach (var tab in child.Children) { - object tabIndex = tab.accessible.get_accState(0); - - if ((int)tabIndex == IE_ACTIVE_TAB) { - return index; - } - index++; - } - } - } - return -1; - } - } - - public string IEActiveTabCaption { - get { - foreach (Accessible accessor in Children) { - foreach (var child in accessor.Children) { - foreach (var tab in child.Children) { - object tabIndex = tab.accessible.get_accState(0); - - if ((int)tabIndex == IE_ACTIVE_TAB) { - return tab.Name; - } - } - } - } - return String.Empty; - } - } - - public List IETabCaptions { - get { - var captionList = new List(); - - foreach (Accessible accessor in Children) { - foreach (var child in accessor.Children) { - foreach (var tab in child.Children) { - captionList.Add(tab.Name); - } - } - } - - if (captionList.Count > 0) { - captionList.RemoveAt(captionList.Count - 1); - } - - return captionList; - } - } - - public int IETabCount { - get { - foreach (Accessible accessor in Children) { - foreach (var child in accessor.Children) { - foreach (var tab in child.Children) { - return child.ChildCount - 1; - } - } - } - return 0; - } - } - - private Accessible(IAccessible acc) { - if (acc == null) { - throw new Exception(); - } - accessible = acc; - } - - private void Activate() { - accessible.accDoDefaultAction(CHILDID_SELF); - } - - private static object[] GetAccessibleChildren(IAccessible ao, out int childs) { - childs = 0; - object[] ret = null; - int count = ao.accChildCount; - - if (count > 0) { - ret = new object[count]; - AccessibleChildren(ao, 0, count, ret, out childs); - } - return ret; - } - } -} - diff --git a/Greenshot/Helpers/ClipboardHelper.cs b/Greenshot/Helpers/ClipboardHelper.cs index 2cc661036..02984fcb7 100644 --- a/Greenshot/Helpers/ClipboardHelper.cs +++ b/Greenshot/Helpers/ClipboardHelper.cs @@ -29,18 +29,18 @@ using System.Threading; using System.Windows.Forms; using Greenshot.Configuration; -using Greenshot.Drawing; -using Greenshot.UnmanagedHelpers; +using GreenshotPlugin.UnmanagedHelpers; using GreenshotPlugin.Core; +using IniFile; namespace Greenshot.Helpers { /// /// Description of ClipboardHelper. /// - public class ClipboardHelper { + public static class ClipboardHelper { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ClipboardHelper)); private static readonly Object clipboardLockObject = new Object(); - private static string previousTmpFile = null; + private static readonly CoreConfiguration config = IniConfig.GetIniSection(); private static IntPtr nextClipboardViewer = IntPtr.Zero; // Template for the HTML Text on the clipboard, see: http://msdn.microsoft.com/en-us/library/ms649015%28v=vs.85%29.aspx private const string HTML_CLIPBOARD_STRING = @"Version:0.9 @@ -61,51 +61,6 @@ EndSelection:<<<<<<<4 "; - - /// - /// Register the window to monitor the clipboard - /// - /// Handle for the window - public static void RegisterClipboardViewer(IntPtr handle) { - LOG.Debug("RegisterClipboardViewer called"); - nextClipboardViewer = User32.SetClipboardViewer(handle); - } - /// - /// Deregister the window to monitor the clipboard - /// - /// Handle for the window - public static void DeregisterClipboardViewer(IntPtr handle) { - LOG.Debug("DeregisterClipboardViewer called"); - User32.ChangeClipboardChain(handle, nextClipboardViewer); - CleanupTmpFile(); - } - - /// - /// Handle WndProc messages for the clipboard - /// - /// Messag - /// true if the message is handled - public static bool HandleClipboardMessages(ref Message m) { - switch (m.Msg) { - case (int)WindowsMessages.WM_DRAWCLIPBOARD: - // Check if there is a format "greenshot" on the clipboard, than don't delete - List currentFormats = GetFormats(); - if (currentFormats != null && !currentFormats.Contains("greenshot")) { - CleanupTmpFile(); - } - // Make sure the next clipboard viewer gets the message - User32.SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam); - return true; - case (int)WindowsMessages.WM_CHANGECBCHAIN: - if (m.WParam == nextClipboardViewer) { - nextClipboardViewer = m.LParam; - } else { - User32.SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam); - } - return true; - } - return false; - } /** * Get the current "ClipboardOwner" but only if it isn't us! @@ -166,9 +121,9 @@ EndSelection:<<<<<<<4 ILanguage lang = Language.GetInstance(); if (clipboardOwner != null) { messageText = String.Format(lang.GetString(LangKey.clipboard_inuse), clipboardOwner); - } else { + } else { messageText = lang.GetString(LangKey.clipboard_error); - } + } LOG.Error(messageText, ee); } else { Thread.Sleep(100); @@ -180,11 +135,142 @@ EndSelection:<<<<<<<4 } } + /// + /// Safe wrapper for Clipboard.ContainsText + /// Created for Bug #3432313 + /// + /// boolean if there is text on the clipboard + public static bool ContainsText() { + lock (clipboardLockObject) { + int retryCount = 2; + while (retryCount >= 0) { + try { + return Clipboard.ContainsText(); + } catch (Exception ee) { + if (retryCount == 0) { + string messageText = null; + string clipboardOwner = GetClipboardOwner(); + ILanguage lang = Language.GetInstance(); + if (clipboardOwner != null) { + messageText = String.Format(lang.GetString(LangKey.clipboard_inuse), clipboardOwner); + } else { + messageText = lang.GetString(LangKey.clipboard_error); + } + LOG.Error(messageText, ee); + } else { + Thread.Sleep(100); + } + } finally { + --retryCount; + } + } + } + return false; + } + + /// + /// Safe wrapper for Clipboard.ContainsImage + /// Created for Bug #3432313 + /// + /// boolean if there is an image on the clipboard + public static bool ContainsImage() { + lock (clipboardLockObject) { + int retryCount = 2; + while (retryCount >= 0) { + try { + return Clipboard.ContainsImage(); + } catch (Exception ee) { + if (retryCount == 0) { + string messageText = null; + string clipboardOwner = GetClipboardOwner(); + ILanguage lang = Language.GetInstance(); + if (clipboardOwner != null) { + messageText = String.Format(lang.GetString(LangKey.clipboard_inuse), clipboardOwner); + } else { + messageText = lang.GetString(LangKey.clipboard_error); + } + LOG.Error(messageText, ee); + } else { + Thread.Sleep(100); + } + } finally { + --retryCount; + } + } + } + return false; + } + + /// + /// Safe wrapper for Clipboard.GetImage + /// Created for Bug #3432313 + /// + /// Image if there is an image on the clipboard + public static Image GetImage() { + lock (clipboardLockObject) { + int retryCount = 2; + while (retryCount >= 0) { + try { + return Clipboard.GetImage(); + } catch (Exception ee) { + if (retryCount == 0) { + string messageText = null; + string clipboardOwner = GetClipboardOwner(); + ILanguage lang = Language.GetInstance(); + if (clipboardOwner != null) { + messageText = String.Format(lang.GetString(LangKey.clipboard_inuse), clipboardOwner); + } else { + messageText = lang.GetString(LangKey.clipboard_error); + } + LOG.Error(messageText, ee); + } else { + Thread.Sleep(100); + } + } finally { + --retryCount; + } + } + } + return null; + } + + /// + /// Safe wrapper for Clipboard.GetText + /// Created for Bug #3432313 + /// + /// string if there is text on the clipboard + public static string GetText() { + lock (clipboardLockObject) { + int retryCount = 2; + while (retryCount >= 0) { + try { + return Clipboard.GetText(); + } catch (Exception ee) { + if (retryCount == 0) { + string messageText = null; + string clipboardOwner = GetClipboardOwner(); + ILanguage lang = Language.GetInstance(); + if (clipboardOwner != null) { + messageText = String.Format(lang.GetString(LangKey.clipboard_inuse), clipboardOwner); + } else { + messageText = lang.GetString(LangKey.clipboard_error); + } + LOG.Error(messageText, ee); + } else { + Thread.Sleep(100); + } + } finally { + --retryCount; + } + } + } + return null; + } + /** * Set text to the clipboard */ public static void SetClipboardData(string text) { - CleanupTmpFile(); IDataObject ido = new DataObject(); ido.SetData(DataFormats.Text, true, text); SetDataObject(ido); @@ -203,22 +289,6 @@ EndSelection:<<<<<<<4 sb.Replace("<<<<<<<4", (utf8EncodedHTMLString.IndexOf("")).ToString("D8")); return sb.ToString(); } - - /// - /// Cleanup previously created tmp file - /// - private static void CleanupTmpFile() { - if (previousTmpFile != null) { - try { - LOG.DebugFormat("Deleting previous tmp file: {0}", previousTmpFile); - File.Delete(previousTmpFile); - } catch (Exception e) { - LOG.Warn("Error deleting " + previousTmpFile, e); - } finally { - previousTmpFile = null; - } - } - } /** * Set an Image to the clipboard @@ -233,35 +303,45 @@ EndSelection:<<<<<<<4 */ private const int BITMAPFILEHEADER_LENGTH = 14; public static void SetClipboardData(Image image) { - CleanupTmpFile(); DataObject ido = new DataObject(); // This will work for Office and most other applications //ido.SetData(DataFormats.Bitmap, true, image); - MemoryStream bmpStream = new MemoryStream(); - MemoryStream imageStream = new MemoryStream(); - MemoryStream pngStream = new MemoryStream(); + MemoryStream bmpStream = null; + MemoryStream imageStream = null; + MemoryStream pngStream = null; try { - // PNG works for Powerpoint - image.Save(pngStream, ImageFormat.Png); + if (config.ClipboardFormats.Contains(ClipboardFormat.PNG)) { + pngStream = new MemoryStream(); + // PNG works for Powerpoint + image.Save(pngStream, ImageFormat.Png); + // Set the PNG stream + ido.SetData("PNG", false, pngStream); + } - // Save image as BMP - image.Save(bmpStream, ImageFormat.Bmp); - // Copy the source, but skip the "BITMAPFILEHEADER" which has a size of 14 - imageStream.Write(bmpStream.GetBuffer(), BITMAPFILEHEADER_LENGTH, (int) bmpStream.Length - BITMAPFILEHEADER_LENGTH); + if (config.ClipboardFormats.Contains(ClipboardFormat.HTML)) { + bmpStream = new MemoryStream(); + // Save image as BMP + image.Save(bmpStream, ImageFormat.Bmp); - // Mark the clipboard for us as "do not touch" - ido.SetData("greenshot", false, "was here!"); - // Set the PNG stream - ido.SetData("PNG", false, pngStream); - // Set the DIB to the clipboard DataObject - ido.SetData(DataFormats.Dib, true, imageStream); + imageStream = new MemoryStream(); + // Copy the source, but skip the "BITMAPFILEHEADER" which has a size of 14 + imageStream.Write(bmpStream.GetBuffer(), BITMAPFILEHEADER_LENGTH, (int) bmpStream.Length - BITMAPFILEHEADER_LENGTH); + + // Set the DIB to the clipboard DataObject + ido.SetData(DataFormats.Dib, true, imageStream); + } + // Set the HTML - previousTmpFile = ImageOutput.SaveToTmpFile(image); - string html = getClipboardString(image, previousTmpFile); - ido.SetText(html, TextDataFormat.Html); + if (config.ClipboardFormats.Contains(ClipboardFormat.HTML)) { + // Mark the clipboard for us as "do not touch" + ido.SetData("greenshot", false, "was here!"); + string tmpFile = ImageOutput.SaveToTmpFile(image, OutputFormat.png, config.OutputFileJpegQuality); + string html = getClipboardString(image, tmpFile); + ido.SetText(html, TextDataFormat.Html); + } } finally { // we need to use the SetDataOject before the streams are closed otherwise the buffer will be gone! // Place the DataObject to the clipboard @@ -288,7 +368,6 @@ EndSelection:<<<<<<<4 * Set Object with type Type to the clipboard */ public static void SetClipboardData(Type type, Object obj) { - CleanupTmpFile(); DataFormats.Format format = DataFormats.GetFormat(type.FullName); //now copy to clipboard diff --git a/Greenshot/Helpers/Colors.cs b/Greenshot/Helpers/Colors.cs index 2dcf380f3..9c91372b2 100644 --- a/Greenshot/Helpers/Colors.cs +++ b/Greenshot/Helpers/Colors.cs @@ -22,11 +22,8 @@ using System; using System.Collections.Generic; using System.Drawing; -namespace Greenshot.Helpers -{ - public class Colors { - private Colors() {} - +namespace Greenshot.Helpers { + public static class Colors { public static bool IsVisible(Color c) { return c != null && !c.Equals(Color.Empty) && !c.Equals(Color.Transparent) && c.A > 0; } @@ -37,8 +34,8 @@ namespace Greenshot.Helpers int g = 0; int b = 0; int count = 0; - foreach(Color color in colors) { - if(!color.Equals(Color.Empty)) { + foreach (Color color in colors) { + if (!color.Equals(Color.Empty)) { a += color.A; r += color.R; g += color.G; diff --git a/Greenshot/Helpers/CopyData.cs b/Greenshot/Helpers/CopyData.cs index 2e8378cf3..739a0518b 100644 --- a/Greenshot/Helpers/CopyData.cs +++ b/Greenshot/Helpers/CopyData.cs @@ -24,9 +24,10 @@ using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using System.Runtime.Serialization.Formatters.Binary; -using System.Text; using System.Windows.Forms; +using GreenshotPlugin.Core; + /// /// Code from vbAccelerator, location: /// http://www.vbaccelerator.com/home/NET/Code/Libraries/Windows_Messages/Simple_Interprocess_Communication/WM_COPYDATA_Demo_zip_SimpleInterprocessCommunicationsCS_CopyData_cs.asp diff --git a/Greenshot/Helpers/EnvironmentInfo.cs b/Greenshot/Helpers/EnvironmentInfo.cs index 157cd2490..f0ec44ac4 100644 --- a/Greenshot/Helpers/EnvironmentInfo.cs +++ b/Greenshot/Helpers/EnvironmentInfo.cs @@ -19,25 +19,31 @@ * along with this program. If not, see . */ using System; +using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; -using Greenshot.UnmanagedHelpers; +using GreenshotPlugin.UnmanagedHelpers; +using GreenshotPlugin.Core; +using IniFile; namespace Greenshot.Helpers { /// /// Description of EnvironmentInfo. /// - public class EnvironmentInfo { + public static class EnvironmentInfo { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger("Greenshot"); - - private EnvironmentInfo(){} public static string EnvironmentToString(bool newline) { StringBuilder environment = new StringBuilder(); environment.Append("Software version: " + Application.ProductVersion); + if (IniConfig.IsPortable) { + environment.Append(" Portable"); + } + environment.Append(" (" + OSInfo.Bits +" bit)"); + if (newline) { environment.AppendLine(); } else { @@ -85,8 +91,11 @@ namespace Greenshot.Helpers { if (ex.Data != null && ex.Data.Count > 0) { report.AppendLine(); report.AppendLine("Additional Information:"); - foreach(string key in ex.Data.Keys) { - report.AppendLine(key + " = " + ex.Data[key]); + foreach(object key in ex.Data.Keys) { + object data = ex.Data[key]; + if (data != null) { + report.AppendLine(key + " = " + data); + } } } if (ex is ExternalException) { @@ -114,6 +123,11 @@ namespace Greenshot.Helpers { StringBuilder exceptionText = new StringBuilder(); exceptionText.AppendLine(EnvironmentInfo.EnvironmentToString(true)); exceptionText.AppendLine(EnvironmentInfo.ExceptionToString(exception)); + exceptionText.AppendLine("Configuration dump:"); + using (TextWriter writer = new StringWriter(exceptionText)) { + IniConfig.SaveIniSectionToWriter(writer, IniConfig.GetIniSection(), true); + } + return exceptionText.ToString(); } } diff --git a/Greenshot/Helpers/FilenameHelper.cs b/Greenshot/Helpers/FilenameHelper.cs index 1f55fd43e..632f834de 100644 --- a/Greenshot/Helpers/FilenameHelper.cs +++ b/Greenshot/Helpers/FilenameHelper.cs @@ -24,12 +24,12 @@ using System.IO; using System.Text.RegularExpressions; using System.Windows.Forms; -using Greenshot.Configuration; using Greenshot.Plugin; using GreenshotPlugin.Core; +using IniFile; namespace Greenshot.Helpers { - public class FilenameHelper { + public static class FilenameHelper { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(FilenameHelper)); private static readonly Regex VAR_REGEXP = new Regex(@"\${(?[^:}]+)[:]?(?[^}]*)}", RegexOptions.Compiled); private static readonly Regex SPLIT_REGEXP = new Regex(";(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", RegexOptions.Compiled); @@ -37,8 +37,6 @@ namespace Greenshot.Helpers { private static CoreConfiguration conf = IniConfig.GetIniSection(); private const string UNSAFE_REPLACEMENT = "_"; - private FilenameHelper() { - } /// /// Remove invalid characters from the fully qualified filename /// @@ -106,9 +104,9 @@ namespace Greenshot.Helpers { /// Variables from the user /// Variables from the machine /// string with the match replacement - private static string MatchVarEvaluator(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars) { + private static string MatchVarEvaluator(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars, bool filenameSafeMode) { try { - return MatchVarEvaluatorInternal(match, captureDetails, processVars, userVars, machineVars); + return MatchVarEvaluatorInternal(match, captureDetails, processVars, userVars, machineVars, filenameSafeMode); } catch (Exception e) { LOG.Error("Error in MatchVarEvaluatorInternal", e); } @@ -121,7 +119,8 @@ namespace Greenshot.Helpers { /// What are we matching? /// The detail, can be null /// - private static string MatchVarEvaluatorInternal(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars) { // some defaults + private static string MatchVarEvaluatorInternal(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars, bool filenameSafeMode) { + // some defaults int padWidth = 0; int startIndex = 0; int endIndex = 0; @@ -176,11 +175,23 @@ namespace Greenshot.Helpers { } } if (processVars != null && processVars.Contains(variable)) { - replaceValue = MakePathSafe((string)processVars[variable]); + if (filenameSafeMode) { + replaceValue = MakePathSafe((string)processVars[variable]); + } else { + replaceValue = (string)processVars[variable]; + } } else if (userVars != null && userVars.Contains(variable)) { - replaceValue = MakePathSafe((string)userVars[variable]); + if (filenameSafeMode) { + replaceValue = MakePathSafe((string)userVars[variable]); + } else { + replaceValue = (string)userVars[variable]; + } } else if (machineVars != null && machineVars.Contains(variable)) { - replaceValue = MakePathSafe((string)machineVars[variable]); + if (filenameSafeMode) { + replaceValue = MakePathSafe((string)machineVars[variable]); + } else { + replaceValue = (string)machineVars[variable]; + } } else if (captureDetails != null && captureDetails.MetaData != null && captureDetails.MetaData.ContainsKey(variable)) { replaceValue = MakePathSafe(captureDetails.MetaData[variable]); } else { @@ -273,6 +284,13 @@ namespace Greenshot.Helpers { break; } } + // do padding + if (padWidth >0) { + replaceValue = replaceValue.PadRight(padWidth, padChar); + } else if (padWidth < 0) { + replaceValue = replaceValue.PadLeft(-padWidth, padChar); + } + // do substring if (startIndex != 0 || endIndex != 0) { if (startIndex < 0) { @@ -296,12 +314,6 @@ namespace Greenshot.Helpers { } } - // do padding - if (padWidth >0) { - replaceValue = replaceValue.PadRight(padWidth, padChar); - } else if (padWidth < 0) { - replaceValue = replaceValue.PadLeft(-padWidth, padChar); - } return replaceValue; } @@ -309,8 +321,9 @@ namespace Greenshot.Helpers { /// "Simply" fill the pattern with environment variables /// /// String with pattern ${var} + /// true to make sure everything is filenamesafe /// Filled string - public static string FillVariables(string pattern) { + public static string FillVariables(string pattern, bool filenameSafeMode) { IDictionary processVars = null; IDictionary userVars = null; IDictionary machineVars = null; @@ -333,7 +346,7 @@ namespace Greenshot.Helpers { } return VAR_REGEXP.Replace(pattern, - new MatchEvaluator(delegate(Match m) { return MatchVarEvaluator(m, null, processVars, userVars, machineVars); }) + new MatchEvaluator(delegate(Match m) { return MatchVarEvaluator(m, null, processVars, userVars, machineVars, filenameSafeMode); }) ); } @@ -361,7 +374,7 @@ namespace Greenshot.Helpers { try { return VAR_REGEXP.Replace(pattern, - new MatchEvaluator(delegate(Match m) { return MatchVarEvaluator(m, captureDetails, processVars, userVars, machineVars); }) + new MatchEvaluator(delegate(Match m) { return MatchVarEvaluator(m, captureDetails, processVars, userVars, machineVars, true); }) ); } catch (Exception e) { // adding additional data for bug tracking diff --git a/Greenshot/Helpers/GuiRectangle.cs b/Greenshot/Helpers/GuiRectangle.cs index 841ccc792..49813cbba 100644 --- a/Greenshot/Helpers/GuiRectangle.cs +++ b/Greenshot/Helpers/GuiRectangle.cs @@ -21,29 +21,44 @@ using System; using System.Drawing; -namespace Greenshot.Helpers -{ +namespace Greenshot.Helpers { /// - /// Description of GuiRectangle. + /// Helper class for creating rectangles with positive dimensions, regardless of input coordinates /// - public class GuiRectangle - { - private GuiRectangle() - { - - } - + public static class GuiRectangle { + public static Rectangle GetGuiRectangle(int x, int y, int w, int h) { - if (w < 0) { - x = x + w; - w = -w; - } - if (h < 0) { - y = y + h; - h = -h; - } - return new Rectangle(x, y, w, h); + Rectangle rect = new Rectangle(x, y, w, h); + MakeGuiRectangle(ref rect); + return rect; } + public static void MakeGuiRectangle(ref Rectangle rect) { + if (rect.Width < 0) { + rect.X += rect.Width; + rect.Width = -rect.Width; + } + if (rect.Height < 0) { + rect.Y += rect.Height; + rect.Height = -rect.Height; + } + } + + public static RectangleF GetGuiRectangleF(float x, float y, float w, float h) { + RectangleF rect = new RectangleF(x, y, w, h); + MakeGuiRectangleF(ref rect); + return rect; + } + + public static void MakeGuiRectangleF(ref RectangleF rect) { + if (rect.Width < 0) { + rect.X += rect.Width; + rect.Width = -rect.Width; + } + if (rect.Height < 0) { + rect.Y += rect.Height; + rect.Height = -rect.Height; + } + } } } diff --git a/Greenshot/Helpers/IECaptureHelper.cs b/Greenshot/Helpers/IECaptureHelper.cs index dfedd6acc..b0ee7e0d0 100644 --- a/Greenshot/Helpers/IECaptureHelper.cs +++ b/Greenshot/Helpers/IECaptureHelper.cs @@ -19,23 +19,18 @@ * along with this program. If not, see . */ using System; -using System.Collections; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; -using System.Globalization; -using System.Runtime.InteropServices; -using System.Threading; -using System.Windows.Forms; using Greenshot.Configuration; using Greenshot.Drawing.Filters; -using Greenshot.Helpers; using Greenshot.Helpers.IEInterop; using Greenshot.Plugin; -using Greenshot.UnmanagedHelpers; +using GreenshotPlugin.UnmanagedHelpers; using GreenshotPlugin.Controls; using GreenshotPlugin.Core; +using IniFile; namespace Greenshot.Helpers { /// @@ -44,45 +39,22 @@ namespace Greenshot.Helpers { /// On top I modified it to use the already available code in Greenshot. /// Many thanks to all the people who contributed here! /// - public class IECaptureHelper { + public static class IECaptureHelper { private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(IECaptureHelper)); private static CoreConfiguration configuration = IniConfig.GetIniSection(); private static ILanguage language = Language.GetInstance(); // Helper method to activate a certain IE Tab public static void ActivateIETab(WindowDetails ieWindowDetails, int tabIndex) { - WindowDetails directUIWindowDetails = GetDirectUI(ieWindowDetails); + WindowDetails directUIWindowDetails = IEHelper.GetDirectUI(ieWindowDetails); // Bring window to the front ieWindowDetails.Restore(); // Get accessible - Accessible ieAccessible = new Accessible(directUIWindowDetails); + Accessible ieAccessible = new Accessible(directUIWindowDetails.Handle); // Activate Tab ieAccessible.ActivateIETab(tabIndex); } - /// - /// Find the DirectUI window for MSAA (Accessible) - /// - /// The browser WindowDetails - /// WindowDetails for the DirectUI window - private static WindowDetails GetDirectUI(WindowDetails browserWindowDetails) { - WindowDetails tmpWD = browserWindowDetails; - // Since IE 9 the TabBandClass is less deep! - if (IEHelper.IEVersion() < 9) { - tmpWD = tmpWD.GetChild("CommandBarClass"); - if (tmpWD != null) { - tmpWD = tmpWD.GetChild("ReBarWindow32"); - } - } - if (tmpWD != null) { - tmpWD = tmpWD.GetChild("TabBandClass"); - } - if (tmpWD != null) { - tmpWD = tmpWD.GetChild("DirectUIHWND");; - } - return tmpWD; - } - /// /// Simple check if IE is running /// @@ -106,9 +78,9 @@ namespace Greenshot.Helpers { foreach (WindowDetails ieWindow in WindowDetails.GetAllWindows("IEFrame")) { try { if (!ieHandleList.Contains(ieWindow.Handle)) { - WindowDetails directUIWD = GetDirectUI(ieWindow); + WindowDetails directUIWD = IEHelper.GetDirectUI(ieWindow); if (directUIWD != null) { - Accessible accessible = new Accessible(directUIWD); + Accessible accessible = new Accessible(directUIWD.Handle); browserWindows.Add(ieWindow, accessible.IETabCaptions); } else { List singleWindowText = new List(); @@ -138,53 +110,51 @@ namespace Greenshot.Helpers { /// The WindowDetails to get the IHTMLDocument2 for /// Ref to the IHTMLDocument2 to return /// The WindowDetails to which the IHTMLDocument2 belongs - private static DocumentContainer GetDocument() { + private static DocumentContainer GetDocument(WindowDetails activeWindow) { DocumentContainer returnDocumentContainer = null; WindowDetails returnWindow = null; IHTMLDocument2 returnDocument2 = null; // alternative if no match WindowDetails alternativeReturnWindow = null; IHTMLDocument2 alternativeReturnDocument2 = null; - WindowDetails activeWindow = WindowDetails.GetActiveWindow(); // Find the IE window foreach (WindowDetails ieWindow in WindowDetails.GetAllWindows("IEFrame")) { LOG.DebugFormat("Processing {0} - {1}", ieWindow.ClassName, ieWindow.Text); Accessible ieAccessible = null; - WindowDetails directUIWD = GetDirectUI(ieWindow); - if (directUIWD != null) { - ieAccessible = new Accessible(directUIWD); - } + WindowDetails directUIWD = IEHelper.GetDirectUI(ieWindow); + if (directUIWD != null) { + ieAccessible = new Accessible(directUIWD.Handle); + } if (ieAccessible == null) { - if (!ieWindow.Equals(activeWindow)) { - LOG.WarnFormat("No ieAccessible for {0}", ieWindow.Text); + LOG.InfoFormat("Active Window is {0}", activeWindow.Text); + if (!ieWindow.Equals(activeWindow)) { + LOG.WarnFormat("No ieAccessible for {0}", ieWindow.Text); continue; - } - LOG.DebugFormat("No ieAccessible, but the active window is an IE window: {0}, ", ieWindow.Text); + } + LOG.DebugFormat("No ieAccessible, but the active window is an IE window: {0}, ", ieWindow.Text); } try { // Get the Document IHTMLDocument2 document2 = null; - int windowMessage = User32.RegisterWindowMessage("WM_HTML_GETOBJECT"); + uint windowMessage = User32.RegisterWindowMessage("WM_HTML_GETOBJECT"); if (windowMessage == 0) { LOG.WarnFormat("Couldn't register WM_HTML_GETOBJECT"); continue; } - WindowDetails ieServer= ieWindow.GetChild("Internet Explorer_Server"); if (ieServer == null) { LOG.WarnFormat("No Internet Explorer_Server for {0}", ieWindow.Text); continue; } LOG.DebugFormat("Trying WM_HTML_GETOBJECT on {0}", ieServer.ClassName); - int response; - User32.SendMessageTimeout(ieServer.Handle, windowMessage, 0, 0, 0x2, 1000, out response); - if (response != 0) { - Guid IID_IHTMLDocument = new Guid("626FC520-A41E-11CF-A731-00A0C9082637"); - int hr = Accessible.ObjectFromLresult(response, ref IID_IHTMLDocument, 0, ref document2); + UIntPtr response; + User32.SendMessageTimeout(ieServer.Handle, windowMessage, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_NORMAL, 1000, out response); + if (response != UIntPtr.Zero) { + document2 = (IHTMLDocument2)Accessible.ObjectFromLresult(response, typeof(IHTMLDocument).GUID, IntPtr.Zero); if (document2 == null) { LOG.Error("No IHTMLDocument2 found"); continue; @@ -263,57 +233,90 @@ namespace Greenshot.Helpers { /// ICapture where the capture needs to be stored /// ICapture with the content (if any) public static ICapture CaptureIE(ICapture capture) { - BackgroundForm backgroundForm = BackgroundForm.ShowAndWait("Greenshot", language.GetString(LangKey.wait_ie_capture)); - - //Get IHTMLDocument2 for the current active window - DocumentContainer documentContainer = GetDocument(); - - // Nothing found - if (documentContainer == null) { - LOG.Debug("Nothing to capture found"); - return null; - } - LOG.DebugFormat("Window class {0}", documentContainer.ContentWindow.ClassName); - LOG.DebugFormat("Window location {0}", documentContainer.ContentWindow.Location); - - - // The URL is available unter "document2.url" and can be used to enhance the meta-data etc. - capture.CaptureDetails.AddMetaData("url", documentContainer.Url); - - // bitmap to return - Bitmap returnBitmap = null; - try { - returnBitmap = capturePage(documentContainer, capture); - } catch (Exception e) { - LOG.Error("Exception found, ignoring and returning nothing! Error was: ", e); - } + WindowDetails activeWindow = WindowDetails.GetActiveWindow(); - if (returnBitmap == null) { - return null; + // Show backgroundform after retrieving the active window.. + BackgroundForm backgroundForm = new BackgroundForm(language.GetString(LangKey.contextmenu_captureie), language.GetString(LangKey.wait_ie_capture)); + backgroundForm.Show(); + //BackgroundForm backgroundForm = BackgroundForm.ShowAndWait(language.GetString(LangKey.contextmenu_captureie), language.GetString(LangKey.wait_ie_capture)); + try { + //Get IHTMLDocument2 for the current active window + DocumentContainer documentContainer = GetDocument(activeWindow); + + // Nothing found + if (documentContainer == null) { + LOG.Debug("Nothing to capture found"); + return null; + } + LOG.DebugFormat("Window class {0}", documentContainer.ContentWindow.ClassName); + LOG.DebugFormat("Window location {0}", documentContainer.ContentWindow.Location); + + // The URL is available unter "document2.url" and can be used to enhance the meta-data etc. + capture.CaptureDetails.AddMetaData("url", documentContainer.Url); + + // bitmap to return + Bitmap returnBitmap = null; + Size pageSize = Size.Empty; + try { + pageSize = PrepareCapture(documentContainer, capture); + returnBitmap = capturePage(documentContainer, capture, pageSize); + } catch (Exception captureException) { + LOG.Error("Exception found, ignoring and returning nothing! Error was: ", captureException); + } + // Capture the element on the page + try { + if (configuration.IEFieldCapture && capture.CaptureDetails.HasDestination("Editor")) { + // clear the current elements, as they are for the window itself + capture.Elements.Clear(); + CaptureElement documentCaptureElement = documentContainer.CreateCaptureElements(pageSize); + foreach(DocumentContainer frameDocument in documentContainer.Frames) { + CaptureElement frameCaptureElement = frameDocument.CreateCaptureElements(Size.Empty); + if (frameCaptureElement != null) { + documentCaptureElement.Children.Add(frameCaptureElement); + } + } + capture.AddElement(documentCaptureElement); + // Offset the elements, as they are "back offseted" later... + Point windowLocation = documentContainer.ContentWindow.WindowRectangle.Location; + capture.MoveElements(-(capture.ScreenBounds.Location.X-windowLocation.X), -(capture.ScreenBounds.Location.Y-windowLocation.Y)); + } + } catch (Exception elementsException) { + LOG.Warn("An error occurred while creating the capture elements: ", elementsException); + } + + + if (returnBitmap == null) { + return null; + } + + // Store the bitmap for further processing + capture.Image = returnBitmap; + // Store the location of the window + capture.Location = documentContainer.ContentWindow.Location; + // Store the title of the Page + if (documentContainer.Name != null) { + capture.CaptureDetails.Title = documentContainer.Name; + } else { + capture.CaptureDetails.Title = activeWindow.Text; + } + + // Only move the mouse to correct for the capture offset + capture.MoveMouseLocation(-documentContainer.ViewportRectangle.X, -documentContainer.ViewportRectangle.Y); + // Used to be: capture.MoveMouseLocation(-(capture.Location.X + documentContainer.CaptureOffset.X), -(capture.Location.Y + documentContainer.CaptureOffset.Y)); + } finally { + // Always close the background form + backgroundForm.CloseDialog(); } - - // Store the bitmap for further processing - capture.Image = returnBitmap; - // Store the location of the window - capture.Location = documentContainer.ContentWindow.Location; - // Store the title of the Page - capture.CaptureDetails.Title = documentContainer.Name; - - // Only move the mouse to correct for the capture offset - capture.MoveMouseLocation(-documentContainer.ViewportRectangle.X, -documentContainer.ViewportRectangle.Y); - // Used to be: capture.MoveMouseLocation(-(capture.Location.X + documentContainer.CaptureOffset.X), -(capture.Location.Y + documentContainer.CaptureOffset.Y)); - - backgroundForm.CloseDialog(); return capture; } - + /// - /// Capture the actual page (document) + /// Prepare the calculates for all the frames, move and fit... /// - /// The document wrapped in a container - /// Bitmap with the page content as an image - private static Bitmap capturePage(DocumentContainer documentContainer, ICapture capture) { - WindowDetails contentWindowDetails = documentContainer.ContentWindow; + /// + /// + /// Size of the complete page + private static Size PrepareCapture(DocumentContainer documentContainer, ICapture capture) { // Calculate the page size int pageWidth = documentContainer.ScrollWidth; int pageHeight = documentContainer.ScrollHeight; @@ -390,9 +393,19 @@ namespace Greenshot.Helpers { LOG.WarnFormat("Capture has a height of {0} which bigger than the maximum supported {1}, cutting height to the maxium", pageHeight, short.MaxValue); pageHeight = Math.Min(pageHeight, short.MaxValue); } - + return new Size(pageWidth, pageHeight); + } + + /// + /// Capture the actual page (document) + /// + /// The document wrapped in a container + /// Bitmap with the page content as an image + private static Bitmap capturePage(DocumentContainer documentContainer, ICapture capture, Size pageSize) { + WindowDetails contentWindowDetails = documentContainer.ContentWindow; + //Create a target bitmap to draw into with the calculated page size - Bitmap returnBitmap = new Bitmap(pageWidth, pageHeight, PixelFormat.Format24bppRgb); + Bitmap returnBitmap = new Bitmap(pageSize.Width, pageSize.Height, PixelFormat.Format24bppRgb); using (Graphics graphicsTarget = Graphics.FromImage(returnBitmap)) { // Clear the target with the backgroundcolor Color clearColor = documentContainer.BackgroundColor; @@ -401,7 +414,7 @@ namespace Greenshot.Helpers { // Get the base document & draw it drawDocument(documentContainer, contentWindowDetails, graphicsTarget); - //ParseElements(documentContainer, graphicsTarget, returnBitmap); + // Loop over the frames and clear their source area so we don't see any artefacts foreach(DocumentContainer frameDocument in documentContainer.Frames) { using(Brush brush = new SolidBrush(clearColor)) { @@ -411,7 +424,6 @@ namespace Greenshot.Helpers { // Loop over the frames and capture their content foreach(DocumentContainer frameDocument in documentContainer.Frames) { drawDocument(frameDocument, contentWindowDetails, graphicsTarget); - //ParseElements(frameDocument, graphicsTarget, returnBitmap); } } return returnBitmap; @@ -450,16 +462,24 @@ namespace Greenshot.Helpers { //Get Browser Window Width & Height int pageWidth = documentContainer.ScrollWidth; int pageHeight = documentContainer.ScrollHeight; + if (pageWidth * pageHeight == 0) { + LOG.WarnFormat("Empty page for DocumentContainer {0}: {1}", documentContainer.Name, documentContainer.Url); + return; + } //Get Screen Width & Height (this is better as the WindowDetails.ClientRectangle as the real visible parts are there! int viewportWidth = documentContainer.ClientWidth; int viewportHeight = documentContainer.ClientHeight; - + if (viewportWidth * viewportHeight == 0) { + LOG.WarnFormat("Empty viewport for DocumentContainer {0}: {1}", documentContainer.Name, documentContainer.Url); + return; + } + // Store the current location so we can set the browser back and use it for the mouse cursor int startLeft = documentContainer.ScrollLeft; int startTop = documentContainer.ScrollTop; - LOG.DebugFormat("Capturing {4} with total size {0},{1} displayed in with size {2},{3}", pageWidth, pageHeight, viewportWidth, viewportHeight, documentContainer.Name); + LOG.DebugFormat("Capturing {4} with total size {0},{1} displayed with size {2},{3}", pageWidth, pageHeight, viewportWidth, viewportHeight, documentContainer.Name); // Variable used for looping horizontally int horizontalPage = 0; @@ -490,7 +510,7 @@ namespace Greenshot.Helpers { try { // cut all junk, due to IE "border" we need to remove some parts Rectangle viewportRect = documentContainer.ViewportRectangle; - if (!Rectangle.Empty.Equals(viewportRect)) { + if (!viewportRect.IsEmpty) { LOG.DebugFormat("Cropping to viewport: {0}", viewportRect); ImageHelper.Crop(ref fragment, ref viewportRect); } diff --git a/Greenshot/Helpers/IEInterop/IEContainer.cs b/Greenshot/Helpers/IEInterop/IEContainer.cs index a17cdc0bc..03a57f20d 100644 --- a/Greenshot/Helpers/IEInterop/IEContainer.cs +++ b/Greenshot/Helpers/IEInterop/IEContainer.cs @@ -24,8 +24,9 @@ using System.Drawing; using System.Globalization; using System.Runtime.InteropServices; -using Greenshot.Helpers.IEInterop; using GreenshotPlugin.Core; +using Greenshot.Plugin; +using IniFile; namespace Greenshot.Helpers.IEInterop { public class ElementContainer { @@ -37,6 +38,7 @@ namespace Greenshot.Helpers.IEInterop { public class DocumentContainer { private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(DocumentContainer)); private static CoreConfiguration configuration = IniConfig.GetIniSection(); + private static readonly List CAPTURE_TAGS = new List(); private const int E_ACCESSDENIED = unchecked((int)0x80070005L); private static Guid IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046"); private static Guid IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E"); @@ -48,7 +50,7 @@ namespace Greenshot.Helpers.IEInterop { private Point destinationLocation; private Point startLocation = Point.Empty; private Rectangle viewportRectangle = Rectangle.Empty; - private string name; + private string name = null; private string url; private bool isDTD; private DocumentContainer parent; @@ -57,12 +59,37 @@ namespace Greenshot.Helpers.IEInterop { private double zoomLevelY = 1; private List frames = new List(); + static DocumentContainer() { + CAPTURE_TAGS.Add("LABEL"); + CAPTURE_TAGS.Add("DIV"); + CAPTURE_TAGS.Add("IMG"); + CAPTURE_TAGS.Add("INPUT"); + CAPTURE_TAGS.Add("BUTTON"); + CAPTURE_TAGS.Add("TD"); + CAPTURE_TAGS.Add("TR"); + CAPTURE_TAGS.Add("TH"); + CAPTURE_TAGS.Add("TABLE"); + CAPTURE_TAGS.Add("TBODY"); + CAPTURE_TAGS.Add("SPAN"); + CAPTURE_TAGS.Add("A"); + CAPTURE_TAGS.Add("UL"); + CAPTURE_TAGS.Add("LI"); + CAPTURE_TAGS.Add("H1"); + CAPTURE_TAGS.Add("H2"); + CAPTURE_TAGS.Add("H3"); + CAPTURE_TAGS.Add("H4"); + CAPTURE_TAGS.Add("H5"); + CAPTURE_TAGS.Add("FORM"); + CAPTURE_TAGS.Add("FIELDSET"); + } + private DocumentContainer(IHTMLWindow2 frameWindow, WindowDetails contentWindow, DocumentContainer parent) { //IWebBrowser2 webBrowser2 = frame as IWebBrowser2; //IHTMLDocument2 document2 = webBrowser2.Document as IHTMLDocument2; IHTMLDocument2 document2 = GetDocumentFromWindow(frameWindow); try { LOG.DebugFormat("frameWindow.name {0}", frameWindow.name); + name = frameWindow.name; } catch { } @@ -89,7 +116,7 @@ namespace Greenshot.Helpers.IEInterop { // element = element.offsetParent; // } while (element != null); // startLocation = new Point((int)x, (int)y); - Point contentWindowLocation = contentWindow.ClientRectangle.Location; + Point contentWindowLocation = contentWindow.WindowRectangle.Location; int x = window3.screenLeft - contentWindowLocation.X; int y = window3.screenTop - contentWindowLocation.Y; startLocation = new Point(x, y); @@ -118,7 +145,7 @@ namespace Greenshot.Helpers.IEInterop { } else { isDTD = false; } - Rectangle clientRectangle = contentWindow.ClientRectangle; + Rectangle clientRectangle = contentWindow.WindowRectangle; try { IHTMLWindow3 window3 = (IHTMLWindow3)document2.parentWindow; IHTMLWindow2 window2 = (IHTMLWindow2)document2.parentWindow; @@ -164,8 +191,16 @@ namespace Greenshot.Helpers.IEInterop { sourceLocation = new Point(ScaleX((int)startLocation.X), ScaleY((int)startLocation.Y)); destinationLocation = new Point(ScaleX((int)startLocation.X), ScaleY((int)startLocation.Y)); - name = document2.title; - url = document2.url; + try { + if (name == null) { + name = document2.title; + } + } catch { + } + try { + url = document2.url; + } catch { + } if (parent != null) { return; @@ -321,6 +356,84 @@ namespace Greenshot.Helpers.IEInterop { } return elements; } + + /// + /// Create a CaptureElement for every element on the page, which can be used by the editor. + /// + /// + public CaptureElement CreateCaptureElements(Size documentSize) { + LOG.DebugFormat("CreateCaptureElements for {0}", Name); + IHTMLElement baseElement = document3.documentElement as IHTMLElement; + IHTMLElement2 baseElement2 = baseElement as IHTMLElement2; + IHTMLRect htmlRect = baseElement2.getBoundingClientRect(); + if (Size.Empty.Equals(documentSize)) { + documentSize = new Size(ScrollWidth, ScrollHeight); + } + Rectangle baseElementBounds = new Rectangle(DestinationLocation.X + htmlRect.left, DestinationLocation.Y + htmlRect.top, documentSize.Width, documentSize.Height); + if (baseElementBounds.Width <= 0 || baseElementBounds.Height <= 0) { + // not visisble + return null; + } + + CaptureElement captureBaseElement = new CaptureElement(name, baseElementBounds); + + foreach(IHTMLElement bodyElement in baseElement.children) { + if ("BODY".Equals(bodyElement.tagName)) { + captureBaseElement.Children.AddRange(RecurseElements(bodyElement)); + } + } + return captureBaseElement; + } + + /// + /// Recurse into the document tree + /// + /// IHTMLElement we want to recurse into + /// List of ICaptureElements with child elements + private List RecurseElements(IHTMLElement parentElement) { + List childElements = new List(); + foreach(IHTMLElement element in parentElement.children) { + string tagName = element.tagName; + + // Skip elements we aren't interested in + if (!CAPTURE_TAGS.Contains(tagName)) { + continue; + } + + ICaptureElement captureElement = new CaptureElement(tagName); + captureElement.Children.AddRange(RecurseElements(element)); + + // Get Bounds + IHTMLElement2 element2 = element as IHTMLElement2; + IHTMLRect htmlRect = element2.getBoundingClientRect(); + + int left = htmlRect.left; + int top = htmlRect.top; + int right = htmlRect.right; + int bottom = htmlRect.bottom; + + // Offset + left += DestinationLocation.X; + top += DestinationLocation.Y; + right += DestinationLocation.X; + bottom += DestinationLocation.Y; + + // Fit to floating children + foreach(ICaptureElement childElement in captureElement.Children) { + //left = Math.Min(left, childElement.Bounds.Left); + //top = Math.Min(top, childElement.Bounds.Top); + right = Math.Max(right, childElement.Bounds.Right); + bottom = Math.Max(bottom, childElement.Bounds.Bottom); + } + Rectangle bounds = new Rectangle(left, top, right-left, bottom-top); + + if (bounds.Width > 0 && bounds.Height > 0) { + captureElement.Bounds = bounds; + childElements.Add(captureElement); + } + } + return childElements; + } public Color BackgroundColor { get { @@ -377,6 +490,7 @@ namespace Greenshot.Helpers.IEInterop { public void setAttribute(string attribute, int value) { setAttribute(attribute, value.ToString()); } + /// /// Set/change an attribute on a document /// diff --git a/Greenshot/Helpers/IEInterop/IHTMLBodyElement.cs b/Greenshot/Helpers/IEInterop/IHTMLBodyElement.cs index 9b9b5041d..a305ce05d 100644 --- a/Greenshot/Helpers/IEInterop/IHTMLBodyElement.cs +++ b/Greenshot/Helpers/IEInterop/IHTMLBodyElement.cs @@ -19,9 +19,7 @@ * along with this program. If not, see . */ using System; -using System.Collections; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; namespace Greenshot.Helpers.IEInterop { [ComImport, Guid("3050F1D8-98B5-11CF-BB82-00AA00BDCE0B"), diff --git a/Greenshot/Helpers/IEInterop/IHTMLDocument.cs b/Greenshot/Helpers/IEInterop/IHTMLDocument.cs index 35f37ed2b..3e7ca0312 100644 --- a/Greenshot/Helpers/IEInterop/IHTMLDocument.cs +++ b/Greenshot/Helpers/IEInterop/IHTMLDocument.cs @@ -20,8 +20,6 @@ */ using System; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using System.Collections; namespace Greenshot.Helpers.IEInterop { /// IHTMLDocument interface. diff --git a/Greenshot/Helpers/IEInterop/IHTMLDocument2.cs b/Greenshot/Helpers/IEInterop/IHTMLDocument2.cs index 14c6905ff..d2b790164 100644 --- a/Greenshot/Helpers/IEInterop/IHTMLDocument2.cs +++ b/Greenshot/Helpers/IEInterop/IHTMLDocument2.cs @@ -20,53 +20,58 @@ */ using System; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using System.Collections; namespace Greenshot.Helpers.IEInterop { - /// IHTMLDocument2 interface. - [Guid("332C4425-26CB-11D0-B483-00C04FD90119")] - [ComImport] - [TypeLibType(TypeLibTypeFlags.FDual)] - [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLDocument2 { - IHTMLElement body { - [DispId(1004)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - string title { - [DispId(1012)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - object frames { - [DispId(1019)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - string url { - [DispId(1025)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } + /// IHTMLDocument2 interface. + [Guid("332C4425-26CB-11D0-B483-00C04FD90119")] + [ComImport] + [TypeLibType(TypeLibTypeFlags.FDual)] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLDocument2 { + IHTMLElement body { + [DispId(1004)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + string title { + [DispId(1012)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + object frames { + [DispId(1019)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + string url { + [DispId(1025)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + IHTMLWindow2 parentWindow { + [DispId(1034)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } - IHTMLWindow2 parentWindow { - [DispId(1034)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } + object bgColor { + [DispId(-501)] + get; + } - object bgColor { - [DispId(-501)] - get; - } + IHTMLSelectionObject selection { + [DispId(1017)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } - IHTMLSelectionObject selection { - [DispId(1017)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - - } + string designMode { + [DispId(1014)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + [DispId(1014)] + set; + } + } } diff --git a/Greenshot/Helpers/IEInterop/IHTMLDocument3.cs b/Greenshot/Helpers/IEInterop/IHTMLDocument3.cs index a87d38017..93a72ccae 100644 --- a/Greenshot/Helpers/IEInterop/IHTMLDocument3.cs +++ b/Greenshot/Helpers/IEInterop/IHTMLDocument3.cs @@ -20,31 +20,28 @@ */ using System; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using System.Collections; namespace Greenshot.Helpers.IEInterop { - /// IHTMLDocument3 interface. - [Guid("3050F485-98B5-11CF-BB82-00AA00BDCE0B")] - [ComImport] - [TypeLibType(TypeLibTypeFlags.FDual)] - [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLDocument3 { - IHTMLElement documentElement { - [DispId(1075)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } + /// IHTMLDocument3 interface. + [Guid("3050F485-98B5-11CF-BB82-00AA00BDCE0B")] + [ComImport] + [TypeLibType(TypeLibTypeFlags.FDual)] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLDocument3 { + IHTMLElement documentElement { + [DispId(1075)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } - [DispId(1086)] - [return: MarshalAs(UnmanagedType.IDispatch)] - IHTMLElementCollection getElementsByName([MarshalAs(UnmanagedType.BStr)] string v); + [DispId(1086)] + [return: MarshalAs(UnmanagedType.IDispatch)] + IHTMLElementCollection getElementsByName([MarshalAs(UnmanagedType.BStr)] string v); - [DispId(1088)] - IHTMLElement getElementById([MarshalAs(UnmanagedType.BStr)] string v); + [DispId(1088)] + IHTMLElement getElementById([MarshalAs(UnmanagedType.BStr)] string v); - [DispId(1087)] - - IHTMLElementCollection getElementsByTagName([MarshalAs(UnmanagedType.BStr)] string v); - } + [DispId(1087)] + IHTMLElementCollection getElementsByTagName([MarshalAs(UnmanagedType.BStr)] string v); + } } \ No newline at end of file diff --git a/Greenshot/Helpers/IEInterop/IHTMLDocument4.cs b/Greenshot/Helpers/IEInterop/IHTMLDocument4.cs index 2485b2c97..d2489a721 100644 --- a/Greenshot/Helpers/IEInterop/IHTMLDocument4.cs +++ b/Greenshot/Helpers/IEInterop/IHTMLDocument4.cs @@ -20,8 +20,6 @@ */ using System; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using System.Collections; namespace Greenshot.Helpers.IEInterop { [ComVisible(true), Guid("3050f69a-98b5-11cf-bb82-00aa00bdce0b"), diff --git a/Greenshot/Helpers/IEInterop/IHTMLDocument5.cs b/Greenshot/Helpers/IEInterop/IHTMLDocument5.cs index 75e96326c..a5a125e63 100644 --- a/Greenshot/Helpers/IEInterop/IHTMLDocument5.cs +++ b/Greenshot/Helpers/IEInterop/IHTMLDocument5.cs @@ -20,8 +20,6 @@ */ using System; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using System.Collections; namespace Greenshot.Helpers.IEInterop { [ComImport, ComVisible(true), Guid("3050f80c-98b5-11cf-bb82-00aa00bdce0b"), diff --git a/Greenshot/Helpers/IEInterop/IHTMLElement.cs b/Greenshot/Helpers/IEInterop/IHTMLElement.cs index 98eaa625d..10a54ede6 100644 --- a/Greenshot/Helpers/IEInterop/IHTMLElement.cs +++ b/Greenshot/Helpers/IEInterop/IHTMLElement.cs @@ -19,9 +19,7 @@ * along with this program. If not, see . */ using System; -using System.Collections; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; namespace Greenshot.Helpers.IEInterop { [ComImport, Guid("3050F1FF-98B5-11CF-BB82-00AA00BDCE0B"), @@ -109,5 +107,11 @@ namespace Greenshot.Helpers.IEInterop { [DispId(-2147417093)] void scrollIntoView(bool varargStart); + + IHTMLElementCollection children { + [DispId(-2147417075)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } } } \ No newline at end of file diff --git a/Greenshot/Helpers/IEInterop/IHTMLElement2.cs b/Greenshot/Helpers/IEInterop/IHTMLElement2.cs index 735adaf40..7a30d2d47 100644 --- a/Greenshot/Helpers/IEInterop/IHTMLElement2.cs +++ b/Greenshot/Helpers/IEInterop/IHTMLElement2.cs @@ -19,17 +19,21 @@ * along with this program. If not, see . */ using System; -using System.Collections; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; namespace Greenshot.Helpers.IEInterop { [ComImport, Guid("3050F434-98B5-11CF-BB82-00AA00BDCE0B"), TypeLibType(TypeLibTypeFlags.FDual), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)] public interface IHTMLElement2 { - [DispId(-2147417067)] - [return: MarshalAs(UnmanagedType.IDispatch)] - IHTMLRect getBoundingClientRect(); + [DispId(-2147417067)] + [return: MarshalAs(UnmanagedType.IDispatch)] + IHTMLRect getBoundingClientRect(); + + IHTMLCurrentStyle currentStyle { + [DispId(-2147417105)] + [return: MarshalAs(UnmanagedType.Interface)] //IHTMLCurrentStyle + get; + } } } \ No newline at end of file diff --git a/Greenshot/Helpers/IEInterop/IHTMLElementCollection.cs b/Greenshot/Helpers/IEInterop/IHTMLElementCollection.cs index 973c8d7bb..34d261051 100644 --- a/Greenshot/Helpers/IEInterop/IHTMLElementCollection.cs +++ b/Greenshot/Helpers/IEInterop/IHTMLElementCollection.cs @@ -19,9 +19,8 @@ * along with this program. If not, see . */ using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; using System.Collections; +using System.Runtime.InteropServices; namespace Greenshot.Helpers.IEInterop { [ComImport(), ComVisible(true), diff --git a/Greenshot/Helpers/IEInterop/IHTMLFramesCollection2.cs b/Greenshot/Helpers/IEInterop/IHTMLFramesCollection2.cs index b1f0b720b..86f5a4003 100644 --- a/Greenshot/Helpers/IEInterop/IHTMLFramesCollection2.cs +++ b/Greenshot/Helpers/IEInterop/IHTMLFramesCollection2.cs @@ -20,8 +20,6 @@ */ using System; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using System.Collections; namespace Greenshot.Helpers.IEInterop { [ComImport(), ComVisible(true), diff --git a/Greenshot/Helpers/IEInterop/IHTMLRect.cs b/Greenshot/Helpers/IEInterop/IHTMLRect.cs index d0ada2f00..b351d68df 100644 --- a/Greenshot/Helpers/IEInterop/IHTMLRect.cs +++ b/Greenshot/Helpers/IEInterop/IHTMLRect.cs @@ -20,7 +20,6 @@ */ using System; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; namespace Greenshot.Helpers.IEInterop { [ComImport, Guid("3050F4A3-98B5-11CF-BB82-00AA00BDCE0B"), diff --git a/Greenshot/Helpers/IEInterop/IHTMLScreen.cs b/Greenshot/Helpers/IEInterop/IHTMLScreen.cs index c86dd2927..65aade596 100644 --- a/Greenshot/Helpers/IEInterop/IHTMLScreen.cs +++ b/Greenshot/Helpers/IEInterop/IHTMLScreen.cs @@ -20,8 +20,6 @@ */ using System; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using System.Collections; namespace Greenshot.Helpers.IEInterop { [ComImport, Guid("3050F35C-98B5-11CF-BB82-00AA00BDCE0B"), diff --git a/Greenshot/Helpers/IEInterop/IHTMLScreen2.cs b/Greenshot/Helpers/IEInterop/IHTMLScreen2.cs index aa135c787..5dafeb734 100644 --- a/Greenshot/Helpers/IEInterop/IHTMLScreen2.cs +++ b/Greenshot/Helpers/IEInterop/IHTMLScreen2.cs @@ -20,8 +20,6 @@ */ using System; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using System.Collections; namespace Greenshot.Helpers.IEInterop { [ComImport, Guid("3050F84A-98B5-11CF-BB82-00AA00BDCE0B"), diff --git a/Greenshot/Helpers/IEInterop/IHTMLSelectionObject.cs b/Greenshot/Helpers/IEInterop/IHTMLSelectionObject.cs index a3d3fcebb..b778d4328 100644 --- a/Greenshot/Helpers/IEInterop/IHTMLSelectionObject.cs +++ b/Greenshot/Helpers/IEInterop/IHTMLSelectionObject.cs @@ -20,7 +20,6 @@ */ using System; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; namespace Greenshot.Helpers.IEInterop { // See: http://msdn.microsoft.com/en-us/library/aa768849%28v=vs.85%29.aspx diff --git a/Greenshot/Helpers/IEInterop/IHTMLStyle.cs b/Greenshot/Helpers/IEInterop/IHTMLStyle.cs index 58383d5d3..7714e6d87 100644 --- a/Greenshot/Helpers/IEInterop/IHTMLStyle.cs +++ b/Greenshot/Helpers/IEInterop/IHTMLStyle.cs @@ -19,9 +19,7 @@ * along with this program. If not, see . */ using System; -using System.Collections; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; namespace Greenshot.Helpers.IEInterop { [ComImport, Guid("3050F25E-98B5-11CF-BB82-00AA00BDCE0B"), @@ -994,493 +992,197 @@ namespace Greenshot.Helpers.IEInterop { } /// paddingRight property of IHTMLStyle interface. - /// An original IDL definition of paddingRight property was the following: VARIANT paddingRight; - // IDL: VARIANT paddingRight; - // VB6: paddingRight As Any - object paddingRight - { - // IDL: HRESULT paddingRight ([out, retval] VARIANT* ReturnValue); - // VB6: Function paddingRight As Any + object paddingRight { [DispId(-2147413099)] get; - // IDL: HRESULT paddingRight (VARIANT value); - // VB6: Sub paddingRight (ByVal value As Any) - [DispId(-2147413099)] - set; } /// paddingTop property of IHTMLStyle interface. - /// An original IDL definition of paddingTop property was the following: VARIANT paddingTop; - // IDL: VARIANT paddingTop; - // VB6: paddingTop As Any - object paddingTop - { - // IDL: HRESULT paddingTop ([out, retval] VARIANT* ReturnValue); - // VB6: Function paddingTop As Any + object paddingTop { [DispId(-2147413100)] get; - // IDL: HRESULT paddingTop (VARIANT value); - // VB6: Sub paddingTop (ByVal value As Any) - [DispId(-2147413100)] - set; } /// pageBreakAfter property of IHTMLStyle interface. - /// An original IDL definition of pageBreakAfter property was the following: BSTR pageBreakAfter; - // IDL: BSTR pageBreakAfter; - // VB6: pageBreakAfter As String - string pageBreakAfter - { - // IDL: HRESULT pageBreakAfter ([out, retval] BSTR* ReturnValue); - // VB6: Function pageBreakAfter As String + string pageBreakAfter { [DispId(-2147413034)] [return: MarshalAs(UnmanagedType.BStr)] get; - // IDL: HRESULT pageBreakAfter (BSTR value); - // VB6: Sub pageBreakAfter (ByVal value As String) - [DispId(-2147413034)] - set; } /// pageBreakBefore property of IHTMLStyle interface. - /// An original IDL definition of pageBreakBefore property was the following: BSTR pageBreakBefore; - // IDL: BSTR pageBreakBefore; - // VB6: pageBreakBefore As String - string pageBreakBefore - { - // IDL: HRESULT pageBreakBefore ([out, retval] BSTR* ReturnValue); - // VB6: Function pageBreakBefore As String + string pageBreakBefore { [DispId(-2147413035)] [return: MarshalAs(UnmanagedType.BStr)] get; - // IDL: HRESULT pageBreakBefore (BSTR value); - // VB6: Sub pageBreakBefore (ByVal value As String) - [DispId(-2147413035)] - set; } /// pixelHeight property of IHTMLStyle interface. - /// An original IDL definition of pixelHeight property was the following: long pixelHeight; - // IDL: long pixelHeight; - // VB6: pixelHeight As Long - int pixelHeight - { - // IDL: HRESULT pixelHeight ([out, retval] long* ReturnValue); - // VB6: Function pixelHeight As Long + int pixelHeight { [DispId(-2147414109)] get; - // IDL: HRESULT pixelHeight (long value); - // VB6: Sub pixelHeight (ByVal value As Long) - [DispId(-2147414109)] - set; } /// pixelLeft property of IHTMLStyle interface. - /// An original IDL definition of pixelLeft property was the following: long pixelLeft; - // IDL: long pixelLeft; - // VB6: pixelLeft As Long - int pixelLeft - { - // IDL: HRESULT pixelLeft ([out, retval] long* ReturnValue); - // VB6: Function pixelLeft As Long + int pixelLeft { [DispId(-2147414111)] get; - // IDL: HRESULT pixelLeft (long value); - // VB6: Sub pixelLeft (ByVal value As Long) - [DispId(-2147414111)] - set; } /// pixelTop property of IHTMLStyle interface. - /// An original IDL definition of pixelTop property was the following: long pixelTop; - // IDL: long pixelTop; - // VB6: pixelTop As Long - int pixelTop - { - // IDL: HRESULT pixelTop ([out, retval] long* ReturnValue); - // VB6: Function pixelTop As Long + int pixelTop { [DispId(-2147414112)] get; - // IDL: HRESULT pixelTop (long value); - // VB6: Sub pixelTop (ByVal value As Long) - [DispId(-2147414112)] - set; } /// pixelWidth property of IHTMLStyle interface. - /// An original IDL definition of pixelWidth property was the following: long pixelWidth; - // IDL: long pixelWidth; - // VB6: pixelWidth As Long - int pixelWidth - { - // IDL: HRESULT pixelWidth ([out, retval] long* ReturnValue); - // VB6: Function pixelWidth As Long + int pixelWidth { [DispId(-2147414110)] get; - // IDL: HRESULT pixelWidth (long value); - // VB6: Sub pixelWidth (ByVal value As Long) - [DispId(-2147414110)] - set; } /// posHeight property of IHTMLStyle interface. - /// An original IDL definition of posHeight property was the following: float posHeight; - // IDL: float posHeight; - // VB6: posHeight As Single - float posHeight - { - // IDL: HRESULT posHeight ([out, retval] float* ReturnValue); - // VB6: Function posHeight As Single + float posHeight { [DispId(-2147414105)] get; - // IDL: HRESULT posHeight (float value); - // VB6: Sub posHeight (ByVal value As Single) - [DispId(-2147414105)] - set; } /// position property of IHTMLStyle interface. - /// An original IDL definition of position property was the following: BSTR position; - // IDL: BSTR position; - // VB6: position As String - string position - { - // IDL: HRESULT position ([out, retval] BSTR* ReturnValue); - // VB6: Function position As String + string position { [DispId(-2147413022)] [return: MarshalAs(UnmanagedType.BStr)] get; } /// posLeft property of IHTMLStyle interface. - /// An original IDL definition of posLeft property was the following: float posLeft; - // IDL: float posLeft; - // VB6: posLeft As Single - float posLeft - { - // IDL: HRESULT posLeft ([out, retval] float* ReturnValue); - // VB6: Function posLeft As Single + float posLeft { [DispId(-2147414107)] get; - // IDL: HRESULT posLeft (float value); - // VB6: Sub posLeft (ByVal value As Single) - [DispId(-2147414107)] - set; } /// posTop property of IHTMLStyle interface. - /// An original IDL definition of posTop property was the following: float posTop; - // IDL: float posTop; - // VB6: posTop As Single - float posTop - { - // IDL: HRESULT posTop ([out, retval] float* ReturnValue); - // VB6: Function posTop As Single + float posTop { [DispId(-2147414108)] get; - // IDL: HRESULT posTop (float value); - // VB6: Sub posTop (ByVal value As Single) - [DispId(-2147414108)] - set; } /// posWidth property of IHTMLStyle interface. - /// An original IDL definition of posWidth property was the following: float posWidth; - // IDL: float posWidth; - // VB6: posWidth As Single - float posWidth - { - // IDL: HRESULT posWidth ([out, retval] float* ReturnValue); - // VB6: Function posWidth As Single + float posWidth { [DispId(-2147414106)] get; - // IDL: HRESULT posWidth (float value); - // VB6: Sub posWidth (ByVal value As Single) - [DispId(-2147414106)] - set; } /// styleFloat property of IHTMLStyle interface. - /// An original IDL definition of styleFloat property was the following: BSTR styleFloat; - // IDL: BSTR styleFloat; - // VB6: styleFloat As String - string styleFloat - { - // IDL: HRESULT styleFloat ([out, retval] BSTR* ReturnValue); - // VB6: Function styleFloat As String + string styleFloat { [DispId(-2147413042)] [return: MarshalAs(UnmanagedType.BStr)] get; - // IDL: HRESULT styleFloat (BSTR value); - // VB6: Sub styleFloat (ByVal value As String) - [DispId(-2147413042)] - set; } /// textAlign property of IHTMLStyle interface. - /// An original IDL definition of textAlign property was the following: BSTR textAlign; - // IDL: BSTR textAlign; - // VB6: textAlign As String - string textAlign - { - // IDL: HRESULT textAlign ([out, retval] BSTR* ReturnValue); - // VB6: Function textAlign As String + string textAlign { [DispId(-2147418040)] [return: MarshalAs(UnmanagedType.BStr)] get; - // IDL: HRESULT textAlign (BSTR value); - // VB6: Sub textAlign (ByVal value As String) - [DispId(-2147418040)] - set; } /// textDecoration property of IHTMLStyle interface. - /// An original IDL definition of textDecoration property was the following: BSTR textDecoration; - // IDL: BSTR textDecoration; - // VB6: textDecoration As String - string textDecoration - { - // IDL: HRESULT textDecoration ([out, retval] BSTR* ReturnValue); - // VB6: Function textDecoration As String + string textDecoration { [DispId(-2147413077)] [return: MarshalAs(UnmanagedType.BStr)] get; - // IDL: HRESULT textDecoration (BSTR value); - // VB6: Sub textDecoration (ByVal value As String) - [DispId(-2147413077)] - set; } /// textDecorationBlink property of IHTMLStyle interface. - /// An original IDL definition of textDecorationBlink property was the following: VARIANT_BOOL textDecorationBlink; - // IDL: VARIANT_BOOL textDecorationBlink; - // VB6: textDecorationBlink As Boolean - bool textDecorationBlink - { - // IDL: HRESULT textDecorationBlink ([out, retval] VARIANT_BOOL* ReturnValue); - // VB6: Function textDecorationBlink As Boolean + bool textDecorationBlink { [DispId(-2147413090)] [return: MarshalAs(UnmanagedType.VariantBool)] get; - // IDL: HRESULT textDecorationBlink (VARIANT_BOOL value); - // VB6: Sub textDecorationBlink (ByVal value As Boolean) - [DispId(-2147413090)] - set; } /// textDecorationLineThrough property of IHTMLStyle interface. - /// An original IDL definition of textDecorationLineThrough property was the following: VARIANT_BOOL textDecorationLineThrough; - // IDL: VARIANT_BOOL textDecorationLineThrough; - // VB6: textDecorationLineThrough As Boolean - bool textDecorationLineThrough - { - // IDL: HRESULT textDecorationLineThrough ([out, retval] VARIANT_BOOL* ReturnValue); - // VB6: Function textDecorationLineThrough As Boolean + bool textDecorationLineThrough { [DispId(-2147413092)] [return: MarshalAs(UnmanagedType.VariantBool)] get; - // IDL: HRESULT textDecorationLineThrough (VARIANT_BOOL value); - // VB6: Sub textDecorationLineThrough (ByVal value As Boolean) - [DispId(-2147413092)] - set; } /// textDecorationNone property of IHTMLStyle interface. - /// An original IDL definition of textDecorationNone property was the following: VARIANT_BOOL textDecorationNone; - // IDL: VARIANT_BOOL textDecorationNone; - // VB6: textDecorationNone As Boolean - bool textDecorationNone - { - // IDL: HRESULT textDecorationNone ([out, retval] VARIANT_BOOL* ReturnValue); - // VB6: Function textDecorationNone As Boolean + bool textDecorationNone { [DispId(-2147413089)] [return: MarshalAs(UnmanagedType.VariantBool)] get; - // IDL: HRESULT textDecorationNone (VARIANT_BOOL value); - // VB6: Sub textDecorationNone (ByVal value As Boolean) - [DispId(-2147413089)] - set; } /// textDecorationOverline property of IHTMLStyle interface. - /// An original IDL definition of textDecorationOverline property was the following: VARIANT_BOOL textDecorationOverline; - // IDL: VARIANT_BOOL textDecorationOverline; - // VB6: textDecorationOverline As Boolean - bool textDecorationOverline - { - // IDL: HRESULT textDecorationOverline ([out, retval] VARIANT_BOOL* ReturnValue); - // VB6: Function textDecorationOverline As Boolean + bool textDecorationOverline { [DispId(-2147413043)] [return: MarshalAs(UnmanagedType.VariantBool)] get; - // IDL: HRESULT textDecorationOverline (VARIANT_BOOL value); - // VB6: Sub textDecorationOverline (ByVal value As Boolean) - [DispId(-2147413043)] - set; } /// textDecorationUnderline property of IHTMLStyle interface. - /// An original IDL definition of textDecorationUnderline property was the following: VARIANT_BOOL textDecorationUnderline; - // IDL: VARIANT_BOOL textDecorationUnderline; - // VB6: textDecorationUnderline As Boolean - bool textDecorationUnderline - { - // IDL: HRESULT textDecorationUnderline ([out, retval] VARIANT_BOOL* ReturnValue); - // VB6: Function textDecorationUnderline As Boolean + bool textDecorationUnderline { [DispId(-2147413091)] [return: MarshalAs(UnmanagedType.VariantBool)] get; - // IDL: HRESULT textDecorationUnderline (VARIANT_BOOL value); - // VB6: Sub textDecorationUnderline (ByVal value As Boolean) - [DispId(-2147413091)] - set; } /// textIndent property of IHTMLStyle interface. - /// An original IDL definition of textIndent property was the following: VARIANT textIndent; - // IDL: VARIANT textIndent; - // VB6: textIndent As Any - object textIndent - { - // IDL: HRESULT textIndent ([out, retval] VARIANT* ReturnValue); - // VB6: Function textIndent As Any + object textIndent { [DispId(-2147413105)] get; - // IDL: HRESULT textIndent (VARIANT value); - // VB6: Sub textIndent (ByVal value As Any) - [DispId(-2147413105)] - set; } /// textTransform property of IHTMLStyle interface. - /// An original IDL definition of textTransform property was the following: BSTR textTransform; - // IDL: BSTR textTransform; - // VB6: textTransform As String - string textTransform - { - // IDL: HRESULT textTransform ([out, retval] BSTR* ReturnValue); - // VB6: Function textTransform As String + string textTransform { [DispId(-2147413108)] [return: MarshalAs(UnmanagedType.BStr)] get; - // IDL: HRESULT textTransform (BSTR value); - // VB6: Sub textTransform (ByVal value As String) - [DispId(-2147413108)] - set; } /// top property of IHTMLStyle interface. - /// An original IDL definition of top property was the following: VARIANT top; - // IDL: VARIANT top; - // VB6: top As Any - object top - { - // IDL: HRESULT top ([out, retval] VARIANT* ReturnValue); - // VB6: Function top As Any + object top { [DispId(-2147418108)] get; - // IDL: HRESULT top (VARIANT value); - // VB6: Sub top (ByVal value As Any) - [DispId(-2147418108)] - set; } /// verticalAlign property of IHTMLStyle interface. - /// An original IDL definition of verticalAlign property was the following: VARIANT verticalAlign; - // IDL: VARIANT verticalAlign; - // VB6: verticalAlign As Any - object verticalAlign - { - // IDL: HRESULT verticalAlign ([out, retval] VARIANT* ReturnValue); - // VB6: Function verticalAlign As Any + object verticalAlign { [DispId(-2147413064)] get; - // IDL: HRESULT verticalAlign (VARIANT value); - // VB6: Sub verticalAlign (ByVal value As Any) - [DispId(-2147413064)] - set; } /// visibility property of IHTMLStyle interface. - /// An original IDL definition of visibility property was the following: BSTR visibility; - // IDL: BSTR visibility; - // VB6: visibility As String - string visibility - { - // IDL: HRESULT visibility ([out, retval] BSTR* ReturnValue); - // VB6: Function visibility As String + string visibility { [DispId(-2147413032)] [return: MarshalAs(UnmanagedType.BStr)] get; - // IDL: HRESULT visibility (BSTR value); - // VB6: Sub visibility (ByVal value As String) - [DispId(-2147413032)] - set; } /// whiteSpace property of IHTMLStyle interface. - /// An original IDL definition of whiteSpace property was the following: BSTR whiteSpace; - // IDL: BSTR whiteSpace; - // VB6: whiteSpace As String - string whiteSpace - { - // IDL: HRESULT whiteSpace ([out, retval] BSTR* ReturnValue); - // VB6: Function whiteSpace As String + string whiteSpace { [DispId(-2147413036)] [return: MarshalAs(UnmanagedType.BStr)] get; - // IDL: HRESULT whiteSpace (BSTR value); - // VB6: Sub whiteSpace (ByVal value As String) - [DispId(-2147413036)] - set; } /// width property of IHTMLStyle interface. - /// An original IDL definition of width property was the following: VARIANT width; - // IDL: VARIANT width; - // VB6: width As Any - object width - { - // IDL: HRESULT width ([out, retval] VARIANT* ReturnValue); - // VB6: Function width As Any + object width { [DispId(-2147418107)] get; - // IDL: HRESULT width (VARIANT value); - // VB6: Sub width (ByVal value As Any) - [DispId(-2147418107)] - set; } /// wordSpacing property of IHTMLStyle interface. - /// An original IDL definition of wordSpacing property was the following: VARIANT wordSpacing; - // IDL: VARIANT wordSpacing; - // VB6: wordSpacing As Any - object wordSpacing - { - // IDL: HRESULT wordSpacing ([out, retval] VARIANT* ReturnValue); - // VB6: Function wordSpacing As Any + object wordSpacing { [DispId(-2147413065)] get; - // IDL: HRESULT wordSpacing (VARIANT value); - // VB6: Sub wordSpacing (ByVal value As Any) - [DispId(-2147413065)] - set; } /// zIndex property of IHTMLStyle interface. - /// An original IDL definition of zIndex property was the following: VARIANT zIndex; - // IDL: VARIANT zIndex; - // VB6: zIndex As Any - object zIndex - { - // IDL: HRESULT zIndex ([out, retval] VARIANT* ReturnValue); - // VB6: Function zIndex As Any + object zIndex { [DispId(-2147413021)] get; - // IDL: HRESULT zIndex (VARIANT value); - // VB6: Sub zIndex (ByVal value As Any) - [DispId(-2147413021)] - set; } } } diff --git a/Greenshot/Helpers/IEInterop/IHTMLTxtRange.cs b/Greenshot/Helpers/IEInterop/IHTMLTxtRange.cs index 1c2a712f8..e3a32e683 100644 --- a/Greenshot/Helpers/IEInterop/IHTMLTxtRange.cs +++ b/Greenshot/Helpers/IEInterop/IHTMLTxtRange.cs @@ -20,7 +20,6 @@ */ using System; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; namespace Greenshot.Helpers.IEInterop { // See: http://msdn.microsoft.com/en-us/library/aa741548%28v=vs.85%29.aspx diff --git a/Greenshot/Helpers/IEInterop/IHTMLWindow2.cs b/Greenshot/Helpers/IEInterop/IHTMLWindow2.cs index 23970bafa..9d5472799 100644 --- a/Greenshot/Helpers/IEInterop/IHTMLWindow2.cs +++ b/Greenshot/Helpers/IEInterop/IHTMLWindow2.cs @@ -20,8 +20,6 @@ */ using System; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using System.Collections; namespace Greenshot.Helpers.IEInterop { [ComVisible(true), ComImport(), Guid("332c4427-26cb-11d0-b483-00c04fd90119"), diff --git a/Greenshot/Helpers/IEInterop/IHTMLWindow3.cs b/Greenshot/Helpers/IEInterop/IHTMLWindow3.cs index 2e7e8fd98..f5f6f2204 100644 --- a/Greenshot/Helpers/IEInterop/IHTMLWindow3.cs +++ b/Greenshot/Helpers/IEInterop/IHTMLWindow3.cs @@ -20,7 +20,6 @@ */ using System; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; namespace Greenshot.Helpers.IEInterop { [ComVisible(true), ComImport(), Guid("3050f4ae-98b5-11cf-bb82-00aa00bdce0b"), diff --git a/Greenshot/Helpers/IEInterop/IOleWindow.cs b/Greenshot/Helpers/IEInterop/IOleWindow.cs index d0184ec14..44bed75d7 100644 --- a/Greenshot/Helpers/IEInterop/IOleWindow.cs +++ b/Greenshot/Helpers/IEInterop/IOleWindow.cs @@ -20,8 +20,6 @@ */ using System; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using System.Collections; namespace Greenshot.Helpers.IEInterop { // Needed to get the Window handle from the IDocument2 diff --git a/Greenshot/Helpers/IEInterop/IServiceProvider.cs b/Greenshot/Helpers/IEInterop/IServiceProvider.cs index c529994a8..9a70e0bb6 100644 --- a/Greenshot/Helpers/IEInterop/IServiceProvider.cs +++ b/Greenshot/Helpers/IEInterop/IServiceProvider.cs @@ -20,7 +20,6 @@ */ using System; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; namespace Greenshot.Helpers.IEInterop { // This is the COM IServiceProvider interface, not System.IServiceProvider .Net interface! diff --git a/Greenshot/Helpers/IEInterop/IWebBrowser2.cs b/Greenshot/Helpers/IEInterop/IWebBrowser2.cs index 62fbc816a..a09b3961b 100644 --- a/Greenshot/Helpers/IEInterop/IWebBrowser2.cs +++ b/Greenshot/Helpers/IEInterop/IWebBrowser2.cs @@ -20,8 +20,6 @@ */ using System; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using System.Collections; namespace Greenshot.Helpers.IEInterop { // IWebBrowser: EAB22AC1-30C1-11CF-A7EB-0000C05BAE0B diff --git a/Greenshot/Helpers/ImageOutput.cs b/Greenshot/Helpers/ImageOutput.cs index 4c87645de..5c7d0750b 100644 --- a/Greenshot/Helpers/ImageOutput.cs +++ b/Greenshot/Helpers/ImageOutput.cs @@ -19,7 +19,6 @@ * along with this program. If not, see . */ using System; -using System.Collections; using System.Drawing; using System.Drawing.Imaging; using System.IO; @@ -31,19 +30,17 @@ using Greenshot.Configuration; using Greenshot.Forms; using Greenshot.Plugin; using GreenshotPlugin.Core; +using IniFile; -namespace Greenshot.Helpers -{ +namespace Greenshot.Helpers { /// /// Description of ImageOutput. /// - public class ImageOutput { + public static class ImageOutput { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ImageOutput)); private static CoreConfiguration conf = IniConfig.GetIniSection(); private static readonly int PROPERTY_TAG_SOFTWARE_USED = 0x0131; - - private ImageOutput() { - } + private static CacheHelper tmpFileCache = new CacheHelper("tmpfile", 60*60*10, new CacheObjectExpired(RemoveExpiredTmpFile)); /// /// Creates a PropertyItem (Metadata) to store with the image. @@ -142,30 +139,10 @@ namespace Greenshot.Helpers } } - /// - /// Helper method to create a temp image file - /// - /// - /// - public static string SaveToTmpFile(Image image) { - string tmpFile = Path.Combine(Path.GetTempPath(),Path.GetRandomFileName() + "." + conf.OutputFileFormat.ToString()); - // Prevent problems with "spaces", which causes a problem in e.g. Outlook 2007 - tmpFile = tmpFile.Replace(" ", "_"); - tmpFile = tmpFile.Replace("%", "_"); - LOG.Debug("Creating TMP File : " + tmpFile); - - try { - ImageOutput.Save(image, tmpFile, conf.OutputFileJpegQuality, false); - } catch (Exception) { - return null; - } - return tmpFile; - } - /// /// Saves image to specific path with specified quality /// - public static void Save(Image image, string fullPath, int quality, bool copyPathToClipboard) { + public static void Save(Image image, string fullPath, bool allowOverwrite, int quality, bool copyPathToClipboard) { fullPath = FilenameHelper.MakeFQFilenameSafe(fullPath); string path = Path.GetDirectoryName(fullPath); @@ -186,6 +163,11 @@ namespace Greenshot.Helpers } catch(ArgumentException ae) { LOG.Warn("Couldn't parse extension: " + extension, ae); } + if (!allowOverwrite && File.Exists(fullPath)) { + ArgumentException throwingException = new ArgumentException("File '" + fullPath + "' already exists."); + throwingException.Data.Add("fullPath", fullPath); + throw throwingException; + } LOG.DebugFormat("Saving image to {0}", fullPath); // Create the stream and call SaveToStream using (FileStream stream = new FileStream(fullPath, FileMode.Create, FileAccess.Write)) { @@ -202,7 +184,8 @@ namespace Greenshot.Helpers /// /// the image to save /// the absolute destination path including file name - public static void Save(Image img, string fullPath) { + /// true if overwrite is allowed, false if not + public static void Save(Image img, string fullPath, bool allowOverwrite) { int q; // Fix for bug 2912959 @@ -219,7 +202,7 @@ namespace Greenshot.Helpers } else { q = conf.OutputFileJpegQuality; } - Save(img, fullPath, q, conf.OutputFileCopyPathToClipboard); + Save(img, fullPath, allowOverwrite, q, conf.OutputFileCopyPathToClipboard); } #endregion @@ -232,10 +215,11 @@ namespace Greenshot.Helpers string returnValue = null; SaveImageFileDialog saveImageFileDialog = new SaveImageFileDialog(captureDetails); DialogResult dialogResult = saveImageFileDialog.ShowDialog(); - if(dialogResult.Equals(DialogResult.OK)) { + if (dialogResult.Equals(DialogResult.OK)) { try { string fileNameWithExtension = saveImageFileDialog.FileNameWithExtension; - ImageOutput.Save(image, fileNameWithExtension); + // TODO: For now we overwrite, should be changed + ImageOutput.Save(image, fileNameWithExtension, true); returnValue = fileNameWithExtension; conf.OutputFileAsFullpath = fileNameWithExtension; IniConfig.Save(); @@ -246,5 +230,79 @@ namespace Greenshot.Helpers return returnValue; } #endregion + + public static string SaveNamedTmpFile(Image image, ICaptureDetails captureDetails, OutputFormat outputFormat, int quality) { + string pattern = conf.OutputFileFilenamePattern; + if (pattern == null || string.IsNullOrEmpty(pattern.Trim())) { + pattern = "greenshot ${capturetime}"; + } + string filename = FilenameHelper.GetFilenameFromPattern(pattern, outputFormat, captureDetails); + // Prevent problems with "other characters", which causes a problem in e.g. Outlook 2007 or break our HTML + filename = Regex.Replace(filename, @"[^\d\w\.]", "_"); + // Remove multiple "_" + filename = Regex.Replace(filename, @"_+", "_"); + string tmpFile = Path.Combine(Path.GetTempPath(),filename); + + LOG.Debug("Creating TMP File: " + tmpFile); + + // Catching any exception to prevent that the user can't write in the directory. + // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218 + try { + ImageOutput.Save(image, tmpFile, true, quality, false); + tmpFileCache.Add(tmpFile, tmpFile); + } catch (Exception e) { + // Show the problem + MessageBox.Show(e.Message, "Error"); + // when save failed we present a SaveWithDialog + tmpFile = ImageOutput.SaveWithDialog(image, captureDetails); + } + return tmpFile; + } + + /// + /// Helper method to create a temp image file + /// + /// + /// + public static string SaveToTmpFile(Image image, OutputFormat outputFormat, int quality) { + string tmpFile = Path.GetRandomFileName() + "." + outputFormat.ToString(); + // Prevent problems with "other characters", which could cause problems + tmpFile = Regex.Replace(tmpFile, @"[^\d\w\.]", ""); + string tmpPath = Path.Combine(Path.GetTempPath(), tmpFile); + LOG.Debug("Creating TMP File : " + tmpPath); + + try { + ImageOutput.Save(image, tmpPath, true, quality, false); + tmpFileCache.Add(tmpPath, tmpPath); + } catch (Exception) { + return null; + } + return tmpPath; + } + + /// + /// Cleanup all created tmpfiles + /// + public static void RemoveTmpFiles() { + foreach(string tmpFile in tmpFileCache.GetElements()) { + if (File.Exists(tmpFile)) { + LOG.DebugFormat("Removing old temp file {0}", tmpFile); + File.Delete(tmpFile); + } + } + } + + /// + /// Cleanup handler for expired tempfiles + /// + /// + /// + private static void RemoveExpiredTmpFile(string filekey, object filename) { + string path = filename as string; + if (path != null && File.Exists(path)) { + LOG.DebugFormat("Removing expired file {0}", path); + File.Delete(path); + } + } } } diff --git a/Greenshot/Helpers/LogHelper.cs b/Greenshot/Helpers/LogHelper.cs index 7b22c2b6a..faf5e6bc7 100644 --- a/Greenshot/Helpers/LogHelper.cs +++ b/Greenshot/Helpers/LogHelper.cs @@ -19,10 +19,18 @@ * along with this program. If not, see . */ using System; +using System.IO; +using System.Windows.Forms; namespace Greenshot.Helpers { public class SpecialFolderPatternConverter : log4net.Util.PatternConverter { protected override void Convert(System.IO.TextWriter writer, object state) { + // Making Greenshot portable + string pafPath = Path.Combine(Application.StartupPath, @"App\Greenshot"); + if (Directory.Exists(pafPath)) { + writer.Write(Path.Combine(Application.StartupPath, @"Data")); + return; + } Environment.SpecialFolder specialFolder = (Environment.SpecialFolder)Enum.Parse(typeof(Environment.SpecialFolder), base.Option, true); writer.Write(Environment.GetFolderPath(specialFolder)); } diff --git a/Greenshot/Helpers/MailHelper.cs b/Greenshot/Helpers/MailHelper.cs index ef52d7085..457105fc3 100644 --- a/Greenshot/Helpers/MailHelper.cs +++ b/Greenshot/Helpers/MailHelper.cs @@ -21,19 +21,17 @@ using System; using System.Collections; using System.Collections.Generic; -using System.ComponentModel; using System.Drawing; using System.IO; using System.Runtime.InteropServices; -using System.Text; +using System.Text.RegularExpressions; using System.Threading; using System.Windows.Forms; -using Greenshot.Configuration; using Greenshot.Helpers.OfficeInterop; using Greenshot.Plugin; using GreenshotPlugin.Core; -using Microsoft.Win32; +using IniFile; /// /// Author: Andrew Baker @@ -49,32 +47,16 @@ namespace Greenshot.Helpers { public class MapiMailMessage { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(MapiMailMessage)); private static CoreConfiguration conf = IniConfig.GetIniSection(); - private const string MAPI_LOCATION_KEY = @"SOFTWARE\Microsoft\Windows Messaging Subsystem"; - private const string MAPI_KEY = @"MAPI"; - - public static bool HasMAPI() { - using (RegistryKey key = Registry.LocalMachine.OpenSubKey(MAPI_LOCATION_KEY, false)) { - if (key != null) { - return "1".Equals(key.GetValue(MAPI_KEY, "0")); - } else { - return false; - } - } - } - - public static bool HasMAPIorOutlook() { - return OutlookExporter.HasOutlook() || HasMAPI(); - } /// /// Helper Method for creating an Email with Attachment /// /// Path to file /// - public static void SendImage(string fullPath, string title, bool deleteFileOnExit) { + public static void SendImage(string fullPath, string title) { MapiMailMessage message = new MapiMailMessage(title, null); message.Files.Add(fullPath); - message.ShowDialog(deleteFileOnExit); + message.ShowDialog(); } @@ -84,35 +66,19 @@ namespace Greenshot.Helpers { /// The image to send /// ICaptureDetails public static void SendImage(Image image, ICaptureDetails captureDetails) { - string pattern = conf.OutputFileFilenamePattern; - if (pattern == null || string.IsNullOrEmpty(pattern.Trim())) { - pattern = "greenshot ${capturetime}"; - } - string filename = FilenameHelper.GetFilenameFromPattern(pattern, conf.OutputFileFormat, captureDetails); - string tmpFile = Path.Combine(Path.GetTempPath(),filename); - // Prevent problems with "spaces", which causes a problem in e.g. Outlook 2007 - tmpFile = tmpFile.Replace(" ", "_"); - tmpFile = tmpFile.Replace("%", "_"); - LOG.Debug("Creating TMP File for Email: " + tmpFile); - - // Catching any exception to prevent that the user can't write in the directory. - // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218 - try { - ImageOutput.Save(image, tmpFile, conf.OutputFileJpegQuality, false); - } catch (Exception e) { - // Show the problem - MessageBox.Show(e.Message, "Error"); - // when save failed we present a SaveWithDialog - tmpFile = ImageOutput.SaveWithDialog(image, captureDetails); - } + string tmpFile = ImageOutput.SaveNamedTmpFile(image, captureDetails, conf.OutputFileFormat, conf.OutputFileJpegQuality); if (tmpFile != null) { // Store the list of currently active windows, so we can make sure we show the email window later! List windowsBefore = WindowDetails.GetVisibleWindows(); - if (!OutlookExporter.HasOutlook() || !OutlookExporter.ExportToOutlook(tmpFile, captureDetails)) { + bool isEmailSend = false; + //if (EmailConfigHelper.HasOutlook() && (conf.OutputEMailFormat == EmailFormat.OUTLOOK_HTML || conf.OutputEMailFormat == EmailFormat.OUTLOOK_TXT)) { + // isEmailSend = OutlookExporter.ExportToOutlook(tmpFile, captureDetails); + //} + if (!isEmailSend && EmailConfigHelper.HasMAPI()) { // Fallback to MAPI - // Send the email and Cleanup the tmp files on exit - SendImage(tmpFile, captureDetails.Title, true); + // Send the email + SendImage(tmpFile, captureDetails.Title); } WindowDetails.ActiveNewerWindows(windowsBefore); } @@ -232,13 +198,13 @@ namespace Greenshot.Helpers { /// /// Displays the mail message dialog asynchronously. /// - public void ShowDialog(bool deleteFilesOnExit) { + public void ShowDialog() { // Create the mail message in an STA thread - Thread t = new Thread(new ParameterizedThreadStart(_ShowMail)); + Thread t = new Thread(new ThreadStart(_ShowMail)); t.IsBackground = true; t.Name = Application.ProductName; t.SetApartmentState(ApartmentState.STA); - t.Start(deleteFilesOnExit); + t.Start(); // only return when the new thread has built it's interop representation _manualResetEvent.WaitOne(); @@ -252,7 +218,7 @@ namespace Greenshot.Helpers { /// /// Sends the mail message. /// - private void _ShowMail(object deleteFilesOnExit) { + private void _ShowMail() { MAPIHelperInterop.MapiMessage message = new MAPIHelperInterop.MapiMessage(); using (RecipientCollection.InteropRecipientCollection interopRecipients = _recipientCollection.GetInteropRepresentation()) { @@ -278,18 +244,6 @@ namespace Greenshot.Helpers { if (_files.Count > 0) { // Deallocate the files _DeallocFiles(message); - if ((bool)deleteFilesOnExit) { - foreach(string file in _files) { - try { - if (File.Exists(file)) { - LOG.Debug("Deleting file " + file); - File.Delete(file); - } - } catch (Exception e) { - LOG.Error("Can't delete file " + file, e); - } - } - } } MAPI_CODES errorCode = (MAPI_CODES)Enum.ToObject(typeof(MAPI_CODES), error); diff --git a/Greenshot/Helpers/OfficeInterop/ExcelWrapper.cs b/Greenshot/Helpers/OfficeInterop/ExcelWrapper.cs index 5768960be..8fcbea226 100644 --- a/Greenshot/Helpers/OfficeInterop/ExcelWrapper.cs +++ b/Greenshot/Helpers/OfficeInterop/ExcelWrapper.cs @@ -19,9 +19,9 @@ * along with this program. If not, see . */ using System; +using System.Collections.Generic; using System.Reflection; using Greenshot.Interop; -using Greenshot.Plugin; namespace Greenshot.Helpers.OfficeInterop { // See http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.application.aspx @@ -34,49 +34,96 @@ namespace Greenshot.Helpers.OfficeInterop { } // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.workbooks.aspx - public interface IWorkbooks : Common { + public interface IWorkbooks : Common, Collection { IWorkbook Add(object template); + IWorkbook this[object Index] { get; } } - // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.document.aspx + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.workbook.aspx public interface IWorkbook : Common { IWorksheet ActiveSheet {get;} + string Name { get; } + void Activate(); + IWorksheets Worksheets { get; } } + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel._worksheet_members.aspx public interface IWorksheet : Common { IPictures Pictures {get;} + string Name { get; } } - public interface IPictures : Common { + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.iworksheets_members.aspx + public interface IWorksheets : Common, Collection { + Object this[object Index] { get; } + } + + public interface IPictures : Common, Collection { void Insert(string file); } public class ExcelExporter { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ExcelExporter)); - private static IExcelApplication ExcelApplication() { + private static IExcelApplication GetOrCreateExcelApplication() { return (IExcelApplication)COMWrapper.GetOrCreateInstance(typeof(IExcelApplication)); } - public static void InsertIntoExistingWorkbook(IWorkbook workbook, string tmpFile) { - workbook.ActiveSheet.Pictures.Insert(tmpFile); + private static IExcelApplication GetExcelApplication() { + return (IExcelApplication)COMWrapper.GetInstance(typeof(IExcelApplication)); } - private static void InsertIntoNewWorkbook(IExcelApplication excelApplication, string tmpFile) { - LOG.Debug("No workbook, creating a new workbook"); - object template = Missing.Value; - IWorkbook workbook = excelApplication.Workbooks.Add(template); - InsertIntoExistingWorkbook(workbook, tmpFile); + public static List GetWorkbooks() { + List currentWorkbooks = new List(); + using( IExcelApplication excelApplication = GetExcelApplication() ) { + if (excelApplication != null) { + for(int i = 1; i <= excelApplication.Workbooks.Count ; i ++) { + IWorkbook workbook = excelApplication.Workbooks[i]; + if (workbook != null) { + currentWorkbooks.Add(workbook.Name); + } + } + } + } + return currentWorkbooks; } - public static void ExportToExcel(string tmpFile) { - using( IExcelApplication excelApplication = ExcelApplication() ) { + /// + /// Insert image from supplied tmp file into the give excel workbook + /// + /// + /// + public static void InsertIntoExistingWorkbook(string workbookName, string tmpFile) { + using( IExcelApplication excelApplication = GetExcelApplication() ) { + if (excelApplication != null) { + for(int i = 1; i <= excelApplication.Workbooks.Count ; i ++) { + IWorkbook workbook = excelApplication.Workbooks[i]; + if (workbook != null && workbook.Name.StartsWith(workbookName)) { + InsertIntoExistingWorkbook(workbook, tmpFile); + } + } + } + } + } + + private static void InsertIntoExistingWorkbook(IWorkbook workbook, string tmpFile) { + IWorksheet sheet = workbook.ActiveSheet; + if (sheet != null) { + if (sheet.Pictures != null) { + sheet.Pictures.Insert(tmpFile); + } + } else { + LOG.Error("No pictures found"); + } + } + + public static void InsertIntoNewWorkbook(string tmpFile) { + using( IExcelApplication excelApplication = GetOrCreateExcelApplication() ) { if (excelApplication != null) { excelApplication.Visible = true; - if (excelApplication.ActiveWorkbook != null) { - InsertIntoExistingWorkbook(excelApplication.ActiveWorkbook, tmpFile); - } else { - InsertIntoNewWorkbook(excelApplication, tmpFile); - } - return; + object template = Missing.Value; + IWorkbook workbook = excelApplication.Workbooks.Add(template); + InsertIntoExistingWorkbook(workbook, tmpFile); } } } diff --git a/Greenshot/Helpers/OfficeInterop/OfficeWrappers.cs b/Greenshot/Helpers/OfficeInterop/OfficeWrappers.cs index b5807f6e3..8eb013ec8 100644 --- a/Greenshot/Helpers/OfficeInterop/OfficeWrappers.cs +++ b/Greenshot/Helpers/OfficeInterop/OfficeWrappers.cs @@ -20,7 +20,6 @@ */ using System; using System.Collections; -using Greenshot.Interop; namespace Greenshot.Helpers.OfficeInterop { /// @@ -29,15 +28,14 @@ namespace Greenshot.Helpers.OfficeInterop { public interface Common : IDisposable { } - public interface Collection : Common, IEnumerable - { + public interface Collection : Common, IEnumerable { int Count { get; } void Remove( int index ); } public interface Items : Collection, IEnumerable { - object this[ object index ] { get; } + Item this[ object index ] { get; } object GetFirst(); object GetLast(); @@ -45,9 +43,11 @@ namespace Greenshot.Helpers.OfficeInterop { object Add( OlItemType type ); } + // See: http://msdn.microsoft.com/en-us/library/ff861252.aspx public interface Item : Common { Attachments Attachments { get; } string Body { get; set; } + OlObjectClass Class { get; } DateTime CreationTime { get; } string EntryID { get; } DateTime LastModificationTime { get; } @@ -69,46 +69,28 @@ namespace Greenshot.Helpers.OfficeInterop { string SenderName { get; } DateTime SentOn { get; } OlBodyFormat BodyFormat { get; set; } + PropertyAccessor PropertyAccessor { get; } + bool Sent { get; } + object MAPIOBJECT { get; } } public interface Attachments : Collection { Attachment Add( object source, object type, object position, object displayName ); } + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.attachment_members.aspx public interface Attachment : Common { string DisplayName { get;set; } - string FileName { get;} - OlAttachmentType Type { get;} + string FileName { get; } + OlAttachmentType Type { get; } + PropertyAccessor PropertyAccessor { get; } + object MAPIOBJECT { get; } } - - // See: http://msdn.microsoft.com/en-us/library/ff861252.aspx - public interface MailItem : Item { - MailItem Forward(); - MailItem Reply(); - bool Sent { get; } - } - - // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.inspector_members.aspx - public interface Inspector : Common { - object CurrentItem { get; } - OlEditorType EditorType { get; } - object ModifiedFormPages { get; } - void Close(OlInspectorClose SaveMode); - void Display(object Modal); - void HideFormPage(string PageName); - bool IsWordMail(); - void SetCurrentFormPage(string PageName); - void ShowFormPage(string PageName); - object HTMLEditor { get; } - IWordDocument WordEditor { get; } - string Caption { get; } - int Height { get; set; } - int Left { get; set; } - int Top { get; set; } - int Width { get; set; } - OlWindowState WindowState { get; set; } - void Activate(); - void SetControlItemProperty(object Control, string PropertyName); + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.propertyaccessor_members.aspx + public interface PropertyAccessor : Common { + void SetProperty(string SchemaName, Object Value); + Object GetProperty(string SchemaName); } public enum OlBodyFormat { @@ -134,6 +116,153 @@ namespace Greenshot.Helpers.OfficeInterop { olPersonal = 1, olPrivate = 2 } + + // See: http://msdn.microsoft.com/en-us/library/ff863329.aspx + public enum OlObjectClass { + olAccount = 105 , // Represents an Account object. + olAccountRuleCondition = 135 , // Represents an AccountRuleCondition object. + olAccounts = 106 , // Represents an Accounts object. + olAction = 32 , // Represents an Action object. + olActions = 33 , // Represents an Actions object. + olAddressEntries = 21 , // Represents an AddressEntries object. + olAddressEntry = 8 , // Represents an AddressEntry object. + olAddressList = 7 , // Represents an AddressList object. + olAddressLists = 20 , // Represents an AddressLists object. + olAddressRuleCondition = 170 , // Represents an AddressRuleCondition object. + olApplication = 0 , // Represents an Application object. + olAppointment = 26 , // Represents an AppointmentItem object. + olAssignToCategoryRuleAction = 122 , // Represents an AssignToCategoryRuleAction object. + olAttachment = 5 , // Represents an Attachment object. + olAttachments = 18 , // Represents an Attachments object. + olAttachmentSelection = 169 , // Represents an AttachmentSelection object. + olAutoFormatRule = 147 , // Represents an AutoFormatRule object. + olAutoFormatRules = 148 , // Represents an AutoFormatRules object. + olCalendarModule = 159 , // Represents a CalendarModule object. + olCalendarSharing = 151 , // Represents a CalendarSharing object. + olCategories = 153 , // Represents a Categories object. + olCategory = 152 , // Represents a Category object. + olCategoryRuleCondition = 130 , // Represents a CategoryRuleCondition object. + olClassBusinessCardView = 168 , // Represents a BusinessCardView object. + olClassCalendarView = 139 , // Represents a CalendarView object. + olClassCardView = 138 , // Represents a CardView object. + olClassIconView = 137 , // Represents a IconView object. + olClassNavigationPane = 155 , // Represents a NavigationPane object. + olClassTableView = 136 , // Represents a TableView object. + olClassTimeLineView = 140 , // Represents a TimelineView object. + olClassTimeZone = 174 , // Represents a TimeZone object. + olClassTimeZones = 175 , // Represents a TimeZones object. + olColumn = 154 , // Represents a Column object. + olColumnFormat = 149 , // Represents a ColumnFormat object. + olColumns = 150 , // Represents a Columns object. + olConflict = 102 , // Represents a Conflict object. + olConflicts = 103 , // Represents a Conflicts object. + olContact = 40 , // Represents a ContactItem object. + olContactsModule = 160 , // Represents a ContactsModule object. + olDistributionList = 69 , // Represents a ExchangeDistributionList object. + olDocument = 41 , // Represents a DocumentItem object. + olException = 30 , // Represents an Exception object. + olExceptions = 29 , // Represents an Exceptions object. + olExchangeDistributionList = 111 , // Represents an ExchangeDistributionList object. + olExchangeUser = 110 , // Represents an ExchangeUser object. + olExplorer = 34 , // Represents an Explorer object. + olExplorers = 60 , // Represents an Explorers object. + olFolder = 2 , // Represents a Folder object. + olFolders = 15 , // Represents a Folders object. + olFolderUserProperties = 172 , // Represents a UserDefinedProperties object. + olFolderUserProperty = 171 , // Represents a UserDefinedProperty object. + olFormDescription = 37 , // Represents a FormDescription object. + olFormNameRuleCondition = 131 , // Represents a FormNameRuleCondition object. + olFormRegion = 129 , // Represents a FormRegion object. + olFromRssFeedRuleCondition = 173 , // Represents a FromRssFeedRuleCondition object. + olFromRuleCondition = 132 , // Represents a ToOrFromRuleCondition object. + olImportanceRuleCondition = 128 , // Represents an ImportanceRuleCondition object. + olInspector = 35 , // Represents an Inspector object. + olInspectors = 61 , // Represents an Inspectors object. + olItemProperties = 98 , // Represents an ItemProperties object. + olItemProperty = 99 , // Represents an ItemProperty object. + olItems = 16 , // Represents an Items object. + olJournal = 42 , // Represents a JournalItem object. + olJournalModule = 162 , // Represents a JournalModule object. + olLink = 75 , // Represents a Link object. + olLinks = 76 , // Represents a Links object. + olMail = 43 , // Represents a MailItem object. + olMailModule = 158 , // Represents a MailModule object. + olMarkAsTaskRuleAction = 124 , // Represents a MarkAsTaskRuleAction object. + olMeetingCancellation = 54 , // Represents a MeetingItem object that is a meeting cancellation notice. + olMeetingRequest = 53 , // Represents a MeetingItem object that is a meeting request. + olMeetingResponseNegative = 55 , // Represents a MeetingItem object that is a refusal of a meeting request. + olMeetingResponsePositive = 56 , // Represents a MeetingItem object that is an acceptance of a meeting request. + olMeetingResponseTentative = 57 , // Represents a MeetingItem object that is a tentative acceptance of a meeting request. + olMoveOrCopyRuleAction = 118 , // Represents a MoveOrCopyRuleAction object. + olNamespace = 1 , // Represents a NameSpace object. + olNavigationFolder = 167 , // Represents a NavigationFolder object. + olNavigationFolders = 166 , // Represents a NavigationFolders object. + olNavigationGroup = 165 , // Represents a NavigationGroup object. + olNavigationGroups = 164 , // Represents a NavigationGroups object. + olNavigationModule = 157 , // Represents a NavigationModule object. + olNavigationModules = 156 , // Represents a NavigationModules object. + olNewItemAlertRuleAction = 125 , // Represents a NewItemAlertRuleAction object. + olNote = 44 , // Represents a NoteItem object. + olNotesModule = 163 , // Represents a NotesModule object. + olOrderField = 144 , // Represents an OrderField object. + olOrderFields = 145 , // Represents an OrderFields object. + olOutlookBarGroup = 66 , // Represents an OutlookBarGroup object. + olOutlookBarGroups = 65 , // Represents an OutlookBarGroups object. + olOutlookBarPane = 63 , // Represents an OutlookBarPane object. + olOutlookBarShortcut = 68 , // Represents an OutlookBarShortcut object. + olOutlookBarShortcuts = 67 , // Represents an OutlookBarShortcuts object. + olOutlookBarStorage = 64 , // Represents an OutlookBarStorage object. + olPages = 36 , // Represents a Pages object. + olPanes = 62 , // Represents a Panes object. + olPlaySoundRuleAction = 123 , // Represents a PlaySoundRuleAction object. + olPost = 45 , // Represents a PostItem object. + olPropertyAccessor = 112 , // Represents a PropertyAccessor object. + olPropertyPages = 71 , // Represents a PropertyPages object. + olPropertyPageSite = 70 , // Represents a PropertyPageSite object. + olRecipient = 4 , // Represents a Recipient object. + olRecipients = 17 , // Represents a Recipients object. + olRecurrencePattern = 28 , // Represents a RecurrencePattern object. + olReminder = 101 , // Represents a Reminder object. + olReminders = 100 , // Represents a Reminders object. + olRemote = 47 , // Represents a RemoteItem object. + olReport = 46 , // Represents a ReportItem object. + olResults = 78 , // Represents a Results object. + olRow = 121 , // Represents a Row object. + olRule = 115 , // Represents a Rule object. + olRuleAction = 117 , // Represents a RuleAction object. + olRuleActions = 116 , // Represents a RuleAction object. + olRuleCondition = 127 , // Represents a RuleCondition object. + olRuleConditions = 126 , // Represents a RuleConditions object. + olRules = 114 , // Represents a Rules object. + olSearch = 77 , // Represents a Search object. + olSelection = 74 , // Represents a Selection object. + olSelectNamesDialog = 109 , // Represents a SelectNamesDialog object. + olSenderInAddressListRuleCondition = 133 , // Represents a SenderInAddressListRuleCondition object. + olSendRuleAction = 119 , // Represents a SendRuleAction object. + olSharing = 104 , // Represents a SharingItem object. + olStorageItem = 113 , // Represents a StorageItem object. + olStore = 107 , // Represents a Store object. + olStores = 108 , // Represents a Stores object. + olSyncObject = 72 , // Represents a SyncObject object. + olSyncObjects = 73 , // Represents a SyncObject object. + olTable = 120 , // Represents a Table object. + olTask = 48 , // Represents a TaskItem object. + olTaskRequest = 49 , // Represents a TaskRequestItem object. + olTaskRequestAccept = 51 , // Represents a TaskRequestAcceptItem object. + olTaskRequestDecline = 52 , // Represents a TaskRequestDeclineItem object. + olTaskRequestUpdate = 50 , // Represents a TaskRequestUpdateItem object. + olTasksModule = 161 , // Represents a TasksModule object. + olTextRuleCondition = 134 , // Represents a TextRuleCondition object. + olUserDefinedProperties = 172 , // Represents a UserDefinedProperties object. + olUserDefinedProperty = 171 , // Represents a UserDefinedProperty object. + olUserProperties = 38 , // Represents a UserProperties object. + olUserProperty = 39 , // Represents a UserProperty object. + olView = 80 , // Represents a View object. + olViewField = 142 , // Represents a ViewField object. + olViewFields = 141 , // Represents a ViewFields object. + olViewFont = 146 , // Represents a ViewFont object. + olViews = 79 // Represents a Views object. + } public enum OlItemType { // Fields @@ -182,4 +311,11 @@ namespace Greenshot.Helpers.OfficeInterop { msoScaleFromMiddle = 1, msoScaleFromBottomRight = 2 } + + // Schema definitions for the MAPI properties + // See: http://msdn.microsoft.com/en-us/library/aa454438.aspx + // and see: http://msdn.microsoft.com/en-us/library/bb446117.aspx + public static class PropTag { + public const string ATTACHMENT_CONTENT_ID = @"http://schemas.microsoft.com/mapi/proptag/0x3712001E"; + } } diff --git a/Greenshot/Helpers/OfficeInterop/OutlookWrapper.cs b/Greenshot/Helpers/OfficeInterop/OutlookWrapper.cs index 4cb4bbe5f..0fa305467 100644 --- a/Greenshot/Helpers/OfficeInterop/OutlookWrapper.cs +++ b/Greenshot/Helpers/OfficeInterop/OutlookWrapper.cs @@ -19,16 +19,24 @@ * along with this program. If not, see . */ using System; +using System.Collections; +using System.Collections.Generic; using System.IO; using System.Text; +using System.Text.RegularExpressions; using System.Threading; using Greenshot.Helpers.IEInterop; using Greenshot.Interop; using Greenshot.Plugin; using GreenshotPlugin.Core; +using IniFile; using Microsoft.Win32; +/// +/// This utils class should help setting the content-id on the attachment for Outlook < 2007 +/// But this somehow doesn't work yet +/// namespace Greenshot.Helpers.OfficeInterop { /// /// Wrapper for Outlook.Application @@ -37,10 +45,39 @@ namespace Greenshot.Helpers.OfficeInterop { public interface IOutlookApplication : Common { string Name { get; } string Version { get; } - object CreateItem(OlItemType ItemType); + Item CreateItem(OlItemType ItemType); object CreateItemFromTemplate(string TemplatePath, object InFolder); object CreateObject(string ObjectName); Inspector ActiveInspector(); + Inspectors Inspectors { get; } + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.inspector_members.aspx + public interface Inspector : Common { + Item CurrentItem { get; } + OlEditorType EditorType { get; } + object ModifiedFormPages { get; } + void Close(OlInspectorClose SaveMode); + void Display(object Modal); + void HideFormPage(string PageName); + bool IsWordMail(); + void SetCurrentFormPage(string PageName); + void ShowFormPage(string PageName); + object HTMLEditor { get; } + IWordDocument WordEditor { get; } + string Caption { get; } + int Height { get; set; } + int Left { get; set; } + int Top { get; set; } + int Width { get; set; } + OlWindowState WindowState { get; set; } + void Activate(); + void SetControlItemProperty(object Control, string PropertyName); + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook._application.inspectors.aspx + public interface Inspectors : Common, Collection, IEnumerable { + Inspector this[Object Index] { get; } } /// @@ -49,8 +86,8 @@ namespace Greenshot.Helpers.OfficeInterop { public class OutlookExporter { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OutlookExporter)); private static CoreConfiguration conf = IniConfig.GetIniSection(); - private static readonly string SIGNATURE_PATH = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"Microsoft\Signatures"); + private static Version outlookVersion = new Version(1,1,1,1); // The signature key can be found at: // HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\\9375CFF0413111d3B88A00104B2A6676\ [New Signature] @@ -58,159 +95,270 @@ namespace Greenshot.Helpers.OfficeInterop { private const string ACCOUNT_KEY = "9375CFF0413111d3B88A00104B2A6676"; private const string NEW_SIGNATURE_VALUE = "New Signature"; private const string DEFAULT_PROFILE_VALUE = "DefaultProfile"; - private const string OUTLOOK_PATH_KEY = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\OUTLOOK.EXE"; + + /// + /// A method to retrieve all inspectors which can act as an export target + /// + /// IOutlookApplication + /// List with inspector captions (window title) + public static List RetrievePossibleTargets() { + List inspectorCaptions = new List(); + try { + using ( IOutlookApplication outlookApplication = GetOutlookApplication()) { + if (outlookApplication == null) { + return null; + } + Inspectors inspectors = outlookApplication.Inspectors; + if (inspectors != null && inspectors.Count > 0) { + LOG.DebugFormat("Got {0} inspectors to check", inspectors.Count); + for(int i=1; i <= inspectors.Count; i++) { + Inspector inspector = outlookApplication.Inspectors[i]; + LOG.DebugFormat("Checking inspector '{0}'", inspector.Caption); + try { + Item currentMail = inspector.CurrentItem; + if (currentMail != null && OlObjectClass.olMail.Equals(currentMail.Class) ) { + if (currentMail != null && !currentMail.Sent) { + inspectorCaptions.Add(inspector.Caption); + } + } + } catch (Exception) { + } + } + } + } + } catch (Exception ex) { + LOG.Warn("Problem retrieving word destinations, ignoring: ", ex); + } + return inspectorCaptions; + + } /// - /// Check if Outlook is installed + /// Export to currently opened Email /// - /// Returns true if outlook is installed - public static bool HasOutlook() { - using (RegistryKey key = Registry.LocalMachine.OpenSubKey(OUTLOOK_PATH_KEY, false)) { - if (key != null) { - // "" is the default key, which should point to the outlook location - string outlookPath = (string)key.GetValue(""); - if (outlookPath != null) { - if (File.Exists(outlookPath)) { + /// + private static bool ExportToOpenEmail(IOutlookApplication outlookApplication, string tmpFile, string subject) { + using (Inspector activeInspector = outlookApplication.ActiveInspector()) { + if (activeInspector != null) { + try { + LOG.DebugFormat("Checking active inspector '{0}'", activeInspector.Caption); + if (ExportToInspector(activeInspector, tmpFile, subject)) { return true; } + } catch (Exception ex) { + LOG.DebugFormat("Problem exporting to activeinspector: {0}", ex.Message); + } + } + } + Inspectors inspectors = outlookApplication.Inspectors; + if (inspectors != null && inspectors.Count > 0) { + LOG.DebugFormat("Got {0} inspectors to check", inspectors.Count); + for(int i=1; i <= inspectors.Count; i++) { + Inspector inspector = outlookApplication.Inspectors[i]; + LOG.DebugFormat("Checking inspector '{0}'", inspector.Caption); + try { + bool exported = ExportToInspector(inspector, tmpFile, subject); + if (exported) { + return true; + } + } catch (Exception ex) { + LOG.DebugFormat("Problem exporting to inspector: {0}", ex.Message); + } + + } + } + + return false; + } + + /// + /// Export the image stored in tmpFile to the Inspector with the caption + /// + /// Caption of the inspector + /// Path to image file + /// name of the attachment (used as the tooltip of the image) + /// true if it worked + public static bool ExportToInspector(string inspectorCaption, string tmpFile, string attachmentName) { + using ( IOutlookApplication outlookApplication = GetOrCreateOutlookApplication()) { + if (outlookApplication != null) { + Inspectors inspectors = outlookApplication.Inspectors; + if (inspectors != null && inspectors.Count > 0) { + LOG.DebugFormat("Got {0} inspectors to check", inspectors.Count); + for(int i=1; i <= inspectors.Count; i++) { + Inspector inspector = outlookApplication.Inspectors[i]; + if (inspector.Caption.StartsWith(inspectorCaption)) { + return ExportToInspector(inspector, tmpFile, attachmentName); + } + } } } } return false; } - /// - /// Export to currently opened Email - /// - /// - private static bool ExportToOpenEmail(Inspector activeInspector, string tmpFile, string subject) { - object objectItem = activeInspector.CurrentItem; - if (objectItem == null) { - LOG.Debug("No current item"); + private static bool ExportToInspector(Inspector inspector, string tmpFile, string attachmentName) { + Item currentMail = inspector.CurrentItem; + if (currentMail == null) { + LOG.Debug("No current item."); return false; } - if (activeInspector.IsWordMail()) { - IWordDocument wordDocument = activeInspector.WordEditor; - if (wordDocument != null) { - if (WordExporter.InsertIntoExistingDocument(wordDocument, tmpFile)) { + if (!OlObjectClass.olMail.Equals(currentMail.Class)) { + LOG.Debug("Item is no mail."); + return false; + } + try { + if (currentMail.Sent) { + LOG.Debug("Item already sent"); + return false; + } + + // Make sure the inspector is activated, only this way the word editor is active! + // This also ensures that the window is visible! + inspector.Activate(); + + // Check for wordmail, if so use the wordexporter + if (inspector.IsWordMail() && inspector.WordEditor != null) { + if (WordExporter.InsertIntoExistingDocument(inspector.WordEditor, tmpFile)) { LOG.Debug("Inserted into Wordmail"); return true; } } else { LOG.Debug("Wordmail editor is not supported"); } - } - using (MailItem currentMail = (MailItem)COMWrapper.Wrap(objectItem, typeof(MailItem))) { - if (currentMail.Sent) { - LOG.Debug("Item already sent"); - return false; + + LOG.DebugFormat("Email '{0}' has format: {1}", currentMail.Subject, currentMail.BodyFormat); + + string contentID; + if (outlookVersion.Major >=12 ) { + contentID = Guid.NewGuid().ToString(); + } else { + LOG.Info("Older Outlook (<2007) found, using filename as contentid."); + contentID = Path.GetFileName(tmpFile); } - LOG.DebugFormat("Current email with format: {0}", currentMail.BodyFormat); + bool inlinePossible = false; if (OlBodyFormat.olFormatHTML.Equals(currentMail.BodyFormat)) { - // if html we can inline it - - // This will cause a security popup... can't ignore it. + // if html we can try to inline it + // The following might cause a security popup... can't ignore it. try { - IHTMLDocument2 document2 = (IHTMLDocument2)activeInspector.HTMLEditor; - if (document2 == null) { - return false; + IHTMLDocument2 document2 = inspector.HTMLEditor as IHTMLDocument2; + if (document2 != null) { + IHTMLSelectionObject selection = document2.selection; + if (selection != null) { + IHTMLTxtRange range = selection.createRange(); + if (range != null) { + // First paste, than attach (otherwise the range is wrong!) + range.pasteHTML("
\""
"); + inlinePossible = true; + } else { + LOG.DebugFormat("No range for '{0}'", inspector.Caption); + } + } else { + LOG.DebugFormat("No selection for '{0}'", inspector.Caption); + } + } else { + LOG.DebugFormat("No HTML editor for '{0}'", inspector.Caption); } - IHTMLSelectionObject selection = document2.selection; - if (selection == null) { - return false; - } - IHTMLTxtRange range = selection.createRange(); - if (range == null) { - return false; - } - // First paste, than attach (otherwise the range is wrong!) - range.pasteHTML("
\""
"); } catch (Exception e) { LOG.Warn("Error pasting HTML, most likely due to an ACCESS_DENIED as the user clicked no.", e); - // Do not continue & add attachment, rather return and try something else - return false; + // Continue with non inline image } - currentMail.Attachments.Add(tmpFile, OlAttachmentType.olByValue, 0, subject); - } else { - // attach file to mail - currentMail.Attachments.Add(tmpFile, OlAttachmentType.olByValue, 1, subject); } - currentMail.Display(false); + + // Create the attachment (if inlined the attachment isn't visible as attachment!) + Attachment attachment = currentMail.Attachments.Add(tmpFile, OlAttachmentType.olByValue, inlinePossible?0:1, attachmentName); + if (outlookVersion.Major >=12) { + // Add the content id to the attachment + try { + PropertyAccessor propertyAccessor = attachment.PropertyAccessor; + propertyAccessor.SetProperty(PropTag.ATTACHMENT_CONTENT_ID, contentID); + } catch { + } + } + } catch (Exception ex) { + LOG.DebugFormat("Problem while trying to add attachment to MailItem '{0}' : {1}", inspector.Caption, ex); + return false; } + LOG.Debug("Finished!"); return true; } - /// /// Export image to a new email /// /// /// /// - private static void ExportToNewEmail(IOutlookApplication outlookApplication, string tmpFile, string subject) { - object obj = outlookApplication.CreateItem( OlItemType.olMailItem ); - using( MailItem newMail = (MailItem)COMWrapper.Wrap(obj, typeof( MailItem ) ) ) { - newMail.Subject = subject; - newMail.BodyFormat = OlBodyFormat.olFormatHTML; - string bodyString = null; - // Read the default signature, if nothing found use empty email - try { - bodyString = GetOutlookSignature(); - } catch (Exception e) { - LOG.Error("Problem reading signature!", e); - } - switch(conf.OutputEMailFormat) { - case EmailFormat.TXT: - newMail.Attachments.Add(tmpFile, OlAttachmentType.olByValue, 1, subject); - newMail.BodyFormat = OlBodyFormat.olFormatPlain; - if (bodyString == null) { - bodyString = ""; + private static void ExportToNewEmail(IOutlookApplication outlookApplication, string tmpFile, string subject, string attachmentName) { + Item newMail = outlookApplication.CreateItem( OlItemType.olMailItem ); + if (newMail == null) { + return; + } + newMail.Subject = subject; + newMail.BodyFormat = OlBodyFormat.olFormatHTML; + string bodyString = null; + // Read the default signature, if nothing found use empty email + try { + bodyString = GetOutlookSignature(); + } catch (Exception e) { + LOG.Error("Problem reading signature!", e); + } + switch(conf.OutputEMailFormat) { + case EmailFormat.OUTLOOK_TXT: + newMail.Attachments.Add(tmpFile, OlAttachmentType.olByValue, 1, attachmentName); + newMail.BodyFormat = OlBodyFormat.olFormatPlain; + if (bodyString == null) { + bodyString = ""; + } + newMail.Body = bodyString; + break; + case EmailFormat.OUTLOOK_HTML: + default: + // Create the attachment + Attachment attachment = newMail.Attachments.Add(tmpFile, OlAttachmentType.olByValue, 0, attachmentName); + // add content ID to the attachment + string contentID = Path.GetFileName(tmpFile); + if (outlookVersion.Major >=12) { + // Add the content id to the attachment + try { + contentID = Guid.NewGuid().ToString(); + PropertyAccessor propertyAccessor = attachment.PropertyAccessor; + propertyAccessor.SetProperty(PropTag.ATTACHMENT_CONTENT_ID, contentID); + } catch { + LOG.Info("Error working with the PropertyAccessor, using filename as contentid"); + contentID = Path.GetFileName(tmpFile); } - newMail.Body = bodyString; - break; - case EmailFormat.HTML: - default: - newMail.Attachments.Add(tmpFile, OlAttachmentType.olByValue, 0, subject); - newMail.BodyFormat = OlBodyFormat.olFormatHTML; - string htmlImgEmbedded = "
\""
"; - string fallbackBody = "" + htmlImgEmbedded + ""; - if (bodyString == null) { - bodyString = fallbackBody; - } else { - int bodyIndex = bodyString.IndexOf("
"; + string fallbackBody = "" + htmlImgEmbedded + ""; + if (bodyString == null) { + bodyString = fallbackBody; + } else { + int bodyIndex = bodyString.IndexOf("= 0) { + bodyIndex = bodyString.IndexOf(">", bodyIndex) + 1; if (bodyIndex >= 0) { - bodyIndex = bodyString.IndexOf(">", bodyIndex) + 1; - if (bodyIndex >= 0) { - bodyString = bodyString.Insert(bodyIndex, htmlImgEmbedded); - } else { - bodyString = fallbackBody; - } + bodyString = bodyString.Insert(bodyIndex, htmlImgEmbedded); } else { bodyString = fallbackBody; } + } else { + bodyString = fallbackBody; } - newMail.HTMLBody = bodyString; - break; - } - // So not save, otherwise the email is always stored in Draft folder.. (newMail.Save();) - newMail.Display(false); + } + newMail.HTMLBody = bodyString; + break; } + // So not save, otherwise the email is always stored in Draft folder.. (newMail.Save();) + newMail.Display(false); } - private static bool ExportToMail(IOutlookApplication outlookApplication, string tmpFile, string subject) { + private static bool ExportToMail(IOutlookApplication outlookApplication, string tmpFile, string subject, string attachmentName) { bool exported = false; if (outlookApplication != null) { - using (Inspector activeInspector = outlookApplication.ActiveInspector()) { - if (conf.OutputOutlookMethod == EmailExport.TryOpenElseNew && activeInspector != null) { - LOG.Debug("EmailExport.TryOpenElseNew"); - exported = ExportToOpenEmail(activeInspector, tmpFile, subject); - } - if (!exported) { - LOG.Debug("EmailExport.AllwaysNew"); - ExportToNewEmail(outlookApplication, tmpFile, subject); - exported = true; - } - } + ExportToNewEmail(outlookApplication, tmpFile, subject, attachmentName); + exported = true; } return exported; } @@ -220,20 +368,20 @@ namespace Greenshot.Helpers.OfficeInterop { ///
/// The file to send /// true if it worked, false if not - public static bool ExportToOutlook(string tmpFile, ICaptureDetails captureDetails) { + public static bool ExportToOutlook(string tmpFile, string subject, string attachmentName) { try { bool exported = false; - string subject = captureDetails.Title.Replace("\"","'"); - using ( IOutlookApplication outlookApplication = OutlookApplication()) { + + using ( IOutlookApplication outlookApplication = GetOrCreateOutlookApplication()) { if (outlookApplication != null) { - exported = ExportToMail(outlookApplication, tmpFile, subject); + exported = ExportToMail(outlookApplication, tmpFile, subject, attachmentName); } } if (exported) { - Thread.Sleep(400); + // Wait to make sure the system "imported" the file + // TODO: this should be handled differently some time + Thread.Sleep(600); } - LOG.DebugFormat("Deleting {0}", tmpFile); - File.Delete(tmpFile); return exported; } catch(Exception e) { LOG.Error("Error while creating an outlook mail item: ", e); @@ -273,10 +421,10 @@ namespace Greenshot.Helpers.OfficeInterop { LOG.DebugFormat("Found email signature: {0}", signatureName); string extension; switch(conf.OutputEMailFormat) { - case EmailFormat.TXT: + case EmailFormat.OUTLOOK_TXT: extension = ".txt"; break; - case EmailFormat.HTML: + case EmailFormat.OUTLOOK_HTML: default: extension = ".htm"; break; @@ -293,8 +441,24 @@ namespace Greenshot.Helpers.OfficeInterop { return null; } - private static IOutlookApplication OutlookApplication() { - return (IOutlookApplication)COMWrapper.GetOrCreateInstance(typeof(IOutlookApplication)); + private static IOutlookApplication GetOutlookApplication() { + IOutlookApplication outlookApplication = (IOutlookApplication)COMWrapper.GetInstance(typeof(IOutlookApplication)); + try { + if (outlookApplication != null) { + outlookVersion = new Version(outlookApplication.Version); + } + } catch { + } + return outlookApplication; + } + + private static IOutlookApplication GetOrCreateOutlookApplication() { + IOutlookApplication outlookApplication = (IOutlookApplication)COMWrapper.GetOrCreateInstance(typeof(IOutlookApplication)); + try { + outlookVersion = new Version(outlookApplication.Version); + } catch { + } + return outlookApplication; } } } diff --git a/Greenshot/Helpers/OfficeInterop/PowerpointWrapper.cs b/Greenshot/Helpers/OfficeInterop/PowerpointWrapper.cs index 17eae505c..d5fe01705 100644 --- a/Greenshot/Helpers/OfficeInterop/PowerpointWrapper.cs +++ b/Greenshot/Helpers/OfficeInterop/PowerpointWrapper.cs @@ -21,7 +21,7 @@ using System; using System.Collections; using System.Drawing; - +using System.Runtime.Remoting.Messaging; using Greenshot.Interop; using Greenshot.Plugin; @@ -37,18 +37,19 @@ namespace Greenshot.Helpers.OfficeInterop { // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.powerpoint.slides_members.aspx public interface ISlides : Common { int Count {get;} - ISlide Add(int Index, PPSlideLayout Layout); + ISlide Add(int Index, int layout); } // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.powerpoint.presentation_members.aspx public interface IPresentation : Common { + string Name { get; } ISlides Slides{ get;} } // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.powerpoint.presentations_members.aspx - public interface IPresentations : Common { - int Count {get;} + public interface IPresentations : Common, Collection { IPresentation Add(MsoTriState WithWindow); + IPresentation item(int index); } // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.powerpoint.slide_members.aspx @@ -126,49 +127,108 @@ namespace Greenshot.Helpers.OfficeInterop { public class PowerpointExporter { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(PowerpointExporter)); - private static IPowerpointApplication PowerpointApplication() { + private static IPowerpointApplication GetOrCreatePowerpointApplication() { return (IPowerpointApplication)COMWrapper.GetOrCreateInstance(typeof(IPowerpointApplication)); } - private static void AddPictureToPresentation(IPresentation presentation, string tmpFile, Image image, ICaptureDetails captureDetails) { + private static IPowerpointApplication GetPowerpointApplication() { + return (IPowerpointApplication)COMWrapper.GetInstance(typeof(IPowerpointApplication)); + } + + /// + /// Get the captions of all the open powerpoint presentations + /// + /// + public static System.Collections.Generic.List GetPowerpointPresentations() { + System.Collections.Generic.List presentations = new System.Collections.Generic.List(); + try { + using( IPowerpointApplication powerpointApplication = GetPowerpointApplication() ) { + if (powerpointApplication != null) { + LOG.DebugFormat("Open Presentations: {0}", powerpointApplication.Presentations.Count); + for(int i = 1; i <= powerpointApplication.Presentations.Count ; i ++) { + IPresentation presentation = powerpointApplication.Presentations.item(i); + if (presentation != null) { + presentations.Add(presentation.Name); + } + } + } + } + } catch (Exception ex) { + LOG.Warn("Problem retrieving word destinations, ignoring: ", ex); + } + + return presentations; + } + + /// + /// Export the image from the tmpfile to the presentation with the supplied name + /// + /// + /// + /// + /// + /// + public static bool ExportToPresentation(string presentationName, string tmpFile, Size imageSize, ICaptureDetails captureDetails) { + using( IPowerpointApplication powerpointApplication = GetPowerpointApplication() ) { + if (powerpointApplication != null) { + LOG.DebugFormat("Open Presentations: {0}", powerpointApplication.Presentations.Count); + for(int i = 1; i <= powerpointApplication.Presentations.Count ; i ++) { + IPresentation presentation = powerpointApplication.Presentations.item(i); + if (presentation != null && presentation.Name.StartsWith(presentationName)) { + try { + AddPictureToPresentation(presentation, tmpFile, imageSize, captureDetails); + return true; + } catch (Exception e){ + LOG.Error(e); + } + } + } + } + } + return false; + } + + private static void AddPictureToPresentation(IPresentation presentation, string tmpFile, Size imageSize, ICaptureDetails captureDetails) { if (presentation != null) { //ISlide slide = presentation.Slides.AddSlide( presentation.Slides.Count + 1, PPSlideLayout.ppLayoutPictureWithCaption); - LOG.DebugFormat("Slides before {0}", presentation.Slides.Count); - ISlide slide = presentation.Slides.Add( presentation.Slides.Count + 1, PPSlideLayout.ppLayoutPictureWithCaption); - LOG.DebugFormat("Slides after {0}", presentation.Slides.Count); - // Shapes[2] is the image shape on this layout. - IShape shapeForLocation = slide.Shapes.item(2); - shapeForLocation.Width = image.Width; - shapeForLocation.Height = image.Height; - LOG.DebugFormat("Shape {0},{1},{2},{3}", shapeForLocation.Left, shapeForLocation.Top, image.Width, image.Height); - IShape shape = slide.Shapes.AddPicture(tmpFile, MsoTriState.msoFalse, MsoTriState.msoTrue, shapeForLocation.Left, shapeForLocation.Top, image.Width, image.Height); - shape.Width = image.Width; - shape.Height = image.Height; + ISlide slide; + float left = 0; + float top = 0; + bool isLayoutPictureWithCaption = false; + try { + slide = presentation.Slides.Add( presentation.Slides.Count + 1, (int)PPSlideLayout.ppLayoutPictureWithCaption); + isLayoutPictureWithCaption = true; + // Shapes[2] is the image shape on this layout. + IShape shapeForLocation = slide.Shapes.item(2); + shapeForLocation.Width = imageSize.Width; + shapeForLocation.Height = imageSize.Height; + left = shapeForLocation.Left; + top = shapeForLocation.Top; + LOG.DebugFormat("Shape {0},{1},{2},{3}", shapeForLocation.Left, shapeForLocation.Top, imageSize.Width, imageSize.Height); + } catch (Exception e) { + LOG.Error(e); + slide = presentation.Slides.Add( presentation.Slides.Count + 1, (int)PPSlideLayout.ppLayoutBlank); + } + IShape shape = slide.Shapes.AddPicture(tmpFile, MsoTriState.msoFalse, MsoTriState.msoTrue, left, top, imageSize.Width, imageSize.Height); + shape.Width = imageSize.Width; + shape.Height = imageSize.Height; shape.ScaleWidth(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromMiddle); shape.ScaleHeight(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromMiddle); - slide.Shapes.item(1).TextFrame.TextRange.Text = captureDetails.Title; + if (isLayoutPictureWithCaption) { + try { + // Using try/catch to make sure problems with the text range don't give an exception. + shape.TextFrame.TextRange.Text = captureDetails.Title; + } catch {}; + } } } - private static void InsertIntoNewPresentation(IPowerpointApplication powerpointApplication, string tmpFile, Image image, ICaptureDetails captureDetails) { - LOG.Debug("No Presentation, creating a new Presentation"); - IPresentation presentation = powerpointApplication.Presentations.Add(MsoTriState.msoTrue); - AddPictureToPresentation(presentation, tmpFile, image, captureDetails); - } - - public static void ExportToPowerpoint(string tmpFile, Image image, ICaptureDetails captureDetails) { - using( IPowerpointApplication powerpointApplication = PowerpointApplication() ) { + public static void InsertIntoNewPresentation(string tmpFile, Size imageSize, ICaptureDetails captureDetails) { + using( IPowerpointApplication powerpointApplication = GetOrCreatePowerpointApplication() ) { if (powerpointApplication != null) { - LOG.DebugFormat("Open Presentations: {0}", powerpointApplication.Presentations.Count); - if (powerpointApplication.Presentations.Count > 0) { - if (powerpointApplication.ActivePresentation != null) { - LOG.Debug("Presentation found!"); - AddPictureToPresentation(powerpointApplication.ActivePresentation, tmpFile, image, captureDetails); - } - } else { - InsertIntoNewPresentation(powerpointApplication, tmpFile, image, captureDetails); - } powerpointApplication.Visible = true; + IPresentation presentation = powerpointApplication.Presentations.Add(MsoTriState.msoTrue); + AddPictureToPresentation(presentation, tmpFile, imageSize, captureDetails); } } } diff --git a/Greenshot/Helpers/OfficeInterop/WordWrapper.cs b/Greenshot/Helpers/OfficeInterop/WordWrapper.cs index 3280eae78..8791f0c57 100644 --- a/Greenshot/Helpers/OfficeInterop/WordWrapper.cs +++ b/Greenshot/Helpers/OfficeInterop/WordWrapper.cs @@ -19,33 +19,57 @@ * along with this program. If not, see . */ using System; +using System.Collections; using Greenshot.Interop; -using Greenshot.Plugin; namespace Greenshot.Helpers.OfficeInterop { // See http://msdn.microsoft.com/de-de/library/microsoft.office.interop.word.applicationclass_members%28v=Office.11%29.aspx [ComProgId("Word.Application")] public interface IWordApplication : Common { IWordDocument ActiveDocument { get; } - ISelection Selection {get;} - IDocuments Documents {get;} - bool Visible {get; set;} + ISelection Selection { get; } + IDocuments Documents { get; } + bool Visible { get; set; } } // See: http://msdn.microsoft.com/de-de/library/microsoft.office.interop.word.documents_members(v=office.11).aspx - public interface IDocuments : Common { - int Count {get;} + public interface IDocuments : Common, Collection { void Add(ref object Template, ref object NewTemplate, ref object DocumentType, ref object Visible); + IWordDocument item(int index); } // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.document.aspx public interface IWordDocument : Common { - IWordApplication Application{ get;} + IWordApplication Application { get; } + Window ActiveWindow { get; } } + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.window_members.aspx + public interface Window : Common { + Pane ActivePane { get; } + string Caption { + get; + } + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.pane_members.aspx + public interface Pane : Common { + View View { get; } + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.view_members.aspx + public interface View : Common { + Zoom Zoom { get; } + } + + // See: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.zoom_members.aspx + public interface Zoom : Common { + int Percentage { get; set; } + } + // See: http://msdn.microsoft.com/de-de/library/microsoft.office.interop.word.selection_members(v=office.11).aspx public interface ISelection : Common { - IInlineShapes InlineShapes { get;} + IInlineShapes InlineShapes { get; } void InsertAfter(string text); } @@ -56,13 +80,45 @@ namespace Greenshot.Helpers.OfficeInterop { public class WordExporter { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(WordExporter)); - private static IWordApplication WordApplication() { + private static IWordApplication GetOrCreateWordApplication() { return (IWordApplication)COMWrapper.GetOrCreateInstance(typeof(IWordApplication)); } + private static IWordApplication GetWordApplication() { + return (IWordApplication)COMWrapper.GetInstance(typeof(IWordApplication)); + } - public static bool InsertIntoExistingDocument(IWordDocument wordDocument, string tmpFile) { + /// + /// Insert the bitmap stored under the tempfile path into the word document with the supplied caption + /// + /// + /// + /// + public static bool InsertIntoExistingDocument(string wordCaption, string tmpFile) { + using( IWordApplication wordApplication = GetWordApplication() ) { + if (wordApplication != null) { + for(int i = 1; i <= wordApplication.Documents.Count ; i ++) { + IWordDocument wordDocument = wordApplication.Documents.item(i); + if (wordDocument.ActiveWindow.Caption.StartsWith(wordCaption)) { + return InsertIntoExistingDocument(wordDocument, tmpFile); + } + } + } + } + return false; + } + + internal static bool InsertIntoExistingDocument(IWordDocument wordDocument, string tmpFile) { if (wordDocument.Application.Selection != null) { AddPictureToSelection(wordDocument.Application.Selection, tmpFile); + try { + wordDocument.ActiveWindow.ActivePane.View.Zoom.Percentage = 100; + } catch(Exception e) { + if (e.InnerException != null) { + LOG.WarnFormat("Couldn't set zoom to 100, error: {0}", e.InnerException.Message); + } else { + LOG.WarnFormat("Couldn't set zoom to 100, error: {0}", e.Message); + } + } return true; } return false; @@ -72,35 +128,44 @@ namespace Greenshot.Helpers.OfficeInterop { selection.InlineShapes.AddPicture(tmpFile, Type.Missing, Type.Missing, Type.Missing); //selection.InsertAfter("blablub\r\n"); } - private static void InsertIntoNewDocument(IWordApplication wordApplication, string tmpFile) { - LOG.Debug("No Document, creating a new Document"); - // Create new Document - object template = string.Empty; - object newTemplate = false; - object documentType = 0; - object documentVisible = true; - wordApplication.Documents.Add(ref template, ref newTemplate, ref documentType, ref documentVisible); - // Add Picture - AddPictureToSelection(wordApplication.Selection, tmpFile); - } - public static void ExportToWord(string tmpFile) { - using( IWordApplication wordApplication = WordApplication() ) { + public static void InsertIntoNewDocument(string tmpFile) { + using( IWordApplication wordApplication = GetOrCreateWordApplication() ) { if (wordApplication != null) { wordApplication.Visible = true; - LOG.DebugFormat("Open Documents: {0}", wordApplication.Documents.Count); - if (wordApplication.Documents.Count > 0) { - if (wordApplication.Selection != null) { - LOG.Debug("Selection found!"); - AddPictureToSelection(wordApplication.Selection, tmpFile); - return; - } - } else { - InsertIntoNewDocument(wordApplication, tmpFile); - return; - } + + // Create new Document + object template = string.Empty; + object newTemplate = false; + object documentType = 0; + object documentVisible = true; + wordApplication.Documents.Add(ref template, ref newTemplate, ref documentType, ref documentVisible); + // Add Picture + AddPictureToSelection(wordApplication.Selection, tmpFile); } } } + + /// + /// Get the captions of all the open word documents + /// + /// + public static System.Collections.Generic.List GetWordDocuments() { + System.Collections.Generic.List documents = new System.Collections.Generic.List(); + try { + using(IWordApplication wordApplication = GetWordApplication()) { + if (wordApplication != null) { + //documents.Add(wordApplication.ActiveDocument); + for(int i = 1; i <= wordApplication.Documents.Count ; i ++) { + IWordDocument document = wordApplication.Documents.item(i); + documents.Add(document.ActiveWindow.Caption); + } + } + } + } catch (Exception ex) { + LOG.Warn("Problem retrieving word destinations, ignoring: ", ex); + } + return documents; + } } } diff --git a/Greenshot/Helpers/PluginHelper.cs b/Greenshot/Helpers/PluginHelper.cs index 1dc9f1f02..cb863fd0a 100644 --- a/Greenshot/Helpers/PluginHelper.cs +++ b/Greenshot/Helpers/PluginHelper.cs @@ -23,25 +23,25 @@ using System.Collections.Generic; using System.Drawing; using System.IO; using System.Reflection; -using System.Text; using System.Windows.Forms; using Greenshot.Configuration; using Greenshot.Plugin; -using GreenshotPlugin.Controls; using GreenshotPlugin.Core; +using IniFile; namespace Greenshot.Helpers { /// /// The PluginHelper takes care of all plugin related functionality /// [Serializable] - public class PluginHelper : IGreenshotPluginHost { + public class PluginHelper : IGreenshotHost { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(PluginHelper)); private static CoreConfiguration conf = IniConfig.GetIniSection(); - public static string configpath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),Application.ProductName); - public static string applicationpath = Path.GetDirectoryName(Application.ExecutablePath); + public static string pluginPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),Application.ProductName); + public static string applicationPath = Path.GetDirectoryName(Application.ExecutablePath); + public static string pafPath = Path.Combine(Application.StartupPath, @"App\Greenshot"); public static readonly PluginHelper instance = new PluginHelper(); private static Dictionary plugins = new Dictionary(); @@ -49,31 +49,6 @@ namespace Greenshot.Helpers { private PluginHelper() { } - public string ConfigurationPath { - get {return configpath;} - } - - public void CreateImageEditorOpenEvent(IImageEditor imageEditor) { - if (OnImageEditorOpen != null) { - ImageEditorOpenEventArgs eventArgs = new ImageEditorOpenEventArgs(imageEditor); - OnImageEditorOpen(this, eventArgs); - } - } - - public void CreateCaptureTakenEvent(ICapture capture) { - if (OnCaptureTaken != null) { - CaptureTakenEventArgs eventArgs = new CaptureTakenEventArgs(capture); - OnCaptureTaken(this, eventArgs); - } - } - - public void CreateSurfaceFromCaptureEvent(ICapture capture, ISurface surface) { - if (OnSurfaceFromCapture != null) { - SurfaceFromCaptureEventArgs eventArgs = new SurfaceFromCaptureEventArgs(capture, surface); - OnSurfaceFromCapture(this, eventArgs); - } - } - public bool HasPlugins() { return (plugins != null && plugins.Count > 0); } @@ -89,10 +64,10 @@ namespace Greenshot.Helpers { public void FillListview(ListView listview) { foreach(PluginAttribute pluginAttribute in plugins.Keys) { ListViewItem item = new ListViewItem(pluginAttribute.Name); - item.SubItems.Add(pluginAttribute.Version); - item.SubItems.Add(pluginAttribute.DllFile); - item.Tag = pluginAttribute; - listview.Items.Add(item); + item.SubItems.Add(pluginAttribute.Version); + item.SubItems.Add(pluginAttribute.DllFile); + item.Tag = pluginAttribute; + listview.Items.Add(item); } } @@ -117,14 +92,25 @@ namespace Greenshot.Helpers { } #region Implementation of IGreenshotPluginHost - public event OnImageEditorOpenHandler OnImageEditorOpen; - public event OnCaptureTakenHandler OnCaptureTaken; - public event OnSurfaceFromCaptureHandler OnSurfaceFromCapture; private ContextMenuStrip mainMenu = null; + public ILanguage CoreLanguage { + get { + return Language.GetInstance(); + } + } + public void SaveToStream(Image img, Stream stream, OutputFormat extension, int quality) { ImageOutput.SaveToStream(img, stream, extension, quality); } + + public string SaveToTmpFile(Image img, OutputFormat outputFormat, int quality) { + return ImageOutput.SaveToTmpFile(img, outputFormat, quality); + } + + public string SaveNamedTmpFile(Image image, ICaptureDetails captureDetails, OutputFormat outputFormat, int quality) { + return ImageOutput.SaveNamedTmpFile(image, captureDetails, outputFormat, quality); + } public string GetFilename(OutputFormat format, ICaptureDetails captureDetails) { string pattern = conf.OutputFileFilenamePattern; @@ -159,6 +145,36 @@ namespace Greenshot.Helpers { get {return plugins;} } + /// + /// Make Capture with specified Handler + /// + /// bool false if the mouse should not be captured, true if the configuration should be checked + /// IDestination + public void CaptureRegion(bool captureMouseCursor, IDestination destination) { + CaptureHelper.CaptureRegion(captureMouseCursor, destination); + } + + /// + /// Use the supplied image, and handle it as if it's captured. + /// + /// Image to handle + public void ImportCapture(ICapture captureToImport) { + MainForm.instance.BeginInvoke((MethodInvoker)delegate { + CaptureHelper.ImportCapture(captureToImport); + }); + } + + /// + /// Get an ICapture object, so the plugin can modify this + /// + /// + public ICapture GetCapture(Image imageToCapture) { + Capture capture = new Capture(imageToCapture); + capture.CaptureDetails = new CaptureDetails(); + capture.CaptureDetails.CaptureMode = CaptureMode.Import; + capture.CaptureDetails.Title = "Imported"; + return capture; + } #endregion #region Plugin loading @@ -188,21 +204,27 @@ namespace Greenshot.Helpers { return false; } - public void LoadPlugins(MainForm mainForm, ICaptureHost captureHost) { + public void LoadPlugins(MainForm mainForm) { // Copy ContextMenu mainMenu = mainForm.MainMenu; List pluginFiles = new List(); - if (Directory.Exists(configpath)) { - foreach(string pluginFile in Directory.GetFiles(configpath, "*.gsp", SearchOption.AllDirectories)) { + if (IniConfig.IsPortable && Directory.Exists(pafPath)) { + foreach(string pluginFile in Directory.GetFiles(pafPath, "*.gsp", SearchOption.AllDirectories)) { pluginFiles.Add(pluginFile); } - } - - if (Directory.Exists(applicationpath)) { - foreach(string pluginFile in Directory.GetFiles(applicationpath, "*.gsp", SearchOption.AllDirectories)) { - pluginFiles.Add(pluginFile); + } else { + if (Directory.Exists(pluginPath)) { + foreach(string pluginFile in Directory.GetFiles(pluginPath, "*.gsp", SearchOption.AllDirectories)) { + pluginFiles.Add(pluginFile); + } + } + + if (Directory.Exists(applicationPath)) { + foreach(string pluginFile in Directory.GetFiles(applicationPath, "*.gsp", SearchOption.AllDirectories)) { + pluginFiles.Add(pluginFile); + } } } @@ -269,23 +291,30 @@ namespace Greenshot.Helpers { } } foreach(string pluginName in tmpAttributes.Keys) { - PluginAttribute pluginAttribute = tmpAttributes[pluginName]; - Assembly assembly = tmpAssemblies[pluginName]; - Type entryType = assembly.GetType(pluginAttribute.EntryType); - if (entryType == null) { - LOG.ErrorFormat("Can't find the in the PluginAttribute referenced type {0} in \"{1}\"", pluginAttribute.EntryType, pluginAttribute.DllFile); - continue; - } try { - IGreenshotPlugin plugin = (IGreenshotPlugin)Activator.CreateInstance(entryType); - if (plugin != null) { - plugin.Initialize(this, captureHost, pluginAttribute); - plugins.Add(pluginAttribute, plugin); - } else { - LOG.ErrorFormat("Can't create an instance of the in the PluginAttribute referenced type {0} from \"{1}\"", pluginAttribute.EntryType, pluginAttribute.DllFile); + PluginAttribute pluginAttribute = tmpAttributes[pluginName]; + Assembly assembly = tmpAssemblies[pluginName]; + Type entryType = assembly.GetType(pluginAttribute.EntryType); + if (entryType == null) { + LOG.ErrorFormat("Can't find the in the PluginAttribute referenced type {0} in \"{1}\"", pluginAttribute.EntryType, pluginAttribute.DllFile); + continue; + } + try { + IGreenshotPlugin plugin = (IGreenshotPlugin)Activator.CreateInstance(entryType); + if (plugin != null) { + if (plugin.Initialize(this, pluginAttribute)) { + plugins.Add(pluginAttribute, plugin); + } else { + LOG.InfoFormat("Plugin {0} not initialized!", pluginAttribute.Name); + } + } else { + LOG.ErrorFormat("Can't create an instance of the in the PluginAttribute referenced type {0} from \"{1}\"", pluginAttribute.EntryType, pluginAttribute.DllFile); + } + } catch(Exception e) { + LOG.Error("Can't load Plugin: " + pluginAttribute.Name, e); } } catch(Exception e) { - LOG.Error("Can't load Plugin: " + pluginAttribute.Name, e); + LOG.Error("Can't load Plugin: " + pluginName, e); } } } diff --git a/Greenshot/Helpers/PrintHelper.cs b/Greenshot/Helpers/PrintHelper.cs index b72a5ce78..a5b7b030c 100644 --- a/Greenshot/Helpers/PrintHelper.cs +++ b/Greenshot/Helpers/PrintHelper.cs @@ -20,7 +20,6 @@ */ using System; using System.Drawing; -using System.Drawing.Drawing2D; using System.Drawing.Printing; using System.Windows.Forms; @@ -29,6 +28,7 @@ using Greenshot.Drawing; using Greenshot.Forms; using Greenshot.Plugin; using GreenshotPlugin.Core; +using IniFile; namespace Greenshot.Helpers { /// @@ -124,16 +124,16 @@ namespace Greenshot.Helpers { if (conf.OutputPrintInverted) { // Invert Bitmap - BitmapBuffer bb = new BitmapBuffer((Bitmap)image, false); - bb.Lock(); - for(int y=0;y /// Offers a few helper functions for scaling/aligning an element with another element /// - public class ScaleHelper { - private ScaleHelper() { + public static class ScaleHelper { + + [Flags] + public enum ScaleOptions { + /// + /// Scale a rectangle in two our four directions, mirrored at it's center coordinates + /// + Centered = 0x01, + /// + /// Scale a rectangle maintaining it's aspect ratio + /// + Rational = 0x02 } + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ScaleHelper)); + /// /// calculates the Size an element must be resized to, in order to fit another element, keeping aspect ratio /// @@ -41,8 +55,6 @@ namespace Greenshot.Helpers { float hFactor = targetSize.Height/currentSize.Height; float factor = crop ? Math.Max(wFactor, hFactor) : Math.Min(wFactor, hFactor); - //System.Diagnostics.Debug.WriteLine(currentSize.Width+"..."+targetSize.Width); - //System.Diagnostics.Debug.WriteLine(wFactor+"..."+hFactor+">>>"+factor); return new SizeF(currentSize.Width * factor, currentSize.Height * factor); } @@ -101,5 +113,260 @@ namespace Greenshot.Helpers { RectangleF newRect = new RectangleF(new Point(0,0), newSize); return GetAlignedRectangle(newRect, targetRect, alignment); } + + public static void RationalScale(ref RectangleF originalRectangle, int resizeHandlePosition, PointF resizeHandleCoords) { + Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords, ScaleOptions.Rational); + } + + public static void CenteredScale(ref RectangleF originalRectangle, int resizeHandlePosition, PointF resizeHandleCoords) { + Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords, ScaleOptions.Centered); + } + + public static void Scale(ref RectangleF originalRectangle, int resizeHandlePosition, PointF resizeHandleCoords) { + Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords, 0x0); + } + + /// + /// Calculates target size of a given rectangle scaled by dragging one of its handles (corners) + /// + /// bounds of the current rectangle, scaled values will be written to this reference + /// position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT + /// coordinates of the used handle/gripper + /// ScaleOptions to use when scaling + public static void Scale(ref RectangleF originalRectangle, int resizeHandlePosition, PointF resizeHandleCoords, ScaleOptions options) { + if(options == null) { + options = GetScaleOptions(); + } + + if((options & ScaleOptions.Rational) == ScaleOptions.Rational) { + adjustCoordsForRationalScale(originalRectangle, resizeHandlePosition, ref resizeHandleCoords); + } + + if((options & ScaleOptions.Centered) == ScaleOptions.Centered) { + // store center coordinates of rectangle + float rectCenterX = originalRectangle.Left + originalRectangle.Width / 2; + float rectCenterY = originalRectangle.Top + originalRectangle.Height / 2; + // scale rectangle using handle coordinates + scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); + // mirror handle coordinates via rectangle center coordinates + resizeHandleCoords.X -= 2 * (resizeHandleCoords.X - rectCenterX); + resizeHandleCoords.Y -= 2 * (resizeHandleCoords.Y - rectCenterY); + // scale again with opposing handle and mirrored coordinates + resizeHandlePosition = (resizeHandlePosition + 4) % 8; + scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); + } else { + scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); + } + + } + + /// + /// Calculates target size of a given rectangle scaled by dragging one of its handles (corners) + /// + /// bounds of the current rectangle, scaled values will be written to this reference + /// position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT + /// coordinates of the used handle/gripper + private static void scale(ref RectangleF originalRectangle, int resizeHandlePosition, PointF resizeHandleCoords) { + switch(resizeHandlePosition) { + + case Gripper.POSITION_TOP_LEFT: + originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X; + originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y; + originalRectangle.X = resizeHandleCoords.X; + originalRectangle.Y = resizeHandleCoords.Y; + break; + + case Gripper.POSITION_TOP_CENTER: + originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y; + originalRectangle.Y = resizeHandleCoords.Y; + break; + + case Gripper.POSITION_TOP_RIGHT: + originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left; + originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y; + originalRectangle.Y = resizeHandleCoords.Y; + break; + + case Gripper.POSITION_MIDDLE_LEFT: + originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X; + originalRectangle.X = resizeHandleCoords.X; + break; + + case Gripper.POSITION_MIDDLE_RIGHT: + originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left; + break; + + case Gripper.POSITION_BOTTOM_LEFT: + originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X; + originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top; + originalRectangle.X = resizeHandleCoords.X; + break; + + case Gripper.POSITION_BOTTOM_CENTER: + originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top; + break; + + case Gripper.POSITION_BOTTOM_RIGHT: + originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left; + originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top; + break; + + default: + throw new ArgumentException("Position cannot be handled: "+resizeHandlePosition); + + } + } + + /// + /// Adjusts resizeHandleCoords so that aspect ratio is kept after resizing a given rectangle with provided arguments + /// + /// bounds of the current rectangle + /// position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT + /// coordinates of the used handle/gripper, adjusted coordinates will be written to this reference + private static void adjustCoordsForRationalScale(RectangleF originalRectangle, int resizeHandlePosition, ref PointF resizeHandleCoords) { + float originalRatio = originalRectangle.Width / originalRectangle.Height; + float newWidth, newHeight, newRatio; + switch(resizeHandlePosition) { + + case Gripper.POSITION_TOP_LEFT: + newWidth = originalRectangle.Right - resizeHandleCoords.X; + newHeight = originalRectangle.Bottom - resizeHandleCoords.Y; + newRatio = newWidth / newHeight; + if(newRatio > originalRatio) { // FIXME + resizeHandleCoords.X = originalRectangle.Right - newHeight * originalRatio; + } else if(newRatio < originalRatio) { + resizeHandleCoords.Y = originalRectangle.Bottom - newWidth / originalRatio; + } + break; + + case Gripper.POSITION_TOP_RIGHT: + newWidth = resizeHandleCoords.X - originalRectangle.Left; + newHeight = originalRectangle.Bottom - resizeHandleCoords.Y; + newRatio = newWidth / newHeight; + if(newRatio > originalRatio) { // FIXME + resizeHandleCoords.X = newHeight * originalRatio + originalRectangle.Left; + } else if(newRatio < originalRatio) { + resizeHandleCoords.Y = originalRectangle.Bottom - newWidth / originalRatio; + } + break; + + case Gripper.POSITION_BOTTOM_LEFT: + newWidth = originalRectangle.Right - resizeHandleCoords.X; + newHeight = resizeHandleCoords.Y - originalRectangle.Top; + newRatio = newWidth / newHeight; + if(newRatio > originalRatio) { + resizeHandleCoords.X = originalRectangle.Right - newHeight * originalRatio; + } else if(newRatio < originalRatio) { + resizeHandleCoords.Y = newWidth / originalRatio + originalRectangle.Top; + } + break; + + case Gripper.POSITION_BOTTOM_RIGHT: + newWidth = resizeHandleCoords.X - originalRectangle.Left; + newHeight = resizeHandleCoords.Y - originalRectangle.Top; + newRatio = newWidth / newHeight; + if(newRatio > originalRatio) { + resizeHandleCoords.X = newHeight * originalRatio + originalRectangle.Left; + } else if(newRatio < originalRatio) { + resizeHandleCoords.Y = newWidth / originalRatio + originalRectangle.Top; + } + break; + } + } + + public static void Scale(Rectangle boundsBeforeResize, int cursorX, int cursorY, ref RectangleF boundsAfterResize) { + Scale(boundsBeforeResize, cursorX, cursorY, ref boundsAfterResize, null); + } + + public static void Scale(Rectangle boundsBeforeResize, int cursorX, int cursorY, ref RectangleF boundsAfterResize, IDoubleProcessor angleRoundBehavior) { + + Scale(boundsBeforeResize, Gripper.POSITION_TOP_LEFT, cursorX, cursorY, ref boundsAfterResize, angleRoundBehavior); + } + + public static void Scale(Rectangle boundsBeforeResize, int gripperPosition, int cursorX, int cursorY, ref RectangleF boundsAfterResize, IDoubleProcessor angleRoundBehavior) { + + ScaleHelper.ScaleOptions opts = ScaleHelper.GetScaleOptions(); + + bool rationalScale = (opts & ScaleHelper.ScaleOptions.Rational) == ScaleHelper.ScaleOptions.Rational; + bool centeredScale = (opts & ScaleHelper.ScaleOptions.Centered) == ScaleHelper.ScaleOptions.Centered; + + if(rationalScale) { + double angle = GeometryHelper.Angle2D(boundsBeforeResize.X, boundsBeforeResize.Y, cursorX, cursorY); + + if(angleRoundBehavior != null) { + angle = angleRoundBehavior.Process(angle); + } + + int dist = GeometryHelper.Distance2D(boundsBeforeResize.X, boundsBeforeResize.Y, cursorX, cursorY); + + boundsAfterResize.Width = (int)Math.Round(dist * Math.Cos(angle / 180 * Math.PI)); + boundsAfterResize.Height = (int)Math.Round(dist * Math.Sin(angle / 180 * Math.PI)); + } + + if(centeredScale) { + float wdiff = boundsAfterResize.Width - boundsBeforeResize.Width; + float hdiff = boundsAfterResize.Height - boundsBeforeResize.Height; + boundsAfterResize.Width += wdiff; + boundsAfterResize.Height += hdiff; + boundsAfterResize.X -= wdiff; + boundsAfterResize.Y -= hdiff; + } + + + } + + /// the current ScaleOptions depending on modifier keys held down + public static ScaleHelper.ScaleOptions GetScaleOptions() { + bool anchorAtCenter = (Control.ModifierKeys & Keys.Control) != 0; + bool maintainAspectRatio = ((Control.ModifierKeys & Keys.Shift) != 0); + ScaleHelper.ScaleOptions opts = 0x0; + if(anchorAtCenter) opts |= ScaleHelper.ScaleOptions.Centered; + if(maintainAspectRatio) opts |= ScaleHelper.ScaleOptions.Rational; + return opts; + } + + public interface IDoubleProcessor { + double Process(double d); + } + + public class ShapeAngleRoundBehavior : IDoubleProcessor { + public static ShapeAngleRoundBehavior Instance = new ShapeAngleRoundBehavior(); + private ShapeAngleRoundBehavior() {} + public double Process(double angle) { + return Math.Round((angle+45)/90)*90 - 45; + } + } + public class LineAngleRoundBehavior : IDoubleProcessor { + public static LineAngleRoundBehavior Instance = new LineAngleRoundBehavior(); + private LineAngleRoundBehavior() {} + public double Process(double angle) { + return Math.Round(angle/15)*15; + } + } + public class FixedAngleRoundBehavior : IDoubleProcessor { + private double fixedAngle; + public FixedAngleRoundBehavior(double fixedAngle) { + this.fixedAngle = fixedAngle; + } + public double Process(double angle) { + return this.fixedAngle; + } + } + + + + + + /*public static int FindGripperPostition(float anchorX, float anchorY, float gripperX, float gripperY) { + if(gripperY > anchorY) { + if(gripperX > anchorY) return Gripper.POSITION_BOTTOM_RIGHT; + else return Gripper.POSITION_BOTTOM_LEFT; + } else { + if(gripperX > anchorY) return Gripper.POSITION_TOP_RIGHT; + else return Gripper.POSITION_TOP_LEFT; + } + }*/ + } } + \ No newline at end of file diff --git a/Greenshot/Helpers/SoundHelper.cs b/Greenshot/Helpers/SoundHelper.cs index 22fc8548f..c6d5a0093 100644 --- a/Greenshot/Helpers/SoundHelper.cs +++ b/Greenshot/Helpers/SoundHelper.cs @@ -19,12 +19,11 @@ * along with this program. If not, see . */ using System; -using System.IO; using System.Reflection; using System.Resources; using System.Runtime.InteropServices; -using Greenshot.UnmanagedHelpers; +using GreenshotPlugin.UnmanagedHelpers; /// /// Create to fix the sometimes wrongly played sample, especially after first start from IDE @@ -34,15 +33,11 @@ namespace Greenshot.Helpers { /// /// Description of SoundHelper. /// - public class SoundHelper { + public static class SoundHelper { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(SoundHelper)); private static GCHandle? gcHandle = null; private static byte[] soundBuffer = null; - - private SoundHelper() { - // Prevent instanciating - } public static void Initialize() { try { diff --git a/Greenshot/Helpers/StartupHelper.cs b/Greenshot/Helpers/StartupHelper.cs index b7519682c..6ae331e4c 100644 --- a/Greenshot/Helpers/StartupHelper.cs +++ b/Greenshot/Helpers/StartupHelper.cs @@ -19,20 +19,14 @@ * along with this program. If not, see . */ using System; -using System.Security; -using System.Security.AccessControl; -using System.Security.Permissions; -using System.Security.Principal; -using System.Text; using System.Windows.Forms; - using Microsoft.Win32; namespace Greenshot.Helpers { /// /// A helper class for the startup registry /// - public class StartupHelper { + public static class StartupHelper { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(StartupHelper)); private const string RUNKEY = @"Software\Microsoft\Windows\CurrentVersion\Run"; diff --git a/Greenshot/Helpers/ToolStripItemEndisabler.cs b/Greenshot/Helpers/ToolStripItemEndisabler.cs index e8f564d43..3fd589684 100644 --- a/Greenshot/Helpers/ToolStripItemEndisabler.cs +++ b/Greenshot/Helpers/ToolStripItemEndisabler.cs @@ -19,7 +19,6 @@ * along with this program. If not, see . */ using System; -using System.ComponentModel; using System.Windows.Forms; namespace Greenshot.Helpers { @@ -28,13 +27,10 @@ namespace Greenshot.Helpers { /// (parent) OwnerItems are ENabled with ToolStripItems, /// (child) DropDownItems are ENabled and DISabled with ToolStripItems. /// - public class ToolStripItemEndisabler { + public static class ToolStripItemEndisabler { [Flags] enum PropagationMode {NONE=0, CHILDREN=1, ANCESTORS=2}; - private ToolStripItemEndisabler() { - } - /// /// Enables all of a ToolStrip's children (recursively), /// but not the ToolStrip itself diff --git a/Greenshot/Helpers/UpdateHelper.cs b/Greenshot/Helpers/UpdateHelper.cs index 8831fa3d5..5083850d4 100644 --- a/Greenshot/Helpers/UpdateHelper.cs +++ b/Greenshot/Helpers/UpdateHelper.cs @@ -22,63 +22,21 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; -using System.IO; using System.Net; using System.Reflection; -using System.Text; using System.Text.RegularExpressions; using System.Windows.Forms; -using System.Xml; using Greenshot.Configuration; -using GreenshotPlugin.Controls; using GreenshotPlugin.Core; +using IniFile; namespace Greenshot.Experimental { - public class SourceforgeFile { - private string file; - public string File { - get {return file;} - } - private DateTime pubdate; - public DateTime Pubdate { - get {return pubdate;} - } - private string link; - public string Link { - get {return link;} - } - private string directLink; - public string DirectLink { - get {return directLink;} - } - private Version version; - public Version Version { - get {return version;} - set { - version = value; - } - } - private string language; - public string Language { - get {return language;} - set {language = value;} - } - - public SourceforgeFile(string file, string pubdate, string link, string directLink) { - this.file = file; - this.pubdate = DateTime.Parse(pubdate); - this.link = link; - this.directLink = directLink; - } - } - /// /// Description of RssFeedHelper. /// - public class UpdateHelper { + public static class UpdateHelper { private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(UpdateHelper)); - private const String RSSFEED = "https://sourceforge.net/api/file/index/project-id/191585/mtime/desc/rss"; private static CoreConfiguration conf = IniConfig.GetIniSection(); private static Dictionary mirrors = new Dictionary(); private static object lockObject = new object(); @@ -132,10 +90,9 @@ namespace Greenshot.Experimental { UpdateHelper.ProcessRSSInfo(currentVersion); if (latestGreenshot != null) { ILanguage lang = Language.GetInstance(); - DialogResult result = MessageBox.Show(lang.GetFormattedString(LangKey.update_found, latestGreenshot.Version), "Greenshot", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly, false); - if (result == DialogResult.OK) { - Process.Start(latestGreenshot.Link); - } + MainForm.instance.notifyIcon.BalloonTipClicked += HandleBalloonTipClick; + MainForm.instance.notifyIcon.BalloonTipClosed += CleanupBalloonTipClick; + MainForm.instance.notifyIcon.ShowBalloonTip(10000, "Greenshot", lang.GetFormattedString(LangKey.update_found, latestGreenshot.Version), ToolTipIcon.Info); } conf.LastUpdateCheck = DateTime.Now; IniConfig.Save(); @@ -145,10 +102,28 @@ namespace Greenshot.Experimental { } } + private static void CleanupBalloonTipClick(object sender, EventArgs e) { + MainForm.instance.notifyIcon.BalloonTipClicked -= HandleBalloonTipClick; + MainForm.instance.notifyIcon.BalloonTipClosed -= CleanupBalloonTipClick; + } + + private static void HandleBalloonTipClick(object sender, EventArgs e) { + try { + if (latestGreenshot != null) { + Process.Start(latestGreenshot.Link); + } + } catch (Exception) { + ILanguage lang = Language.GetInstance(); + MessageBox.Show(lang.GetFormattedString(LangKey.error_openlink, latestGreenshot.Link),lang.GetString(LangKey.error)); + } finally { + MainForm.instance.notifyIcon.BalloonTipClicked -= HandleBalloonTipClick; + MainForm.instance.notifyIcon.BalloonTipClosed -= CleanupBalloonTipClick; + } + } + private static void ProcessRSSInfo(Version currentVersion) { // Reset latest Greenshot - latestGreenshot = null; - Dictionary> rssFiles = readRSS(); + Dictionary> rssFiles = SourceForgeHelper.readRSS(); if (rssFiles == null) { return; @@ -210,106 +185,5 @@ namespace Greenshot.Experimental { // } // } } - - /// - /// Read the Greenshot RSS feed, so we can use this information to check for updates - /// - /// Dictionary> with files and their RssFile "description" - private static Dictionary> readRSS() { - HttpWebRequest webRequest = (HttpWebRequest)GreenshotPlugin.Core.NetworkHelper.CreatedWebRequest(RSSFEED); - XmlTextReader rssReader = new XmlTextReader(webRequest.GetResponse().GetResponseStream()); - XmlDocument rssDoc = new XmlDocument(); - - // Load the XML content into a XmlDocument - rssDoc.Load(rssReader); - - // Loop for the tag - XmlNode nodeRss = null; - for (int i = 0; i < rssDoc.ChildNodes.Count; i++) { - // If it is the rss tag - if (rssDoc.ChildNodes[i].Name == "rss") { - // tag found - nodeRss = rssDoc.ChildNodes[i]; - } - } - - if (nodeRss == null) { - LOG.Debug("No RSS Feed!"); - return null; - } - - // Loop for the tag - XmlNode nodeChannel = null; - for (int i = 0; i < nodeRss.ChildNodes.Count; i++) { - // If it is the channel tag - if (nodeRss.ChildNodes[i].Name == "channel") { - // tag found - nodeChannel = nodeRss.ChildNodes[i]; - } - } - - if (nodeChannel == null) { - LOG.Debug("No channel in RSS feed!"); - return null; - } - - Dictionary> rssFiles = new Dictionary>(); - - // Loop for the , <link>, <description> and all the other tags - for (int i = 0; i < nodeChannel.ChildNodes.Count; i++) { - // If it is the item tag, then it has children tags which we will add as items to the ListView - - if (nodeChannel.ChildNodes[i].Name == "item") { - XmlNode nodeItem = nodeChannel.ChildNodes[i]; - string sfLink = nodeItem["link"].InnerText; - string pubdate = nodeItem["pubDate"].InnerText; - try { - Match match= Regex.Match(Uri.UnescapeDataString(sfLink), @"^http.*sourceforge.*\/projects\/([^\/]+)\/files\/([^\/]+)\/([^\/]+)\/(.+)\/download$"); - if (match.Success) { - string project = match.Groups[1].Value; - string subdir = match.Groups[2].Value; - string type = match.Groups[3].Value; - string file = match.Groups[4].Value; - // !!! Change this to the mirror !!! - string mirror = "kent"; - string directLink = Uri.EscapeUriString("http://"+mirror+".dl.sourceforge.net/project/"+project+"/"+subdir+"/"+type+"/"+file); - Dictionary<string, SourceforgeFile> filesForType; - if (rssFiles.ContainsKey(type)) { - filesForType = rssFiles[type]; - } else { - filesForType = new Dictionary<string, SourceforgeFile>(); - rssFiles.Add(type, filesForType); - } - SourceforgeFile rssFile = new SourceforgeFile(file, pubdate, sfLink, directLink); - if (file.EndsWith(".exe") ||file.EndsWith(".zip")) { - string version = Regex.Replace(file, ".*[a-zA-Z]-", ""); - version = Regex.Replace(version, ".exe$", ""); - version = Regex.Replace(version, ".zip$", ""); - if (version.Trim().Length > 0) { - version = version.Replace('-','.'); - version = version.Replace(',','.'); - try { - rssFile.Version = new Version(version); - } catch (Exception) { - LOG.DebugFormat("Found invalid version {0} in file {1}", version, file); - } - } - } - if (type.Equals("Translations")) { - string culture = Regex.Replace(file, @"[a-zA-Z]+-(..-..)\.(xml|html)", "$1"); - CultureInfo cultureInfo = new CultureInfo(culture); - rssFile.Language = cultureInfo.NativeName; - } - filesForType.Add(file, rssFile); - } - } catch (Exception ex) { - LOG.WarnFormat("Couldn't read RSS entry for: {0}", nodeChannel["title"].InnerText); - LOG.Warn("Reason: ", ex); - } - } - } - - return rssFiles; - } } } diff --git a/Greenshot/Languages/help-en-US.html b/Greenshot/Languages/help-en-US.html index 263e73a2c..078f219e1 100644 --- a/Greenshot/Languages/help-en-US.html +++ b/Greenshot/Languages/help-en-US.html @@ -112,6 +112,13 @@ point the mouse cursor to the window and hit the <kbd>PgDown</kbd> key. After doing so, you can select child elements of the window to be captured. </p> + <p class="hint"> + Capturing context menus on their own is different: using the "Capture window" + shortcut would make the context menu disappear, and obviously the same would happen + if you used Greenshot's context menu in order to create the screenshot. If you want + to capture a context menu you have just brought up by right-clicking anything, + simply activate region mode <kbd>Print</kbd>, then press the <kbd>Space</kbd> key. + </p> <a name="capture-fullscreen"></a> <h3>Capture fullscreen <kbd>Control</kbd> + <kbd>Print</kbd></h3> @@ -154,8 +161,8 @@ Select one of the shape drawing tools from the toolbar on the left hand side of the image editor or from the <em>Object</em> menu. There is also a key assigned to each tool for your convenience.<br> - Available shapes are: rectangle <kbd>R</kbd>, ellipse <kbd>E</kbd>, line <kbd>L</kbd> - and arrow <kbd>A</kbd>.<br> + Available shapes are: rectangle <kbd>R</kbd>, ellipse <kbd>E</kbd>, line <kbd>L</kbd>, + arrow <kbd>A</kbd> and freehand line <kbd>F</kbd>.<br> Click, hold down the mouse button and drag to define position and size of the shape. Release the mouse button when you are done. </p> @@ -170,6 +177,17 @@ You can select multiple elements for editing at a time. In order to select multiple elements, hold down the <kbd>Shift</kbd> key while clicking the elements. </p> + <p class="hint"> + If you want to draw equilateral shapes (e.g. force a rectangle to be a square) hold + down <kbd>Shift</kbd> while drawing. When drawing lines or arrows, holding down <kbd>Shift</kbd> + results in the line's angle being rounded in steps 15.<br> + You can also use <kbd>Shift</kbd> if you want to resize an existing object maintaining it's aspect ratio. + </p> + <p class="hint"> + When drawing or scaling, you can hold down <kbd>Ctrl</kbd> to have the object anchored in + it's geometrical middle. I.e. the object is resized in the opposite direction, too. (This + is very handy if you want to draw an ellipse around something on your screenshot.) + </p> <a name="editor-text"></a> <h3>Adding text</h3> diff --git a/Greenshot/Languages/help-fr-FR.html b/Greenshot/Languages/help-fr-FR.html new file mode 100644 index 000000000..131c68827 --- /dev/null +++ b/Greenshot/Languages/help-fr-FR.html @@ -0,0 +1,289 @@ + +<html> + <head> + <title>Aide Greenshot - version franaise + + + +

Aide Greenshot

+ + Version 0.8 - traduction franaise par Thierry Henkart + +

Contenu

+
    +
  1. Crer une copie d'cran
  2. +
      +
    1. Capturer une zone d'cran
    2. +
    3. Capturer la dernire zone d'cran
    4. +
    5. Capturer une fentre
    6. +
    7. Capturer tout l'cran
    8. +
    + +
  3. Utilisation de l'diteur d'image
  4. +
      +
    1. Dessiner des formes
    2. +
    3. Ajouter du texte
    4. +
    5. Mettre en surbrillance
    6. +
    7. Masquer
    8. +
    9. Rogner
    10. +
    11. Rutiliser des lments
    12. +
    13. Exporter la capture d'cran
    14. +
    +
  5. Dialogue Prfrences
  6. +
      +
    1. Gnral
    2. +
    3. Sortie
    4. +
    5. Imprimante
    6. +
    +
  7. Dsirez-vous collaborer?
  8. +
      +
    1. Pensez un don
    2. +
    3. Faites connatre l'outil
    4. +
    5. Proposez une traduction
    6. +
    +
+ + +

Crer une copie d'cran

+

+ Vous pouvez crer une copie d'cran soit en utilisant la touche Print de votre clavier, + soit en effectuant un click droit sur l'icne Greenshot dans la barre de tches.
+ Il y a plusieurs options de cration d'une capture d'cran : +

+ +

Capturer une zone d'cran Print

+

+ Le mode "capture de zone d'cran" vous permet de slectionner la partie de votre cran capturer.
+ Lorsque vous tes dans ce mode, vous verrez le pointeur de votre souris remplac par une croix. + Faites un click gauche sur l'un des coins de la zone que vous voulez slectionnez, et + maintenez le bouton enfonc. Dplacez votre souris, toujours bouton gauche enfonc, + afin de dterminer la zone rectangulaire que vous dsirez slectionner. + Lorsque le rectangle vert recouvre la surface que vous souhaitez capturer, + relachez le bouton de la souris. +

+

+ Vous pouvez utiliser la barre d'espace Space pour switcher entre + le mode "zone d'cran" et le mode "fentre". +

+

+ Si vous souhaitez capturer une zone avec prcision, il peut tre plus facile de slectionner une capture d'cran + initiale lgrement plus grande et de rogner la capture ensuite en utilisant l'diteur + d'image de Greenshot +

+ + +

Capturer la dernire zone d'cran Shift + Print

+

+ Si vous avez effectu une capture de zone ou de fentre + auparavant, vous pouvez re-capturer la mme rgion grce cette option. +

+ + +

Capturer une fentre Alt + Print

+

+ Cre une capture d'cran de la fentre active. +

+

+ Le dialogue Prfrences offre l'option de ne pas capturer + d'office la fentre active, mais de slectionner une fentre de manire interactive. + Si cette option est slectionne, vous pouvez slectionner une fentre en cliquant dessus + (comme dans la capture de zone d'cran, Greenshot va + mettre en surbrillance la zone qui va tre capture.
Si vous dsirez qu'une fentre "fille" soit capture ou un simple cadre, positionnez le curseur de la souris et appuyez sur la touche "Page Down" PgDown. Vous pourrez ensuite slectionner l'lment souhait. +

+ + +

Capturer tout l'cran Control + Print

+

+ Cre une copie de tout l'cran. +

+ + +

Utiliser l'diteur d'image

+

+ Greenshot est fourni avec un diteur d'images d'utilisation simple, proposant une panoplie + d'outils permettant des annotations ou l'ajout de formes la capture d'cran. Il permet galement de mettre en vidence ou de masquer certaines parties de la capture d'cran. +

+

+ L'diteur d'image Greenshot peut tre utilis galement pour ouvrir des images partir de fichiers ou du bloc-notes. Faites simplement un click droit sur l'icne Greenshot dans la barre d'outils + et choisissez respectivement Ouvrir partir du fichier + ou Ouvrir l'image du presse-papier. +

+

+ Par dfaut, l'diteur d'image s'ouvre lorsqu'un cran est captur. Si vous ne dsirez pas utiliser l'diteur d'images, vous pouvez le dsactiver dans les Prfrences. +

+ + + +

Dessiner des formes

+

+ Slectionnez un des outils de dessin de formes depuis la barre d'outils gauche de l'diteur d'images ou du menu Objet. Il existe aussi une touche assigne chaque outil, votre convenance.
+ Les formes disponibles sont: le rectangle R, l'ellipse E, la ligne L + et la flche A.
+ Cliquez, maintenez le bouton de la souris, et dplacez-la pour dfinir la position et la taille de la forme. Librez le bouton de souris quand vous avez termin. +

+

+ Vous pouvez dplacer ou redimensionner des formes existantes aprs avoir slectionn l'outil de slection ESC depuis la barre d'outils.
Pour chaque type d'lment , il y a une srie d'options disponibles pour changer l'aspect des lments (par exemple, l'paisseur du trait, la couleur de la ligne, la couleur de remplissage). Vous pouvez changer les options d'un lment existant aprs l'avoir slectionn, mais galement celle de l'lment que vous allez dessiner ensuite.

+

+ Vous pouvez slectionner en une seule fois plusieurs lments diter en maintenant la touche Shift enfonce lorsque vous slectionnez les lments choisis. +

+ + +

Ajouter du texte

+

+ L'utilisation de l'outil texte T est semblable celle de l'outil + formes. Dessinez simplement la bote de texte la taille dsire, et introduisez alors le texte.
Pour diter un texte existant, double-clickez sur celui-ci.

+ + +

Mettre des lments en surbrillance

+

+ Aprs avoir slectionn l'outil de surbrillance, faites exactement comme si vouliez dessiner une forme.
+ Il y a plusieurs options de surbrillance que vous pouvez slectionner en cliquant sur le bouton gauche dans la barre d'outil au dessus. +

+
    +
  • Mettre un texte en surbrillance : met en vidence un texte en lui appliquant une couleur brillante, comme le ferait un marqueur fluo
  • +
  • Mettre une zone en surbrillance : floute * et assombrit tout ce qui est en dehors de la zone slectionne
  • +
  • Echelle de gris : tout ce qui est en dehors de la zone slectionne est gris
  • +
  • Agrandissement : la zone slectionne est affiche agrandie.
  • +
+ + +

Masquer des lments

+

+ Masquer des lments de la capture d'cran est une bonne ide, partir du moment o celle-ci contient des donnes confidentielles, par exemple des numros de compte, des noms, des mots de passe, des visages.
Utilisez l'outil de masquage O exactement comme l'outil de surbrillance.
+ Les options disponibles pour le masquage sont : +

+
    +
  • Pixelisation: augmente la taille des pixels pour la zone slectionne
  • +
  • Floutage*: floute la zone slectionne
  • +
+ +

+ * Suivant les capacits de votre ordinateur, le floutage peut altrer les performances + de l'diteur d'images Greenshot. S'il vous semble que l'diteur d'image ralentit sensiblement en cas de floutage, essayez de rduire les valeurs de Preview quality dans la barre d'outils, ou diminuez la taille de pixel.
+ Si la performance de floutage est toujours trop mauvaise, utilisez alors plutt la pixelisation. +

+ + +

Rogner la capture d'cran

+

+ Si vous n'avez besoin que d'une partie de l'cran captur, utilisez l'outil de rognage C + pour slectionner uniquement la surface souhaite.
+ Aprs avoir slectionn l'outil de rognage, dessinez un rectangle reprsentant la surface que vous souhaitez conserver. Vous pouvez modifier la taille de cet lment votre gr.
+ Lorsque vous tes satisfait de votre slection, confirmez votre choix dans la barre d'outil, ou tapez Enter. Vous pouvez annuler le rognage via le bouton "Cancel" ou en tapant + ESC. +

+ + +

Rutilisation d'lments dessins

+

+ Si vous vous apercevez que vous rutilisez des lments identiques ou similaires + dans vos captures d'crans (par ex. des lments de texte contenant le type et version du browser, ou que vous masquez le mme lment sur plusieurs captures d'crans), vous pouvez rutiliser certains lments.
+ Slectionnez Sauvegarder les objets dans un fichier depuis le menu Objet pour sauvegarder les lments que vous dsirez rutiliser plus tard. Charger les objets depuis un fichier permet d'appliquer les mmes lments une nouvelle capture d'cran. +

+ + +

Exporter une capture d'cran

+

+ Aprs avoir dit votre capture d'cran, vous pouvez exporter le rsultat pour diffrents usages, selon vos besoins. + Vous pouvez accder toutes les options d'export vie le menu Fichier ou via des shortcuts. +

+
    +
  • Sauvegarder Control + S: sauvegarde l'image dans un fichier (si l'image a dj t sauvegarde, sinon affiche le dialogue Sauvegarder sous...
  • +
  • Sauvegarder sous... Control + Shift + S: vous permet de choisir le chemin, le nom de fichier et le format du fichier sauvegarder
  • +
  • Copier l'image vers le presse-papier Control + Shift + C: insre une copie de l'image dans le presse-papier, ce qui vous permet de la copier dans d'autres programmes
  • +
  • Imprimer... Control + P: envoie l'image l'imprimante
  • +
  • e-mail Control + E: ouvre un nouveau message dans votre client mail par dfaut, en ajoutant l'image comme annexe
  • +
+

+ Aprs avoir sauvegard une image depuis l'diteur, vous pouvez clicker dans la barre d'tat en bas de l'diteur (click droit) afin de soit copier le chemin de sauvegarde dans le presse-papier, soit ouvrir le rpertoire dans l'explorateur Windows. +

+ + + +

Le dialogue "Prfrences"

+ + +

Gnral

+
    +
  • Langue : Langue prfre.
    + Vous pouvez tlcharger des langues additionnelles pour Greenshot ici.
  • +
  • Enregistrer les raccourcis clavier: Si slectionn, Greenshot peut tre utilis avec la touche Print.
  • +
  • Lancer Greenshot au dmarrage : Dmarre le programme au boot du systme.
  • +
  • Faire flasher l'cran : Retour visuel lors d'une capture d'cran
  • +
  • Jouer un son d'appareil photo : Retour audio lors d'une capture d'cran
  • +
  • Capturer le pointeur de la souris : Si slectionn, le pointeur de la souris sera captur. Le pointeur sera gr comme un lment spar dans l'diteur, de manire pouvoir le dplacer ou le supprimer plus tard.
  • +
  • Utiliser le mode interactif de capture de fentre : Plutt que de capturer directement la fentre active, le mode interactif vous permet de slectionner la fentre capturer. Il est galement possible de capturer des fentres imbriques, voir capturer une fentre.
  • +
+ + +

Sortie

+
    +
  • Destination de la capture d'cran : Vous permet de choisir la ou les destination(s) de votre capture d'cran.
  • +
  • Prfrences d'enregistrement : Rpertoire et nom de fichier utiliser lors de la sauvegarde direct ou suggrer lors de la sauvegarde avec le dialogue "sauver comme...". Cliquer sur le bouton ? pour obtenir plus d'information sur les variables utilisables comme paramtres dans le nom de fichier.
  • +
  • Paramtres JPEG : Qualit utiliser lors d'une sauvegarde JPEG
  • +
+ + +

Imprimante

+
    +
  • Rduire aux dimensions de la page : Si l'image dpasse la taille du papier, elle sera rduite aux dimensions de la page.
  • +
  • Elargir aux dimensions de la page : Si l'image est infrieure la taille du papier, elle sera largie pour tre imprime aussi grande que possible, sans dpasser la taille du papier.
  • +
  • Tourner l'impression selon l'orientation de la page: Va retourner un format d'image paysage de 90 pour l'imprimer.
  • +
+ + + +

Dsirez-vous collaborer?

+ +

+ Actuellement, nous n'avons pas besoin d'aide au niveau dveloppement. Cependant, il y a plusieurs choses que vous pouvez faire pour aider Greenshot et l'quipe de dveloppement. Merci d'avance :) +

+ + +

Envisagez un don

+

+ Nous nous investissons dans Greenshot et dpensons pas mal de notre temps pour dvelopper un logiciel gratuit et opensource. Si vous avez l'impression que cela vous rend plus productif, si cela vous fait gagner du temps et de l'argent ( vous ou votre compagnie), ou si simplement vous aimez Greenshot et l'ide d'un software opensource : pensez rcompenser nos efforts par une petite participation.
+ Jetez un coup d'oeil notre site pour voir comment supporter l'quipe de dveloppement Greenshot:
+ http://getgreenshot.org/support/ +

+ + +

Faites connatre l'outil

+

+ Si vous apprciez Greenshot, faites-le connatre aux autres : parlez de Greenshot vos amis et vos collgues. Sur les sites sociaux galement.
+ Recommandez Greenshot dans les forums ; rajoutez des liens sur vos sites ou vos blogs.

+ + +

Proposez une traduction

+

+ Greenshot n'est pas disponible dans votre langue prfre? Si vous vous sentez d'attaque pour traduire une partie de l'application , vous tes plus que bienvenu. + Si vous tes un utilisateur enregistr sur sourceforge.net, vous pouvez soumettre des traductions + translations tracker.
+ Assurez-vous qu'il n'y a pas de traduction dans votre langue sur + downloads page. Vrifiez galement sur translations tracker, + il pourrait y avoir une traduction en cours ou au moins en discussion.
+ Veuillez prendre note du fait que nous ne publierons sur notre page de tlchargement que les traductions qui auront t introduites via votre compte utilisateur sourceforge.net. Vu qu'il est plus que probable que nous ne pourrons comprendre votre traduction, ce serait bien que les autres utilisateurs de sourceforge puissent vous contacter pour des amliorations ou des adaptations dans le cas d'une nouvelle version de Greenshot. +

+

+ +Des remarques, des commentaires, des corrections ? +Merci de contacter traducere@henkart.be + + + + diff --git a/Greenshot/Languages/help-pl-PL.html b/Greenshot/Languages/help-pl-PL.html new file mode 100644 index 000000000..7e2ad2396 --- /dev/null +++ b/Greenshot/Languages/help-pl-PL.html @@ -0,0 +1,337 @@ + + + + Greenshot Help + + + + +

Pomoc Greenshot

+ + Wersja 0.8 + +

Zawartość

+
    +
  1. Tworzenie zrzutu ekranu
  2. +
      +
    1. Przechwytywanie obszaru
    2. +
    3. Przechwytywanie ostatniego obszaru
    4. +
    5. Przechwytywanie okna
    6. +
    7. Przechwytywanie pełnego ekranu
    8. +
    + +
  3. Korzystanie z edytora graficznego
  4. +
      +
    1. Rysowanie kształtów
    2. +
    3. Dodawanie tekstu
    4. +
    5. Wyróżnianie miejsc
    6. +
    7. Maskowanie miejsc
    8. +
    9. Kadrowanie zrzutu ekranu
    10. +
    11. Wykorzystanie opracowanych elementów
    12. +
    13. Eksportowanie zrzutu ekranu
    14. +
    +
  5. Okno ustawień
  6. +
      +
    1. Ustawienia ogólne
    2. +
    3. Ustawienia wyjściowe
    4. +
    5. Ustawienia drukarki
    6. +
    +
  7. Chcesz pomóc?
  8. +
      +
    1. Rozważ darowiznę
    2. +
    3. Opowiadaj o nas
    4. +
    5. Dodaj tłumaczenie
    6. +
    +
+ + +

Tworzenie zrzutu ekranu

+

+ Można utworzyć zrzut ekranu albo za pomocą klawisza Print na klawiaturze + lub klikając prawym przyciskiem myszy ikonę Greenshot w zasobniku systemowym.
+ Istnieje kilka opcji tworzenia zrzutu ekranu: +

+ + +

Przechwytywanie obszaruPrint

+

+ Tryb przechwytywania obszaru pozwala przechwycić tylko wybraną część ekranu.
+ Po uruchomieniu trybu obszaru pojawi się celownik, zamiast wskaźnika myszy. Kliknij + i przytrzymaj lewy przycisk myszy, w jednym z rogów obszaru z którego chcesz wykonać + zrzut ekranu. Wciąż trzymając wciśnięty przycisk myszy, przeciągnij myszą aby zdefiniować + prostokąt obszaru do przechwycenia. Kiedy zielony prostokąt obejmie obszar, który chcesz + by był przechwycony w zrzutcie ekranu, po prostu zwolnij przycisk myszy. +

+

+ Możesz użyć klawisza Space , aby przełączyć między trybem obszaru + a trybem okno. +

+

+ Jeśli chcesz zrobić dokładny zrzut obszaru, może łatwiej będzie wybrać początkową + powierzchnię zrzutu ekranu trochę większą, i potem przyciąć + zrzut ekranu za pomocą edytora obrazu Greenshot. +

+ + +

Przechwytywanie ostatniego obszaru Shift + Print

+

+ Jeśli nie przechwyciłeś obszaru, lub okna + wcześniej, możesz przechwycić ten sam obszar ponownie, używając tej opcji. +

+ + +

Przechwytywanie okna Alt + Print

+

+ Tworzy zrzut ekranu z okna, które jest aktualnie aktywne. +

+

+ Okno ustawień oferuje możliwość nie przejmowania + aktywnego okna od razu, ale pozwala wybrać jedno interaktywnie. + Jeśli ta opcja jest zaznaczona, użytkownik może wybrać okno, klikając go + (jak w trybie obszaru, Greenshot wyróżni obszar + który będzie przechwytywany).
Jeśli chcesz przechwycić okno wewnętrzne (np. + w przeglądarce podglądu (bez paska narzędzi itp.) lub pojedynczą klatkę strony + internetowej używając ramki), ustaw wskaźnik kursora myszy w oknie i naciśnij klawisz + PgDown. Teraz możesz wybrać wewnętrzne okno do przechwycenia. +

+ + +

Przechwytywanie pełnego ekranu Control + Print

+

+ Tworzy kompletny zrzut całego ekranu. +

+ + +

Korzystanie z edytora graficznego

+

+ Greenshot jest wyposażony w łatwy w użyciu edytor zdjęć, zapewniając wygodne + narzędzia retuszu do dodawania adnotacji lub kształtów na ekranie. Umożliwia nawet + podkreślenie lub ukrycie części ekranu. +

+

+ Edytor obrazów Greenshot'a nie musi być używany tylko do zrzutów ekranu. Można również + otworzyć do edycji obrazy z pliku lub ze schowka. Kliknij prawym przyciskiem myszy + ikonę Greenshot w zasobniku systemowym i wybierz odpowiednio, Otwórz obraz z pliku + lub Otwórz obraz ze schowka. +

+

+ Domyślnie, edytor zdjęć zostanie otwarty, gdy zrzutu ekranu zostanie + przechwycony. Jeśli nie chcesz korzystać z edytora obrazów, możesz wyłączyć tę + opcję, w oknie ustawień. +

+ + + +

Rysowanie kształtów

+

+ Wybierz jedno z narzędzi do rysowania kształtów, z paska narzędzi po lewej stronie + edytora zdjęć, lub z menu Objekt. Dla Twojej wygody, istnieje również + przypisany klawisz dla każdego narzędzia.
+ Dostępne kształty: prostokąt R, elipsa E, linia L + i strzałki A.
+ Kliknij prawy przycisk, przytrzymaj naciśnięty przycisk myszy i przeciągnij, + aby określić położenie i rozmiar kształtu. Zwolnij przycisk myszy, gdy skończysz. +

+

+ Można przenieść lub zmienić rozmiar istniejącego kształtu po wybraniu narzędzia + ESC z paska narzędzi.
Dla każdego typu elementu jest określony zestaw + dostępnych opcji do zmiany wyglądu elementu (np. grubość linii, kolor linii, kolor + wypełnienia). Możesz zmienić opcje dla istniejącego elementu, po jego wybraniu. + Ale także dla następnego elementu jaki należy rysować, po wybraniu narzędzia do rysowania. +

+

+ Możesz wybrać wiele elementów do edycji na raz. Aby zaznaczyć kilka elementów, + przytrzymaj klawisz Shift podczas zaznaczania wybranych elementów. +

+ + +

Dodawanie tekstu

+

+ Korzystanie z narzędzia tekstowego T jest podobne do korzystania z + narzędzikształtu. Wystarczy narysować okienko tekstowe, + do żądanego rozmiaru, a następnie wpisać tekst.
+ Kliknij dwukrotnie istniejący element tekstowy, aby edytować tekst. +

+ + +

Wyróżnianie miejsc

+

+ Po wybraniu narzędzia wyróżnienia H, możemy zdefiniować obszar przeznaczony do + wyróżnienia, dokładnie w takim kształcie jaki chcesz narysować.
+ Istnieje kilka opcji wyróżniania, które można wybrać poprzez kliknięcie prawym przyciskiem + myszy na pasku narzędzi u góry: +

+
    +
  • Wyróżnianie tekstu: wyróżnia obszar przez zastosowanie jasnych kolorów dla tła, podobnie + jak biurowy zakreślacz tekstu
  • +
  • Wyróżnij obszar: zamglenie * , i wszystko przyciemnieje, poza zaznaczonym obszarem
  • +
  • Skala szarości: wszystko, poza zaznaczonym obszarem, zostanie włączone do skali szarości
  • +
  • Powiększenie: zaznaczony obszar zostanie wyświetlony w powiększeniu
  • +
+ + +

Maskowanie miejsc

+

+ Maskowanie części ekranu jest dobrym pomysłem, jeśli zrzut zawiera dane, które nie są + przeznaczone dla innych osób, np. dane konta bankowego, nazwy, hasła lub twarze na zdjęciach.
+ Użyj narzędzi maskowania O dokładnie tak, jak używa się narzędzi + wyróżniania.
+ Dostępne opcje dla maskowania to: +

+
    +
  • Rozmiar piksela: zwiększa rozmiar w pikselach, zaznaczonego obszaru
  • +
  • Zamglenie*: rozmywa zaznaczony obszar
  • +
+ +

+ * W zależności od wydajności komputera, stosowanie efektu zamglenia może spowolnić + edytor obrazu Greenshota Jeśli uważasz, że edytor zdjęć reaguje powoli, jak tylko + zastosujesz zamglenie, spróbuj zmniejszyć wartość Jakość podglądu na pasku narzędzi, + lub zmniejszyć wartość Zakres zamglenia.
+ Jeśli wydajność zamglenia jest jeszcze zbyt niekorzystna do pracy z nim, możesz preferować + korzystanie z efektu Rozmiar piksela , zamiast efektu Zamglenia. +

+ + +

Kadrowanie zrzutu ekranu

+

+ Jeśli potrzebujesz, by tylko część zrzutu ekranu została zarejestrowana, za pomocą narzędzia + przycinania C , możesz przyciąć go do żądanego obszaru.
+ Po wybraniu narzędzia przycinania, narysuj prostokąt na obszarze zrzutu ekranu, który chcesz + zachować. Można zmienić rozmiar zaznaczonego obszaru, jak każdy inny element.
+ Kiedy jesteś zadowolony z wyboru, użyj przycisku potwierdzenia na pasku narzędzi, lub naciśnij + klawisz Enter . Możesz anulować kadrowanie, klikając przycisk Anuluj, lub klawisz + ESC, na klawiaturze +

+ + +

Wykorzystanie opracowanych elementów

+

+ Jeżeli zechcesz użyć tych samych, lub podobnych elementów, do większości zrzutów ekranu + (np. pole tekstowe zawierające typ i wersję przeglądarki, lub maskował te same + elementy na kilka zrzutach ekranu) można ponownie użyć elementów.
+ Wybierz Zapisz obiekty do pliku , w menu Objekt , aby zapisać bieżący + zbiór elementów do ponownego wykorzystania w przyszłości. Użycie narzędzia + Załaduj obiekty z pliku , zastosuje te same elementy do innego ekranu. +

+ + +

Eksportowanie zrzutu ekranu

+

+ Po zakończeniu edycji ekranu, można wyeksportować wynik w różnych celach, + w zależności od potrzeb. Możesz uzyskać dostęp do wszystkich opcji eksportu poprzez + menu Plik w pasku narzędzi, na samej górze, lub za pomocą skrótów: +

+
    +
  • Zapisz Control + S: zapisuje obraz do pliku (jeśli obraz został już zapisany, w przeciwnym wypadku wyświetla dialog Zapisz jako...)
  • +
  • Zapisz jako... Control + Shift + S: pozwala na wybór formatu, lokalizacji, nazwy pliku i obrazu dla zapisywanego pliku
  • +
  • Kopiuj obrazek do schowka Control + Shift + C: umieszcza kopię obrazu w schowku, umożliwiając wklejenie jej do innych programów
  • +
  • Drukuj... Control + P: przesyła obraz do drukarki
  • +
  • E-Mail Control + E: otwiera nową wiadomość, w domyślnym kliencie e-mail, dodając obraz jako załącznik
  • +
+

+ Po zapisaniu obrazu z edytora, kliknij prawym przyciskiem myszy na pasku stanu na dole + okna edytora, albo skopiuj ścieżkę pliku do schowka, lub otwórz zawierający go katalog, + w Eksploratorze Windows. +

+ + + +

Okno ustawień

+ + +

Ustawienia ogólne

+
    +
  • Język: Możesz wybrać język, który chcesz używać.
    + Możesz pobrać dodatkowe pliki językowe dla Greenshota, tutaj.
  • +
  • Rejestracja klawiszy skrótu: Po zaznaczeniu, Greenshot może być uruchamiany za pomocą klawisza Print.
  • +
  • Uruchom Greenshot przy starcie: Uruchomia program wraz ze startem systemu.
  • +
  • Pokaż błysk flesza: Efekt lampy błyskowej podczas wykonywania przechwytywania
  • +
  • Odtwórz dźwięk aparatu: Sygnał dźwiękowy migawki, podczas wykonywania przechwytywania
  • +
  • Przechwytywanie wskaźnika myszy: Jeżeli jest zaznaczone, zostanie przechwycony wskaźnik myszy. Wskaźnik jest obsługiwany jako osobny element w edytorze, dzięki czemu można go później przenieść lub usunąć.
  • +
  • Użyj trybu interaktywnego okna przechwytywanego: Zamiast przechwytywania aktywnego okna od razu, tryb interaktywny + pozwala wybrać okno do przechwytywania. Możliwe jest również przechwytywanie okien podrzędnych, zobacz Przechwytywanie okna.
  • +
+ + +

Ustawienia wyjściowe

+
    +
  • Miejsce zrzutu ekranu: Pozwala na wybór miejsca docelowego dla ulokowania zrzutu ekranu, po jego zrobieniu.
  • +
  • Preferowane ustawienia pliku wyjściowego: Katalog i nazwa pliku zapisu bezpośredniego, lub sugerowanego (za pomocą dialogu Zapisz jako...) podczas zapisywania. Kliknij przycisk ? , aby dowiedzieć się więcej o symbolach zastępczych, które mogą być użyte jako wzorzec nazwy pliku.
  • +
  • Ustawienia JPEG: Ustawienia jakości zapisu plików JPEG
  • +
+ + +

Ustawienia drukarki

+
    +
  • Zacieśnij wydruk aby dopasować rozmiar papieru: Jeśli obraz przekroczy rozmiar papieru, będzie zacieśniony, aby zmieścił się na stronie.
  • +
  • Powiększ wydruk aby dopasować rozmiar papieru: Jeśli obraz jest mniejszy niż rozmiar papieru, będzie skalowany do wydrukowania jak największy, nie przekraczając rozmiaru papieru.
  • +
  • Obróć wydruku do orientacji strony: Obraz będzie obrócony, w formacie krajobrazu, o 90 do drukowania.
  • +
+ + + +

Chcesz pomóc?

+ +

+ Obecnie nie potrzeba pomocy w rozwoju. Jednakże, istnieje kilka rzeczy, które + mogą wesprzeć Greenshot i deweloperów.
+ Z góry dziękuję :) +

+ + +

Rozważ darowiznę

+

+ Wkładamy dużo pracy w Greenshot i poświęcamy sporo czasu, aby zapewnić + kawał dobrego oprogramowania, o wolnym i otwartym kodzie źródłowym. Jeśli czujesz, + że zapewnia to większą wydajność pracy, jeśli oszczędza to Tobie (lub firmie) + dużo czasu i pieniędzy, czy po prostu podobnie jak Greenshot, popierasz ideę + oprogramowania open source:. rozważ uhonorowanie naszych wysiłków, przekazując darowiznę
+ Proszę spojrzeć na naszą stronę domową, aby zobaczyć, jak można wspierać zespół rozwoju Greenshot
+ http://getgreenshot.org/support/ +

+ + +

Rozpowszechnianie

+

+ Jeśli podoba Ci się Greenshot, niech ludzie się dowiedzą: powiedzieć swoim znajomym i kolegom o Greenshot. + Swoim zwolennikom, także :)
+ Oceń Greenshot na portalach z oprogramowaniem, lub wstaw łącze do naszej strony głównej, na swoim blogu lub stronie. +

+ + +

Dodaj tłumaczenie

+

+ Greenshot nie jest dostępny w wybranym języku? Jeśli uważasz, że nadaje się do tłumaczenia jakiś + kawałek oprogramowania, to jest to więcej niż mile widziane. + Jeżeli jesteś zarejestrowanym użytkownikiem na sourceforge.net, możesz przesłać tłumaczenia do naszego + działu tłumaczeń.
+ Upewnij się, że nie istnieje już tłumaczenie na Twój język w naszych + plikach do pobrania. Sprawdź również nasz dział tłumaczeń, + może być tam tłumaczenie w toku, lub przynajmniej w dyskusji.
+ Pamiętaj, my tylko dostarczamy tłumaczenie na naszej stronie plików do pobrania, jeżeli + zostały złożone za pośrednictwem konta użytkownika sourceforge.net. Ponieważ ktoś może + nie być w stanie zrozumieć tłumaczenia, w interesie innych użytkowników sourceforge jest to, + aby mogli skontaktować się z Tobą w sprawie ulepszeń i udoskonaleń, w przypadku nowej wersji + Greenshot. +

+ + + + + diff --git a/Greenshot/Languages/language-ar-SY.xml b/Greenshot/Languages/language-ar-SY.xml new file mode 100644 index 000000000..2d2b9619b --- /dev/null +++ b/Greenshot/Languages/language-ar-SY.xml @@ -0,0 +1,526 @@ + + + + + Translated by Ramzy Samman and Jamal Mashal تُرجم بواسطة رمزي السمان وجمال مشعل + + + جرين شوت - الاداة الثورية في تصوير الشاشة + + + ارسم مستطيل (R) + + + احفظ + + + التفضيلات... + + + مكان الحفظ + + + الاعدادات + + + مكان حفظ اللقطات بشكل افتراضي (اتركها فارغة للحفظ على سطح المكتب) + + + اللغة + + + نمط اسم الملف + + + لغة واجهة جرين شوت (يتطلب اعادة تشغيل البرنامج) + + + النمط المستخدم في تسمية الملفات عند حفظ الصورة + + + نوع الصورة + + + نوع الصورة الافتراضي + + + منطقة الالتقاط + + + التقط المنطقة السابقة + + + خروج + + + مؤثرات + + + تشغيل صوت عند الالتقاط + + + اظهار وميض + + + خطأ + + + لايمكن حفظ الصورة في {0}. +رجاء تاكد من القدرة على حفظ الملف في هذا المكان. + + + التقط كامل الشاشة + + + قص + + + نسخ + + + لصق + + + حول جرين شوت + + + حقوق النشر © 2007 - 2010 توماس براون, جينس كلنجين, روبين كروم +جرين شوت لا يأتي مع أية ضمان. هذا برنامج حر, مرحبا بك لتعيد توزيعه تحت شروط معينة. +تفاصيل حول رخصة جنو العمومية: + + + لا يمكن فتح الوصلة. + + + لا يمكن حفظ اللقطة, جد مكان مناسب للحفظ. + + + الايقونات بواسطة مجموعة ايقونات يوسوكي كامياماني (تحت رخصة المشاع الإبداعي الاصدار 3.0) + + + جرين شوت استضيف بواسطة sourceforge.net في + + + رجاء بلغ عن الاخطاء الى + + + اذا اعجبك البرنامج انت مدعو لدعمنا: + + + تم حفظ الصورة في {0}. + + + ثم حفظ الصورة في الذاكرة. + + + احفظ باسم... + + + ملف + + + عدل + + + عنصر + + + ارسم شكل دائري (E) + + + اضف صندوق كتابة (T) + + + احذف + + + حدد الكل + + + انسخ الصورة للذاكرة + + + التقط النافذة + + + كرر العنصر المحدد + + + مساعدة + + + حول البرنامج + + + محرر جرين شوت للصور + + + اعدادات التطبيق + + + اعدادات المفضلة لملف النتائج + + + تجاهل محرر الصور + + + تسجيل الاختصارات + + + عرف ما اذا كانت الاختصارات Prnt, Ctrl + Print, Alt + Prnt محفوظة للاستعمال العام بواسطة جرين شوت في بداية البرنامج, وحتى اغلاقه + + + امر الطباعة ارسل الى '{0}'. + + + اطبع + + + مساعدة + + + JPEG اعدادات + + + JPEG جودة + + + اظهر نافذة جودة JPEG في كل مرة تحفظ فيها صورة JPEG + + + جودة JPEG + + + رجاء اختار جودة صورة JPEG + + + احفظ جودة JPEG الافتراضية ولا تسالني مجددا + + + لون الخط + + + لون التعبئة + + + سماكة الخط + + + منتقي الالوان + + + طبق + + + شفاف + + + HTML لون + + + أحمر + + + أخضر + + + أزرق + + + ألفا + + + اخر لون استعمل + + + اغلق + + + تحذير + + + لا يمكن تسجيل اختصار واحد او اكثر. لذلك, قد لا يكون بالامكان استخدام اختصارات جرين شوت. +هذه المشكلة على الاغلب سببها برنامج اخر يدعي استخدام نفس الاختصارات. +رجاء قم بالغاء البرنامج الذي يقوم باستخدام مفتاح الطباعة. يمكنك ايضا استخدام كل ميزات جرين شوت من الايقونة على شريط المهام. + + + افتح في محرر الصور + + + ارسل للطباعة + + + احفظ مباشرة (باستخدام الاعدادات بالأسفل) + + + انسخ للذاكرة + + + ارسم خط (L) + + + ‫بعد التقاط الشاشة .. + + + ارسم سهم (A) + + + رؤوس السهم + + + نقطة البداية + + + نقطة النهاية + + + كلاهما + + + لاشيء + + + وضع التعتيم + + + وضع التظليل + + + برنامج جرين شوت يعمل حاليا + + + تشغيل جرين شوت مع بدأ التشغيل + + + جرين شوت لم يستطع الحفظ في الذاكرة, العملية {0} حجبت الوصول. + + + حدث خطأ خلال عملية الطباعة + + + خصائص جرين شوت للطباعة + + + ضع المطبوعة في وسط الصفحة + + + كبر المطبوعة لملائمة حجم الصفحة + + + ادر المطبوعة مع اتجاه الصفحة + + + صغر المطبوعة لملائمة حجم الصفحة + + + احفظ الخيارات كافتراضية ولا تسالني مجددا + + + اظهر نافذة خيارات الطباعة في كل مرة تطبع صورة + + + خصائص الطباعة + + + النتائج + + + عام + + + خطأ في الوصول إلى الذاكرة. حاول مجددا. + + + عريض + + + مائل + + + الترتيب + + + الحجم + + + إلى الأعلى + + + مستوى واحد إلى الأعلى + + + مستوى واحد إلى الأسفل + + + إلى الأسفل + + + تفضيلات سريعة + + + خطأ + + + عذرا, حدث خطأ غير متوقع. + الخبر الجيد: انت تستطيع التخلص من هذا عن طريق تعبئة تقرير الاخطاء. + رجاء قم بزيارة الرابط اسفل, انشئ تقرير اخطاء جديد والصق النص من المربع الى الوصف. + + رجاء قم باضافة تلخيص ذو معنى وارفق اية معلومات تعتبرها مفيدة في اكتشاف الخطأ + أيضا, سوف نقدر وبشدة اذا قمت بفحص ما إذا ما قد تم البلاغ عن الخطأ من قبل. شكرا :) + + + إغلاق + + + نسخ مسار الملف الى الذاكرة في كل مرة يتم حفظ صورة + + + انسخ المسار الي الذاكرة + + + سوف يتم استبدال الرموز التالية تلقائيا في النمط المعرف: + +${YYYY} السنة, 4 منازل +${MM} الشهر, منزلتان +${DD} اليوم, منزلتان +${hh} الساعة, منزلتان +${mm} الدقيقة, منزلتان +${ss} الثواني, منزلتان +${NUM} incrementing number, 6 منازل +${title} عنوان النافذة +${user} مستخدم الوندوز +${domain} نطاق وندوز +${hostname} اسم الحاسوب + +بامكانك ايضا جعل جرين شوت ينشئ مجلدات بصورة ديناميكية, ببساطة استخدم رمز (/) لفصل المجلدات واسماء الملفات. +مثال: النمط ${YYYY}-${MM}-${DD}\${hh}-${mm}-${ss} +سيولد مجلدا لليوم الحالي في مكان الحفظ الافتراضي, مثلا 28-09-2011, اسم ملف لقطة الشاشة سيكون على اساس الوقت الحالي, مثلا 14_13_15 (مع امتداد الحفظ) + + + اداة التحديد (ESC) + + + احفظ باسم.. + + + احفظ مباشرة (باستخدام الخيارات المفضلة) + + + افتح المجلد في مستكشف ويندوز + + + اطبع التاريخ / الوقت اسفل الصفحة + + + تظليل (H) + + + التأثير الضبابي + + + تشويش + + + منطقة التظليل + + + تظليل النص + + + مقياس اللون الرمادي + + + تكبير + + + حجم البيكسل + + + تعتيم (O) + + + قطر التأثير الضبابي + + + السطوع + + + معاينة الجودة + + + عامل التضخيم + + + الظل + + + تأكيد + + + الغاء + + + قص (C) + + + فتح صورة من الذاكرة + + + خطأ غير متوقع حدث عند المحاولة للكتابة على الذاكرة. + + + لا يمكن حفظ ملف الاعدادات. رجاء تأكد من صلاحيات الوصول ل '{0}'. + + + الطابعة + + + إلتقط صورة + + + التقط مؤشر الفأرة + + + فتح صورة من ملف + + + الملف "{0}" لا يمكن فتحه. + + + هل تريد حفظ اللقطة? + + + حفظ الصورة? + + + استخدم وضع نافذة الالتقاط التفاعلي + + + التقط النافذة حتى لو كانت محجوبة + + + التقط المحتوى فقط بواسطة التطبيقات المدعومة + + + بريد الكتروني + + + البريد الالكتروني + + + تحميل العنصر من ملف + + + حفظ العنصر في ملف + + + وقت الانتظار بالجزء من الثانية قبل الإلتقاط + + + انقر الزر الايمن هنا أو اضغط مفتاح الطباعة. + + + ادعم جرين شوت + + + \ No newline at end of file diff --git a/Greenshot/Languages/language-cs-CZ.xml b/Greenshot/Languages/language-cs-CZ.xml index 3a771285a..8a6e9abef 100644 --- a/Greenshot/Languages/language-cs-CZ.xml +++ b/Greenshot/Languages/language-cs-CZ.xml @@ -1,5 +1,5 @@  - + - + + + Greenshot - das revolutionäre Screenshot-Tool @@ -96,7 +98,7 @@ Für Greenshot besteht KEINERLEI GARANTIE. Greenshot ist freie Software, die Sie Detaillierte Informationen zur GNU General Public License: - Konnte Link nicht öffnen. + Konnte Link '{0}' nicht öffnen. Screenshot konnte nicht gespeichert werden, bitte wählen Sie einen anderen Speicherort. @@ -260,9 +262,15 @@ Sie können alle Greenshot-Funktionen aber auch über das Kontextmenü des Green In Zwischenablage kopieren + + Ziel auswählen + Linie zeichnen (L) + + Freihandlinie zeichnen (F) + Screenshot Ziel @@ -486,7 +494,7 @@ Zeit, z.B. 11_58_32 (plus Dateinamenerweiterung wie in den Einstellungen definie Abfotografieren - Zusatzmodulen + Zusatzmodule Mousepointer mit abfotografieren @@ -531,13 +539,22 @@ Zeit, z.B. 11_58_32 (plus Dateinamenerweiterung wie in den Einstellungen definie Objekte in Datei speichern - Mache dem Editor so groß wie dem screenshot + Anpassen an Aufnahmebereich + + + Automatisch zuschneiden + + + Rückgängig {0} + + + Wiederherstellen {0} Millisekunden warten vor abfotografieren - Klicken Sie hier mit der rechten Maustaste oder drücken Sie die Druck-Taste. + Klicken Sie hier mit der rechten Maustaste oder drücken Sie die {0} Taste. Greenshot unterstützen @@ -578,5 +595,32 @@ Zeit, z.B. 11_58_32 (plus Dateinamenerweiterung wie in den Einstellungen definie Eine neuere Greenshot Version steht zur Verfügung! Wollen Sie Greenshot {0} herunterladen? + + Exportiert nach: {0} + + + Wie angezeigt + + + Standardfarbe verwenden + + + Eigene Farbe verwenden + + + Transparenz erhalten + + + Automatisch + + + MAPI klient + + + Outlook mit text + + + Outlook mit HTML + \ No newline at end of file diff --git a/Greenshot/Languages/language-el-GR.xml b/Greenshot/Languages/language-el-GR.xml index 14fa1febc..1067d453d 100644 --- a/Greenshot/Languages/language-el-GR.xml +++ b/Greenshot/Languages/language-el-GR.xml @@ -1,5 +1,5 @@  - + + + Greenshot - the revolutionary screenshot utility @@ -62,6 +64,9 @@ Effects + + Show notifications + Play camera sound @@ -96,7 +101,7 @@ Greenshot comes with ABSOLUTELY NO WARRANTY. This is free software, and you are Details about the GNU General Public License: - Could not open link. + Could not open link '{0}'. Could not save screenshot, please find a suitable location. @@ -259,9 +264,15 @@ All Greenshot features still work directly from the tray icon context menu witho Copy to clipboard + + Select destination + Draw line (L) + + Draw freehand (F) + Screenshot Destination @@ -533,11 +544,20 @@ time, e.g. 11_58_32 (plus extension defined in the settings) Match capture size + + Auto crop + + + Undo {0} + + + Redo {0} + Milliseconds to wait before capture - Right-click here or press the Print-key. + Right-click here or press the {0} key. Support Greenshot @@ -578,5 +598,32 @@ time, e.g. 11_58_32 (plus extension defined in the settings) A newer version of Greenshot is available! Do you want to download Greenshot {0}? + + Exported to: {0} + + + As displayed + + + Use default color + + + Use custom color + + + Preserve transparency + + + Automatically + + + MAPI client + + + Outlook with text + + + Outlook with HTML + \ No newline at end of file diff --git a/Greenshot/Languages/language-es-ES.xml b/Greenshot/Languages/language-es-ES.xml index 1f1ae2193..fac14a35b 100644 --- a/Greenshot/Languages/language-es-ES.xml +++ b/Greenshot/Languages/language-es-ES.xml @@ -1,5 +1,5 @@  - + + + Capturer Internet Explorer + + + Raccourcis clavier + + + Capturer l'écran + + + Capturer Internet Explorer + + + Capturer la dernière région + + + Capturer une région + + + Capturer une fenêtre + + + Imprimer en couleurs inversées. + + + Capturer la fenêtre même si elle est obstruée + + + Ne capturer le contenu que dans les applications supportées + + + Veuillez patienter pendant que la page dans Internet Explorer est capturée... + \ No newline at end of file diff --git a/Greenshot/Languages/language-he-IL.xml b/Greenshot/Languages/language-he-IL.xml index c4954c500..9d669dfe2 100644 --- a/Greenshot/Languages/language-he-IL.xml +++ b/Greenshot/Languages/language-he-IL.xml @@ -1,5 +1,5 @@  - + diff --git a/Greenshot/Languages/language-hu-HU.xml b/Greenshot/Languages/language-hu-HU.xml index 959f2569b..b7c9d4a01 100644 --- a/Greenshot/Languages/language-hu-HU.xml +++ b/Greenshot/Languages/language-hu-HU.xml @@ -1,5 +1,5 @@  - + + + Tradução para o português de Portugal por Paulo Carreiro (PCarreiro) + + + Greenshot - O revolucionário Utilitário de Captura de Écran + + + Desenhar Rectángulo (R) + + + Guardar + + + Preferências... + + + Caminho + + + Preferências + + + Lugar onde os écrans capturados serão guardados por defeito (deixar em branco para guardar na Área de Trabalho) + + + Idioma + + + Formato do nome + + + Idioma do interface de utilisador do Greenshot (necessita reiniciar) + + + Formato usado para gerar o nome dos arquivos quando se guardam os écrans capturados + + + Formato da imagem + + + Formato da imagen usado por defeito + + + Capturar região + + + Capturar a última região + + + Sair + + + Efeitos + + + Reproduzir o som de uma câmera + + + Simular o flash de uma câmera + + + Erro + + + Não foi possível guardar o arquivo em {0}. +Por favor verifique o caminho selecionado para o armazenamento. + + + Capturar o écran inteiro + + + Cortar + + + Copiar + + + Colar + + + Sobre o Greenshot + + + Copyright (C) 2007-2010 Thomas Braun, Jens Klingen, Robin Krom +O Greenshot não tem NENHUMA GARANTIA. Este software gratuito pode ser redistribuído sob algumas condições. +Detalhes sobre a licença GNU: + + + O link '{0}' não pode ser aberto. + + + O écran capturado não pôde ser guardado, por favor encontre um local adequado. + + + Ícones de Yusuke Kamiyamane (Biblioteca Fugue, licença "Creative Commons Attribution 3.0") + + + O Greenshot está armazenado no sourceforge.net em + + + Por favor envie erros para + + + Se gostou do Greenshot, por favor contribua: + + + Imagem guardada em {0}. + + + Imagem enviada para a área de transferência. + + + Guardar como... + + + Arquivo + + + Editar + + + Objecto + + + Desenhar Elipse (E) + + + Desenhar Quadro de Texto (T) + + + Apagar + + + Selecionar tudo + + + Copiar imagem para a Área de transferência + + + Capturar écran + + + Duplicar elemento selecionado + + + Ajuda + + + Sobre o Greenshot + + + Editor de Imagens do Greenshot + + + Configurações da Aplicação + + + Configurações Padrão para os Arquivos de Captura + + + Não passar pelo Editor de imagens + + + Configurar teclas de atalho + + + Configurar os atalhos Print, Ctrl + Print, Alt + Print para uso pelo Greenshot quando este iniciar, e até que ele seja finalizado. + + + A impressão foi enviada para '{0}'. + + + Imprimir + + + Ajuda do Greenshot + + + Configurações para JPEG + + + Qualidade do JPEG + + + Perguntar a qualidade do JPEG cada vez que uma imagem for guardada + + + Qualidade Greenshot para JPEG + + + Por favor selecione a qualidade desejada para a imagem JPEG. + + + Guardar esta qualidade JPEG como padrão e não perguntar novamente + + + Cor da linha + + + Cor de preenchimento + + + Espessura da linha + + + Selector de Cores + + + Aplicar + + + Transparência + + + Cor HTML + + + Vermelho + + + Verde + + + Azul + + + Alfa + + + Cores usadas recentemente + + + Fechar + + + Atenção + + + Uma ou mais teclas de atalho não puderam ser configuradas. Por isso pode não ser possível utilizar as teclas de atalho do Greenshot. +Este problema é geralmente causado por outra aplicação solicitando acesso a estas teclas de atalho. +Por favor desactive o outro programa que está utilizando a tecla Print ou utilize as funções do Greenshot via o menu de contexto do ícone no System Tray. + + + Abrir imagem no editor + + + Enviar para impressora + + + Guardar num arquivo + + + Área de transferência + + + Desenhar Linha (L) + + + Destino do écran capturado + + + Desenhar Seta (A) + + + Ponta das setas + + + No início + + + No fim + + + Em ambos + + + Nenhuma + + + Modo de obscurecimento + + + Modo de destaque + + + Uma instância do Greenshot já está sendo executada. + + + Executar o Greenshot ao iniciar o Windows + + + O Greenshot não conseguiu escrever na área de transferência porque o processo {0} bloqueou o acesso. + + + Ocorreu um erro ao se tentar imprimir. + + + Opçoes de impressão do Greenshot + + + Centralizar a impressão na página + + + Aumentar o tamanho da impressão para ocupar toda a página + + + Rotacionar a impressão de acordo com a orientação da página + + + Diminuir o tamanho da impressão para caber na página + + + Salvar as opções como padrão e não perguntar de novo + + + Mostrar as opções de impressão toda vez que uma imagem for impressa + + + Opções de Impressão + + + Captura + + + Geral + + + Erro ao aceder à área de transferência. Por favor tente novamente. + + + Negrito + + + Itálico + + + Organizar + + + Tamanho + + + Trazer para frente + + + Avançar + + + Recuar + + + Enviar para trás + + + Preferências rápidas + + + Erro + + + Desculpe, ocorreu um erro inesperado. + +A boa notícia é: você pode-nos ajudar a corrigir o problema enviando-nos uma descrição do erro. +Por favor visite a URL abaixo, crie um novo relatório de erro e cole o conteúdo da área de texto na descrição do erro. + +Por favor adicione um resumo significativo do erro, além de qualquer informação que considere útil para a reprodução o problema. +Também apreciaremos muito se você puder verificar se não existe já um relatório de erro para este problema. (Você pode usar a opção de busca para encontrar rapidamente.) Obrigado :) + + + Fechar + + + Copiar o caminho completo do arquivo para a Área de transferência + + + Copiar o caminho da pasta actual do arquivo para a Área de transferência + + + Os seguientes marcadores de posição serão substituídos automaticamente pelo formato definido: +%YYYY% ano, 4 dígitos +%MM% mês, 2 dígitos +%DD% dia, 2 dígitos +%hh% hora, 2 dígitos +%mm% minuto, 2 dígitos +%ss% segundo, 2 dígitos +%NUM% número incremental, 6 dígitos +%title% Título da janela +%user% Utilisador do Windows +%domain% Domínio de Windows +%hostname% Nome do Computador + +Você também pode fazer o Greenshot criar directórios dinamicamente, simplesmente usando o símbolo de barra invertida (\) para separar directórios e nome de arquivo. +Exemplo: o formato %YYYY%-%MM%-%DD%\%hh%-%mm%-%ss% +irá gerar um directório para o dia actual dentro do caminho de armazenamento padrão, exemplo: 2008-06-29, os nomes dos écrans capturados serão baseados na +hora atual, ejemplo: 11_58_32 (mais a extensão definida nas configurações de preferência) + + + Ferramenta de Selecção (ESC) + + + Guardar como... (mostrar caixa de diálogo) + + + Guardar directamente (Usando a configuração padrão para arquivos de captura) + + + Abrir o directório no Windows Explorer + + + Imprimir data / hora na parte inferior da página + + + Destacar (H) + + + Desfocar + + + Pixelização + + + Destacar área + + + Destacar texto + + + Escalas de cinza + + + Ampliar + + + Tamanho de Pixel + + + Obscurecer (O) + + + Raio de desfoque + + + Brilho + + + Qualidade do preview + + + Factor de ampliação + + + Sombra + + + Confirmar + + + Cancelar + + + Cortar (C) + + + Abrir imagem da área de transferência + + + Um erro inesperado ocorreu ao tentar escrever na área de transferência. + + + Não foi possível guardar o arquivo de configuração do Greenshot. Por favor verifique as permissões de acesso a '{0}'. + + + Impressora + + + Captura + + + Capturar também o cursor do rato + + + Abrir imagem do arquivo + + + O arquivo "{0}" não põde ser aberto. + + + Deseja guardar a imagem capturada? + + + Guardar imagem? + + + Usar modo interactivo + + + Capturar janela mesmo que ela esteja obstruída + + + Capturar o conteúdo somente de aplicações suportadas + + + Enviar por e-mail + + + Enviar por e-mail + + + Carregar objectos de arquivo... + + + Salvar objectos em arquivo... + + + Milisegundos à esperar antes de iniciar a captura + + + Botão direito aqui ou pressionar a tecla Print. + + + Suporte do Greenshot + + + + diff --git a/Greenshot/Languages/language-ru-RU.xml b/Greenshot/Languages/language-ru-RU.xml index 03453a11c..3c06e4d2f 100644 --- a/Greenshot/Languages/language-ru-RU.xml +++ b/Greenshot/Languages/language-ru-RU.xml @@ -1,76 +1,79 @@  - + - Русский перевод: Алексей Сехан, sehan@mail.ru, 2010-08-16 + Русский перевод Андрея Кравцова, http://sapfir.mylivepage.ru - Greenshot — революционная утилита для получения экранных снимков + Greenshot — передовая утилита для получения скриншотов - Прямоугольник (R) + Нарисовать прямоугольник (R) Сохранить - Параметры... + Настройки... - Папка для снимков + Место хранения Настройки - Папка по умолчанию для сохранения снимков (если пусто, то на Рабочий стол) + Место, где скриншоты сохраняются по умолчанию (оставить пустым для сохранения на рабочем столе) - Язык (Language) + Язык - Шаблон имени файла + Имя файла шаблона - Язык интерфейса (потребуется перезапуск программы) + Язык интерфейса пользователя - Шаблон, используемый для генерации имен файлов при сохранении экранных снимков + Шаблон, используемый для генерации имен файлов при сохранении скриншотов Формат изображения - Формат по умолчанию + Формат изображения по умолчанию - Снимок области + Захват области - Снимок той же области + Захват последней области Выход + + Открыть последнее местоположение + - Эффекты при снимке + Эффекты - Щелкнуть, как фотокамерой + Играть звук камеры - Блеснуть, как фотовспышкой + Применить вспышку Ошибка - Невозможно сохранить файл в {0}. -Проверьте, доступна ли эта папка для записи. + Не удается сохранить файл в {0}. +Проверьте, доступно ли это место для сохранения. Снимок всего экрана @@ -88,17 +91,18 @@ О программе Greenshot - Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom -Greenshot предоставляется БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ. Greenshot — свободное программное обеспечение с лицензией GPL (GNU General Public License) и вы можете распростанять его, соблюдая лицензию: + Авторские права (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom +Greenshot поставляется БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.Это бесплатная программа и Вы можете распространять ее с определёнными условиями. +Подробно о GNU General Public License: - Не могу открыть ссылку. + Невозможно открыть ссылку. - Не удалось сохранить снимок. Пожалуйста, найдите подходящее место. + Невозможно сохранить скриншот, пожалуйста, найдите подходящее место. - Набор значков Fugue, автор Yusuke Kamiyamane, лицензия Creative Commons Attribution 3.0 + Набор иконок Yusuke Kamiyamane's Fugue (Creative Commons Attribution 3.0 license) Greenshot размещается на sourceforge.net @@ -110,10 +114,10 @@ Greenshot предоставляется БЕЗ КАКИХ-ЛИБО ГАРАНТ Если вам понравился Greenshot, вы можете поддержать нас: - Изображение сохранено в {0}. + Изображение сохраняется в {0}. - Изображение помещено в буфер обмена. + Изображение помещается в буфер обмена. Сохранить как... @@ -122,89 +126,88 @@ Greenshot предоставляется БЕЗ КАКИХ-ЛИБО ГАРАНТ Файл - Правка + Редактировать Объект - Эллипс (E) + Нарисовать эллипс (E) - Текст (T) + Добавить текстовое поле (T) Удалить - Выделить все + Выбрать все - Поместить в буфер обмена + Копировать изображение в буфер обмена - Снимок окна + Захват окна - Дублировать + Дубликат выбранного элемента Справка - О программе + О программе Greenshot - Greenshot: Редактор экранных снимков + Редактор изображений Greenshot - Настройки программы + Настройки приложения - Параметры сохранения в файл + Предпочтительные настройки выходного файла - Перехватывать горячие клавиши + Назначить горячие клавиши - Клавиша Print (PrintScreen), сочетания Ctrl-Print, Alt-Print -будут перехватываться программой Greenshot, пока она запущена. + Определяет, работают ли ярлыки Prnt, Ctrl + Print, Alt + Prnt для глобального использования Greenshot при запуске программы, пока программа работает. - Задание печати отправлено на {0}. + Задание на печать отправлено в {0}. - Напечатать + Печать Справка Greenshot - Параметры JPEG + Настройки JPEG - Качество + Качество JPEG - Показывать диалог выбора качества при каждом сохранении в JPEG + Показывать диалог JPEG качества при каждом сохранении - Качество Greenshot + Качество JPEG Greenshot - Выберите качество JPEG + Выберите качество изображения JPEG - Сохранить с выбранным качеством и больше не спрашивать + Сохранить качество JPEG как по умолчанию и больше не спрашивать - Цвет контура + Цвет линии Цвет заливки - Толщина контура + Толщина линии Выбор цвета @@ -216,7 +219,7 @@ Greenshot предоставляется БЕЗ КАКИХ-ЛИБО ГАРАНТ Прозрачный - Цвет в HTML + Цвет HTML Красный @@ -228,10 +231,10 @@ Greenshot предоставляется БЕЗ КАКИХ-ЛИБО ГАРАНТ Синий - Плотн. + Альфа - Недавно использованные цвета + Недавно используемые цвета Закрыть @@ -240,120 +243,123 @@ Greenshot предоставляется БЕЗ КАКИХ-ЛИБО ГАРАНТ Предупреждение - Не все горячие клавиши удалось зарегистрировать. Вероятно, они уже зарегистрированы другой программой. -Чтобы клавишу Print (PrintScreen) и её сочетания обрабатывала программа Greenshot, следует закрыть (не свернуть) другие программы, -перехватывающие те же горячие клавиши. Или же можно использовать команды контекстного меню Greenshot в системной области. + Горячую клавишу (и) "{0}" не возможно зарегистрировать.Эта проблема, вероятно, вызвана еще одним инструментом,использующим ту же горячую клавишу (и)! Вы можете либо изменить настройки горячих клавиш или деактивировать/изменить программное обеспечение с использованием горячих клавиш. + +Все функции Greenshot продолжают работать прямо из иконки контекстного меню в трее, без горячих клавиш. - Открыть в редакторе + Открыть в графическом редакторе - Напечатать + Отправить на печать - Сохранить напрямую в файл + Сохранить напрямую (настройки ниже) - Поместить в буфер обмена + Копировать в буфер обмена - Отрезок (L) + Нарисовать линию (L) + + + Нарисовать от руки (F) - Сделанный снимок... + Назначение скриншота - Стрелка (A) + Нарисовать стрелку(A) - Стрелка + Наконечник стрелки - В начале + Начальная точка - В конце + Конечная точка - С обеих сторон + Обе точки - Нет + Ничего Режим затемнения - Режим прояснения + Режим выделения Greenshot уже запущен. - Запускать Greenshot при входе в Windows + Автозагрузка - Не удалось записать данные в буфер обмена, который блокирован процессом {0}. + Не удалось записать данные в буфер обмена, доступ заблокирован процессом {0}. - Ошибка при печати. + Произошла ошибка при попытке напечатать. - Параметры печати + Опции печати Greenshot - Центрировать на странице + Распечатать по центру страницы - Увеличить на всю страницу + Растянуть на всю страницу Повернуть согласно ориентации страницы - Уменьшить, чтобы вместить в страницу + Подогнать, чтобы вместить на страницу - Запомнить эти параметры и больше не спрашивать + Сохранить настройки по умолчанию и больше не спрашивать - Уточнять параметры печати перед каждой распечаткой + Показывать диалог параметров печати при каждой печати Параметры печати - Снимки + Вывод - Общие + Общее - Ошибка при доступе к буферу обмена. Попробуйте повторить. + Ошибка при доступе в буфер обмена.Пожалуйста, попробуйте еще раз. - Полужирный + Жирный Курсив - Порядок + Размещение Размер - На передний план + Вверх - На один уровень вперед + На один уровень вверх - На один уровень назад + На один уровень вниз - На задний план + Вниз Быстрые настройки @@ -362,91 +368,98 @@ Greenshot предоставляется БЕЗ КАКИХ-ЛИБО ГАРАНТ Ошибка - Увы, произошла непредвиденная ошибка. + Извините,произошла непредвиденная ошибка. -Хорошая новость: вы можете помочь исправить программу, отправив нам отчет об ошибке. -По указанному ниже адресу создайте новый отчет об ошибке и скопируйте содержимое текстовой области в описание. Добавьте любую информацию, которая могла бы помочь нам воспроизвести обстоятельства проявления ошибки. Кроме того, мы были бы весьма признательны, если бы вы проверили, не сообщал ли уже кто-то о такой же ошибке (вы можете использовать поиск по сайту). +Хорошая новость:Вы можете помочь нам избавиться от этой ошибки, путем подачи отчета о ней. +Пожалуйста, посетите ссылку ниже, создайте новый отчет об ошибке и вставьте содержимое из текстового поля. -Спасибо за содействие :) +Пожалуйста, добавьте значимое резюме и приложите любую информацию, которую вы считаете полезной для воспроизведения проблемы. +Кроме того, мы были бы весьма признательны, если вы попробуете найти решение этой ошибки, вользовавшись поисковиком. Спасибо:) Закрыть - При сохранении копировать полное имя файла в буфер обмена + Копировать путь к файлу в буфер обмена каждый раз при сохранении - Копировать полное имя файла + Копировать путь в буфер обмена - Подстановочные символы: + Следующие заполнители будут заменены в шаблоне автоматически: +${YYYY} Год, 4 цифры +${MM} Месяц, 2 цифры +${DD} День, 2 цифры +${hh} Часы, 2 цифры +${mm} Минуты, 2 цифры +${ss} Секунды, 2 цифры +${NUM} Увеличивающееся число, 6 цифр +${title} Заголовок окна +${user} Пользователь Windows +${domain} Домен Windows +${hostname} Имя ПК -${YYYY} год, 4 цифры -${MM} месяц, 2 цифры -${DD} день, 2 цифры -${hh} часы, 2 цифры -${mm} минуты, 2 цифры -${ss} секунды, 2 цифры -${NUM} возрастающий номер, 6 цифр -${title} заголовок окна - -Greenshot может именовать по шаблону не только файлы, но и папки, если в шаблоне используется обратная косая черта \ - -Например, шаблон ${YYYY}-${MM}-${DD}\${hh}-${mm}-${ss} указывает, что в папке по умолчанию будет создана папка для текущего дня, например, 2008-06-29, а имя помещённого в неё файла будет содержать текущее время, например 16-40-23 (плюс расширение имени, заданное в настройках) +Вы также можете создавать динамичные каталоги Greenshot, просто используйте символ обратную косую черту (\) для отдельных папок и названий файлов. +Например шаблона: ${YYYY}-${MM}-${DD}\${hh}-${mm}-${ss} +будет создавать папки на текущий день в вашем хранилище по умолчанию, например, 2008-06-29, содержащее имя скриншота файла будет основывается на текущем +времени, например, 11_58_32 (плюс расширения, определенные в настройках) - Выбор объектов (ESC) + Выбор инструмента (ESC) - Сохранить с выбором папки и имени файла + Сохранить как (диалог отображения) - Сохранить в файл, указанный в настройках + Сохранить непосредственно (персонал.настройки) - Открыть папку в Проводнике + Открыть папку в проводнике Печатать дату и время внизу страницы + + Печать с инвертированными цветами + - Высветление + Выделение (H) - Размытие (B) + Пятно - Квадратики (P) + Пикселизация - Ясное среди мутного (I) + Подсветить область - Цветовое выделение (H) + Подсветить текст - Цветное среди серого + Оттенок серого Увеличение - Размер квадратиков + Размер пикселя - Затемнение + Затемнение (O) - Радиус размытия + Радиус пятна Яркость - Качество предпросмотра + Качество предосмотра - Увеличение (M) + Фактор увеличения Тень @@ -464,16 +477,19 @@ Greenshot может именовать по шаблону не только ф Открыть изображение из буфера обмена - Неожиданная ошибка произошла при записи в буфер обмена. + Произошла непредвиденная ошибка при записи в буфер обмена. - Не удалось сохранить настройки программы. Проверьте, разрешена ли запись в {0}. + Невозможно сохранить конфигурацию файла Greenshot.Пожалуйста, проверьте права доступа для {0}. Печать - Снимок + Захват + + + Модули Захватить указатель мыши @@ -481,23 +497,35 @@ Greenshot может именовать по шаблону не только ф Открыть изображение из файла + + Режим захвата окна + + + Захват окна + + + Захват Internet Explorer + + + Редактор + - Не удалось открыть файл "{0}". + Файл "{0}" не может быть открыт. - Сохранить экранный снимок? + Сохранить скриншот? Сохранить изображение? - Интерактивный выбор окна для снимка + Использование интерактивного режима захвата окна - Отправить электронной почтой + E-Mail - Отправить электронной почтой + E-Mail Загрузить объекты из файла @@ -505,14 +533,86 @@ Greenshot может именовать по шаблону не только ф Сохранить объекты в файл + + Соответствовать размеру захвата + + + Автообрезание + + + Отменить {0} + + + Повторить {0} + - Задержка перед снимком (мс) + Ожидание в миллисек. перед захватом - Щелкните правой кнопкой мыши или нажмите клавишу PrintScreen. + Щелкните правой кнопкой мыши здесь или нажмите кнопку "Печать" - Поддержать проект + Поддержать Greenshot + + + Захват Internet Explorer + + + Горячие клавиши + + + Захват экрана + + + Захват Internet Explorer + + + Последняя область захвата + + + Захват области + + + Захват окна + + + Пожалуйста, подождите, пока страница в Internet Explorer захватывается... + + + Сеть и обновления + + + Интервал проверки обновлений в днях (0=не проверять) + + + Использовать прокси систему по умолчанию + + + Доступна новая версия Greenshot! Вы хотите скачать Greenshot {0}? + + + Как отображается + + + Использовать цвет по умолчанию + + + Использовать пользовательский цвет + + + Сохранить прозрачность + + + Автоматически + + + Клиент MAPI + + + Outlook с текстом + + + Outlook с HTML \ No newline at end of file diff --git a/Greenshot/Languages/language-sv-SE.xml b/Greenshot/Languages/language-sv-SE.xml index 78cb0c647..e2c42fdc0 100644 --- a/Greenshot/Languages/language-sv-SE.xml +++ b/Greenshot/Languages/language-sv-SE.xml @@ -1,5 +1,5 @@  - + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Greenshot/releases/additional_files/readme.txt b/Greenshot/releases/additional_files/readme.txt index c158c5dbc..b4a7d0280 100644 --- a/Greenshot/releases/additional_files/readme.txt +++ b/Greenshot/releases/additional_files/readme.txt @@ -1,47 +1,113 @@ Greenshot: A screenshot tool optimized for productivity. Save a screenshot or a part of the screen to a file within a second. Apply text and shapes to the screenshot. Offers capture of window, region or full screenshot. Supports several image formats. + CHANGE LOG: -0.8.1 +0.9.0-Unstable (Build 1535) + +We changed the version to 0.9.0 as the amount of features in 0.8.1 was more than planned. +Due to the many changes we need to go through a Release Candidate iteration again... Bugs resolved: -* Image editor problems when exiting Greenshot. -* Systray icon wasn't removed when stopping Greenshot -* Installer fixes for silent installation and the selected installer language will be passed to Greenshot -* Hotkeys on Windows 7 x64 weren't working, should be okay now. -* Changed variable naming from %VAR% to ${VAR}, a.o to prevent early resolving on the command-line -* Fixed problems with calculating the window size for Windows Vista & Windows 7. -* Fixed annoying bug in editor which made the screen jump if the editor had scrollbars, got even more annoying with the new IE capture feature. -* Fixed mousewheel scrolling in editor -* Capture & editor performance improved -* Fixed capture region selection screen losing focus -* Many other minor stability fixes -* At first start all available languages can be selected +* Fixed a problem with the window preview, if the window had a small height, when using the context menu (Windows Vista and later) +* Fixed a problem with temp-files being removed before they were used, now using a delay of ~10 hours +* Removed clipboard monitoring, which hopefully solves some problems with Virtual Machines Features added: -* Changed the configuration from a proprietary binary format to a readable & modifiable "greenshot.ini". -* Added the Dutch language as a third default language for all Greenshot parts (application, plugins and installer) -* Added all currently available languages to the installer. -* Added configurable hotkeys -* Added Aero (DWM) window capture on Windows Vista and later! Either the window is captured with transparency or it is possible to replace the transparent window border with a background color, making the capture look cleaner. -* Added Internet Explorer capture. Select your IE - Tab from the Greenshot context menu or use the default hotkey "Ctrl + Shift + PrintScreen" to capture the active IE page. -* Added OCR Plugin, this will only work when Microsoft Office 2003 or 2007 is installed. Unfortunately there is no way to check what languages Office supports, this needs to be set manually! To set the language, go into the Greenshot configuration screen, a new "plugin" tab is available. Click on the tab, on the OCR plugin and on the configure button. This should allow you to change the language which is used to OCR your selection! -* Added environment variable support for the filename and path. Now one can use e.g. "${TMP}" -* Added "experimental" Windows "Enhanced" MetaFile (=Vector graphics) support. The bitmap can be resized "without" quality loss. To use this, e.g. drag/drop a "WMF" file from the Microsoft Office "Clipart" directory on the open Greenshot editor. -* Added Imgur (see: http://Imgur.com) plugin -* Added plugin white/black listing, mainly needed for administrators specifying which plugins will be loaded and which not. -* Added better Email export: Outlook support, creating HTML email with "in-body" image using the default signature for new Emails. -* Added GDI capturing windows with transparency, only works if Aero (DWM) is disabled! -* Added update check, if an update is detected a popup is shown asking if the user wants to download this -* Added HTML as clipboard format +* Greenshot can now run in 64 bit mode, if the OS supports it. +* Added a "destinations" concept, making it possible to select all destinations from the main settings or using them inside the editor. +* Added a "processor" concept, making it possible to modify the capture before it's send to a destination. Currently there is only an internal implementation which replaces the TitleFix plugin. +* Added Office destinations (Word, Excel, Powerpoint & Outlook) with dynamic resolving of open "instances". +0.8.1-Unstable (Build 1483) + +Bugs resolved: +* Fixed a bug that windows which dissapear when they lose focus couldn't be selected in the "interactive window mode" (Press printscreen and than space). These are e.g. (context) menus and the Windows 7 Clock. +* Fixed graphics glitches when resizing the linethickness of an object from very thick into thin. (e.g. 50 -> 1) +* Fixed graphics glitches when duplicating a line or arrow, there suddenly are more "grippers" (those points which can be used to resize or change direction)- +* Fixed a minor issue when trying to select an arrow, the hit detection was slightly off. +* Fixed a problem that an invisible Greenshot window was showing when using Alt-Tab directly after the start of Greenshot. Although the window dissapears right after selecting, this was confusing. +* Fixed a problem with the main Greenshot context menu when entering and leaving the "capture windows" very quickly. (The context menu moved to the top-left corner of you screen) +* Fixed our balloon-tip which shows where Greenshot is after someone starts it the very first time. +* Fixed that our drop-down boxes in the settings weren't translated +* Fixed that it was possible to open multiple instances of the settings window, this would cause exceptions when someone changed something in it. +* Not a real bug or feature: but we are in the process of updating our english and german help to be more up to date. Dutch should follow soon... + +Features added: +* The editor now has a freehand tool, this makes it possible to draw some things freehand. Every "stroke" (mouse-down to mouse-up) is one "object" which can be manipulated: move, delete, change Z-order and change the properties like color and thickness. +* The editor now has undo/redo +* Now one can use the shift key to fix the mouse coordinates while capturing or drawing. If you press and hold shift only the first direction in which you move can be change, the other stays fixed. + +0.8.1-RC7 (Build 1427) + +Bugs resolved: +* Fixed a nasty bug that some email clients (e.g. iPad, Thunderbird) didn't display inline images in Greenshot generated emails. Unfortunately this only works with Office 2007 and later. +* Fixed Bug #3433566: Exception when clicking on the update message "balloon", this only prevents a stacktrace and shows "can't open link ....". +* Fixed Bug #3435368: Transparency issues +* Trying to fix Bug #3428802, problems with missing/corrupted "accessibility.dll". Which is a .NET problem on someones PC. +* Changed the installer to optimize the Greenshot installation, this should cause Greenshot to start quicker. +* Added a shadow option to bitmaps inside the editor. e.g Bitmaps coming from drag & drop or insert window +* Fixed some small stabillity issues that were reported with the RC6 + +0.8.1-RC6 (Build 1392) + +Bugs resolved: +* Fixed bug #3431881: Image opened via Greenshot is locked until Greenshot was closed. +* Fixed bug #3431223: Problems storing & retrieving the editor settings +* Fixed bug #3432313: Exception when clipboard is busy +* Fixed bug #3431100: At first run Greenshot doesn't use the selected language and gives an exception when going into the settings. +* Fixed a bug with the "TitleFix" Plugin, due to an error in the configuration reading this wasn't active. +* Fixed bug #3429716: When trying to upload to an older version of JIRA the error "No such operation 'addBase64EncodedAttachmentsToIssue'" appears. + As a fallback the old, but unfortunately not 100% working, method 'addAttachmentsToIssue' will be used. + For details see: https://jira.atlassian.com/browse/JRA-11693 + +0.8.1-RC5 (Build 1372) + +Bugs resolved: +* Fixed bug #3430555: Greenshot got wrong state when using "Capture Last region" with no region selected +* Fixed bug #3430560: Capturing the active window didn't set the region +* Fixed installer problems with the .NET 2.0 Language Pack, we removed this requirement as Greenshot doesn't need this. +* Fixed some translations + +0.8.1-RC4 (Build 1366) + +Bugs resolved: +* Fixed a problem with cleaning up tmp files (Bug #3429670) +* Made the zip work directly out from the directory it's extracted in. +* Fixed instability when loading older/incompatibel plugins. +* Fixed a startup order problem which made Greenshot unusable. +* Fixed problems with the Outlook exporter which had difficulties exporting into an open Email. + Usually a new is created, this option can only be enabled via the greenshot.ini! You can find it under "OutputOutlookMethod", needs to be set to "TryOpenElseNew" + +Features added: +* Added "Auto Crop", an option in the edit menu of the editor. + This will go into crop mode and select the biggest solid (!!) rectangle around your capture, so you can remove it. + Usefull if you want to capture something on a plain background and don't want to put a lot of effort in crop to the smallest bitmap. + Hard to explain, just try it... +* Added ClipboardFormats setting to the greenshot.ini, you can find it as "ClipboardFormats" + If people have problems with the HTML format which was added, it can be removed here: ClipboardFormats=PNG,DIB + +0.8.1-RC3 (Build 1339) + +Bugs resolved: +* Fixed multiple stability issues when capturing +* Fixed problems with cleanup of the "Please wait" popup. +* Installer fixes for silent installation and the selected installer language will be passed to Greenshot +* At first start all available languages can be selected +* Hotkeys on Windows 7 x64 weren't working, should be okay now. +* Changed variable naming from %VAR% to ${VAR}, a.o to prevent early resolving on the command-line +* Fixed annoying bug in editor which made the screen jump if the editor had scrollbars, got even more annoying with the new IE capture feature. +* Fixed mousewheel scrolling in editor +* Fixed capture region selection screen losing focus +* Many other minor stability fixes + Known bugs: * When having multiple monitors the systray context menu will have options which apear on a different screen. (Issue in Microsoft Windows) -* The "I" Mouse-Cursor will not be rendered correctly on the final image. (Issue in Microsoft Windows) -* There might still be some minor rendering problems due to performance improvements, these will not be visible on the resulting image. We will fix them as soon as we find them. +* The "I" Mouse-Cursor will not be rendered correctly on the saved image. (Issue in Microsoft Windows) +* There might still be some minor rendering problems due to our performance improvements, these will not be visible on the final saved/exported image. We will fix them as soon as we find them. -0.8.0 +0.8.0 (Build 0627) Bugs resolved: * save-as dialog honors default storage location again diff --git a/Greenshot/releases/innosetup/setup.iss b/Greenshot/releases/innosetup/setup.iss index 8fa242e03..516de16d6 100644 --- a/Greenshot/releases/innosetup/setup.iss +++ b/Greenshot/releases/innosetup/setup.iss @@ -1,5 +1,5 @@ #define ExeName "Greenshot" -#define Version "0.8.1.$WCREV$" +#define Version "0.9.0.$WCREV$" ; Include the scripts to install .NET Framework 2.0 ; See http://www.codeproject.com/KB/install/dotnetfx_innosetup_instal.aspx @@ -9,40 +9,37 @@ #include "scripts\products\msi20.iss" #include "scripts\products\msi31.iss" #include "scripts\products\dotnetfx20.iss" -#include "scripts\products\dotnetfx20lp.iss" #include "scripts\products\dotnetfx20sp1.iss" -#include "scripts\products\dotnetfx20sp1lp.iss" #include "scripts\products\dotnetfx20sp2.iss" -#include "scripts\products\dotnetfx20sp2lp.iss" [Files] Source: ..\..\bin\Release\*; DestDir: {app}; Flags: overwritereadonly ignoreversion replacesameversion +;Source: ..\greenshot-defaults.ini; DestDir: {app}; Flags: overwritereadonly ignoreversion replacesameversion Source: ..\additional_files\*; DestDir: {app}; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion ;Language files Source: ..\..\bin\Release\Languages\*nl-NL*; DestDir: {app}\Languages; Flags: overwritereadonly ignoreversion replacesameversion; Source: ..\..\bin\Release\Languages\*en-US*; DestDir: {app}\Languages; Flags: overwritereadonly ignoreversion replacesameversion; Source: ..\..\bin\Release\Languages\*de-DE*; DestDir: {app}\Languages; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\bin\Release\Languages\*cs-CZ*; DestDir: {app}\Languages; Components: languages\CZ; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\bin\Release\Languages\*el-GR*; DestDir: {app}\Languages; Components: languages\GR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\bin\Release\Languages\*es-ES*; DestDir: {app}\Languages; Components: languages\ES; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\bin\Release\Languages\*fi-FI*; DestDir: {app}\Languages; Components: languages\FI; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\bin\Release\Languages\*fr-FR*; DestDir: {app}\Languages; Components: languages\FR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\bin\Release\Languages\*he-IL*; DestDir: {app}\Languages; Components: languages\IL; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\bin\Release\Languages\*hu-HU*; DestDir: {app}\Languages; Components: languages\HU; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\bin\Release\Languages\*it-IT*; DestDir: {app}\Languages; Components: languages\IT; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\bin\Release\Languages\*ja-JP*; DestDir: {app}\Languages; Components: languages\JP; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\bin\Release\Languages\*lt-LT*; DestDir: {app}\Languages; Components: languages\LT; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\bin\Release\Languages\*pl-PL*; DestDir: {app}\Languages; Components: languages\PL; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\bin\Release\Languages\*pt-BR*; DestDir: {app}\Languages; Components: languages\BR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\bin\Release\Languages\*ru-RU*; DestDir: {app}\Languages; Components: languages\RU; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\bin\Release\Languages\*sv-SE*; DestDir: {app}\Languages; Components: languages\SE; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\bin\Release\Languages\*tr-TR*; DestDir: {app}\Languages; Components: languages\TR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\bin\Release\Languages\*zh-CN*; DestDir: {app}\Languages; Components: languages\CN; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\bin\Release\Languages\*zh-TW*; DestDir: {app}\Languages; Components: languages\TW; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\*ar-SY*; DestDir: {app}\Languages; Components: languages\arSY; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\*cs-CZ*; DestDir: {app}\Languages; Components: languages\csCZ; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\*el-GR*; DestDir: {app}\Languages; Components: languages\elGR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\*es-ES*; DestDir: {app}\Languages; Components: languages\esES; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\*fi-FI*; DestDir: {app}\Languages; Components: languages\fiFI; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\*fr-FR*; DestDir: {app}\Languages; Components: languages\frFR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\*he-IL*; DestDir: {app}\Languages; Components: languages\heIL; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\*hu-HU*; DestDir: {app}\Languages; Components: languages\huHU; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\*it-IT*; DestDir: {app}\Languages; Components: languages\itIT; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\*ja-JP*; DestDir: {app}\Languages; Components: languages\jaJP; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\*lt-LT*; DestDir: {app}\Languages; Components: languages\ltLT; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\*pl-PL*; DestDir: {app}\Languages; Components: languages\plPL; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\*pt-BR*; DestDir: {app}\Languages; Components: languages\ptBR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\*pt-PT*; DestDir: {app}\Languages; Components: languages\ptPT; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\*ru-RU*; DestDir: {app}\Languages; Components: languages\ruRU; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\*sv-SE*; DestDir: {app}\Languages; Components: languages\svSE; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\*tr-TR*; DestDir: {app}\Languages; Components: languages\trTR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\*zh-CN*; DestDir: {app}\Languages; Components: languages\zhCN; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\*zh-TW*; DestDir: {app}\Languages; Components: languages\zhTW; Flags: overwritereadonly ignoreversion replacesameversion; -;Flickr Plugin -;Source: ..\..\bin\Release\Plugins\GreenshotFlickrPlugin\*; DestDir: {app}\Plugins\GreenshotFlickrPlugin; Components: plugins\flickr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -;Source: ..\..\bin\Release\Languages\Plugins\GreenshotFlickrPlugin\*; DestDir: {app}\Languages\Plugins\GreenshotFlickrPlugin; Components: plugins\flickr; Flags: overwritereadonly ignoreversion replacesameversion; ;OCR Plugin Source: ..\..\bin\Release\Plugins\Greenshot-OCR-Plugin\*; DestDir: {app}\Plugins\Greenshot-OCR-Plugin; Components: plugins\ocr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: ..\..\bin\Release\Languages\Plugins\Greenshot-OCR-Plugin\*; DestDir: {app}\Languages\Plugins\Greenshot-OCR-Plugin; Components: plugins\ocr; Flags: overwritereadonly ignoreversion replacesameversion; @@ -52,11 +49,25 @@ Source: ..\..\bin\Release\Languages\Plugins\GreenshotJiraPlugin\*; DestDir: {app ;Imgur Plugin Source: ..\..\bin\Release\Plugins\GreenshotImgurPlugin\*; DestDir: {app}\Plugins\GreenshotImgurPlugin; Components: plugins\imgur; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: ..\..\bin\Release\Languages\Plugins\GreenshotImgurPlugin\*; DestDir: {app}\Languages\Plugins\GreenshotImgurPlugin; Components: plugins\imgur; Flags: overwritereadonly ignoreversion replacesameversion; +;Box Plugin +;Source: ..\..\bin\Release\Plugins\GreenshotBoxPlugin\*; DestDir: {app}\Plugins\GreenshotBoxPlugin; Components: plugins\box; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +;Source: ..\..\bin\Release\Languages\Plugins\GreenshotBoxPlugin\*; DestDir: {app}\Languages\Plugins\GreenshotBoxPlugin; Components: plugins\box; Flags: overwritereadonly ignoreversion replacesameversion; +;DropBox Plugin +;Source: ..\..\bin\Release\Plugins\GreenshotDropBoxPlugin\*; DestDir: {app}\Plugins\GreenshotDropBoxPlugin; Components: plugins\dropbox; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +;Source: ..\..\bin\Release\Languages\Plugins\GreenshotDropBoxPlugin\*; DestDir: {app}\Languages\Plugins\GreenshotDropBoxPlugin; Components: plugins\dropbox; Flags: overwritereadonly ignoreversion replacesameversion; +;Flickr Plugin +;Source: ..\..\bin\Release\Plugins\GreenshotFlickrPlugin\*; DestDir: {app}\Plugins\GreenshotFlickrPlugin; Components: plugins\flickr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +;Source: ..\..\bin\Release\Languages\Plugins\GreenshotFlickrPlugin\*; DestDir: {app}\Languages\Plugins\GreenshotFlickrPlugin; Components: plugins\flickr; Flags: overwritereadonly ignoreversion replacesameversion; +;Picasa Plugin +;Source: ..\..\bin\Release\Plugins\GreenshotPicasaPlugin\*; DestDir: {app}\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +;Source: ..\..\bin\Release\Languages\Plugins\GreenshotPicasaPlugin\*; DestDir: {app}\Languages\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly ignoreversion replacesameversion; ;Confluence Plugin -;Source: ..\..\bin\Release\Plugins\GreenshotConfluencePlugin\*; DestDir: {app}\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -;Source: ..\..\bin\Release\Languages\Plugins\GreenshotConfluencePlugin\*; DestDir: {app}\Languages\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly ignoreversion replacesameversion; -;Title-Fix Plugin -Source: ..\..\bin\Release\Plugins\Greenshot-TitleFix-Plugin\*; DestDir: {app}\Plugins\Greenshot-TitleFix-Plugin; Components: plugins\titlefix; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: ..\..\bin\Release\Plugins\GreenshotConfluencePlugin\*; DestDir: {app}\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\Plugins\GreenshotConfluencePlugin\*; DestDir: {app}\Languages\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly ignoreversion replacesameversion; +;ExternalCommand Plugin +Source: ..\..\bin\Release\Plugins\GreenshotExternalCommandPlugin\*; DestDir: {app}\Plugins\GreenshotExternalCommandPlugin; Components: plugins\externalcommand; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +;Network Import Plugin +;Source: ..\..\bin\Release\Plugins\GreenshotNetworkImportPlugin\*; DestDir: {app}\Plugins\GreenshotNetworkImportPlugin; Components: plugins\networkimport; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; [Setup] ; changes associations is used when the installer installs new extensions, it clears the explorer icon cache ;ChangesAssociations=yes @@ -69,6 +80,7 @@ AppSupportURL=http://getgreenshot.org AppUpdatesURL=http://getgreenshot.org AppVerName={#ExeName} {#Version} AppVersion={#Version} +ArchitecturesInstallIn64BitMode=x64 DefaultDirName={pf}\{#ExeName} DefaultGroupName={#ExeName} InfoBeforeFile=..\additional_files\readme.txt @@ -122,12 +134,15 @@ nl.startup=Start {#ExeName} wanneer Windows opstart en.startgreenshot=Start {#ExeName} de.startgreenshot={#ExeName} starten nl.startgreenshot=Start {#ExeName} -en.titlefix=Title cleanup for Internet explorer and Firefox -de.titlefix=Titel aufräumen bei Internet explorer und Firefox -nl.titlefix=Titel opruimen bij Internet explorer en Firefox -en.jira=Editor plug-in for Jira -de.jira=Editor plug-in für Jira -nl.jira=Editor plug-in voor Jira +en.jira=Jira plug-in +de.jira=Jira plug-in +nl.jira=Jira plug-in +en.confluence=Confluence plug-in +de.confluence=Confluence plug-in +nl.confluence=Confluence plug-in +en.externalcommand=Open with external command plug-in +de.externalcommand=Öffne mit ein externes Kommando plug-in +nl.externalcommand=Open met externes commando plug-in en.ocr=OCR Plugin (needs Microsoft Office Document Imaging (MODI)) de.ocr=OCR Plugin (braucht Microsoft Office Document Imaging (MODI)) nl.ocr=OCR Plugin (heeft Microsoft Office Document Imaging (MODI) nodig) @@ -137,32 +152,41 @@ nl.imgur=Imgur Plugin (Zie: http://imgur.com) en.language=Additional languages de.language=Zusatz Sprachen nl.language=Extra talen +en.optimize=Optimizing performance, this may take a while. +de.optimize=Optimierung der Leistung, kann etwas dauern. +nl.optimize=Prestaties verbeteren, kan even duren. [Components] Name: "plugins"; Description: "Plugins"; Types: Full Name: "plugins\ocr"; Description: {cm:ocr}; Types: Full; Name: "plugins\jira"; Description: {cm:jira}; Types: Full Name: "plugins\imgur"; Description: {cm:imgur}; Types: Full; -;Name: "plugins\confluence"; Description: "Confluence Plugin"; Types: Full -Name: "plugins\titlefix"; Description: {cm:titlefix}; Types: Full +Name: "plugins\confluence"; Description: {cm:confluence}; Types: Full +Name: "plugins\externalcommand"; Description: {cm:externalcommand}; Types: Full +;Name: "plugins\networkimport"; Description: "Network Import Plugin"; Types: Full +;Name: "plugins\box"; Description: "Box Plugin"; Types: Full +;Name: "plugins\dropbox"; Description: "DropBox Plugin"; Types: Full ;Name: "plugins\flickr"; Description: "Flickr Plugin"; Types: Full +;Name: "plugins\picasa"; Description: "Picasa Plugin"; Types: Full Name: "languages"; Description: {cm:language}; Types: Full -Name: "languages\CZ"; Description: "Ceština"; Types: Full -Name: "languages\GR"; Description: "ελληνικά"; Types: Full -Name: "languages\ES"; Description: "Español"; Types: Full -Name: "languages\FI"; Description: "Suomi"; Types: Full -Name: "languages\FR"; Description: "Français"; Types: Full -Name: "languages\IL"; Description: "עִבְרִית"; Types: Full -Name: "languages\HU"; Description: "Magyar"; Types: Full -Name: "languages\IT"; Description: "Italiano"; Types: Full -Name: "languages\JP"; Description: "日本語"; Types: Full -Name: "languages\LT"; Description: "Lietuvių"; Types: Full -Name: "languages\PL"; Description: "Polski"; Types: Full -Name: "languages\BR"; Description: "Português do Brasil"; Types: Full -Name: "languages\RU"; Description: "Pусский"; Types: Full -Name: "languages\SE"; Description: "Svenska"; Types: Full -Name: "languages\TR"; Description: "Turkish"; Types: Full -Name: "languages\CN"; Description: "简体中文"; Types: Full -Name: "languages\TW"; Description: "繁體中文"; Types: Full +Name: "languages\arSY"; Description: "العربية"; Types: Full; Check: hasLanguageGroup('d') +Name: "languages\csCZ"; Description: "Ceština"; Types: Full; Check: hasLanguageGroup('1') +Name: "languages\elGR"; Description: "ελληνικά"; Types: Full; Check: hasLanguageGroup('4') +Name: "languages\esES"; Description: "Español"; Types: Full; Check: hasLanguageGroup('1') +Name: "languages\fiFI"; Description: "Suomi"; Types: Full; Check: hasLanguageGroup('1') +Name: "languages\frFR"; Description: "Français"; Types: Full; Check: hasLanguageGroup('1') +Name: "languages\heIL"; Description: "עִבְרִית"; Types: Full; Check: hasLanguageGroup('c') +Name: "languages\huHU"; Description: "Magyar"; Types: Full; Check: hasLanguageGroup('2') +Name: "languages\itIT"; Description: "Italiano"; Types: Full; Check: hasLanguageGroup('1') +Name: "languages\jaJP"; Description: "日本語"; Types: Full; Check: hasLanguageGroup('7') +Name: "languages\ltLT"; Description: "Lietuvių"; Types: Full; Check: hasLanguageGroup('3') +Name: "languages\plPL"; Description: "Polski"; Types: Full; Check: hasLanguageGroup('2') +Name: "languages\ptBR"; Description: "Português do Brasil"; Types: Full; Check: hasLanguageGroup('1') +Name: "languages\ptPT"; Description: "Português de Portugal"; Types: Full; Check: hasLanguageGroup('1') +Name: "languages\ruRU"; Description: "Pусский"; Types: Full; Check: hasLanguageGroup('5') +Name: "languages\svSE"; Description: "Svenska"; Types: Full; Check: hasLanguageGroup('1') +Name: "languages\trTR"; Description: "Turkish"; Types: Full; Check: hasLanguageGroup('6') +Name: "languages\zhCN"; Description: "简体中文"; Types: Full; Check: hasLanguageGroup('a') +Name: "languages\zhTW"; Description: "繁體中文"; Types: Full; Check: hasLanguageGroup('9') [Code] // Build a list of greenshot parameters from the supplied installer parameters function GetParamsForGS(argument: String): String; @@ -211,6 +235,21 @@ begin Result := parametersString; end; +// Check if language group is installed +function hasLanguageGroup(argument: String): Boolean; +var + keyValue: String; + returnValue: Boolean; +begin + returnValue := true; + if (RegQueryStringValue( HKLM, 'SYSTEM\CurrentControlSet\Control\Nls\Language Groups', argument, keyValue)) then begin + if Length(keyValue) = 0 then begin + returnValue := false; + end; + end; + Result := returnValue; +end; + function InitializeSetup(): Boolean; begin // Enhance installer otherwise .NET installations won't work @@ -220,20 +259,24 @@ begin //install .netfx 2.0 sp2 if possible; if not sp1 if possible; if not .netfx 2.0 if minwinversion(5, 1) then begin dotnetfx20sp2(); - dotnetfx20sp2lp(); end else begin if minwinversion(5, 0) and minwinspversion(5, 0, 4) then begin // kb835732(); dotnetfx20sp1(); - dotnetfx20sp1lp(); end else begin dotnetfx20(); - dotnetfx20lp(); end; end; Result := true; end; [Run] -Filename: {app}\{#ExeName}.exe; Description: {cm:startgreenshot}; Parameters: {code:GetParamsForGS}; WorkingDir: {app}; Flags: nowait postinstall runasoriginaluser +Filename: "{dotnet20}\ngen.exe"; Parameters: "install ""{app}\{#ExeName}.exe"""; StatusMsg: "{cm:optimize}"; Flags: runhidden; +Filename: "{dotnet20}\ngen.exe"; Parameters: "install ""{app}\GreenshotPlugin.dll"""; StatusMsg: "{cm:optimize}"; Flags: runhidden; +Filename: "{app}\{#ExeName}.exe"; Description: "{cm:startgreenshot}"; Parameters: "{code:GetParamsForGS}"; WorkingDir: "{app}"; Flags: nowait postinstall runasoriginaluser + [InstallDelete] -Name: {app}; Type: filesandordirs; \ No newline at end of file +Name: {app}; Type: filesandordirs; + +[UninstallRun] +Filename: "{dotnet20}\ngen.exe"; Parameters: "uninstall ""{app}\{#ExeName}.exe"""; StatusMsg: "Cleanup"; Flags: runhidden; +Filename: "{dotnet20}\ngen.exe"; Parameters: "uninstall ""{app}\GreenshotPlugin.dll"""; StatusMsg: "Cleanup"; Flags: runhidden; \ No newline at end of file diff --git a/GreenshotConfluencePlugin/Confluence.cs b/GreenshotConfluencePlugin/Confluence.cs index d977b9d5a..c7e5cdf9e 100644 --- a/GreenshotConfluencePlugin/Confluence.cs +++ b/GreenshotConfluencePlugin/Confluence.cs @@ -19,14 +19,12 @@ * along with this program. If not, see . */ using System; -using System.Collections; using System.Collections.Generic; -using System.IO; -using System.Text; using System.Windows.Forms; using GreenshotConfluencePlugin; using GreenshotPlugin.Core; +using IniFile; /// /// For details see the Confluence API site @@ -37,25 +35,73 @@ namespace 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) { + id = searchResult.id; + Title = searchResult.title; + SpaceKey = space; + Url = searchResult.url; + Content = searchResult.excerpt; + } + + public Page(RemotePageSummary pageSummary) { + id = pageSummary.id; + Title = pageSummary.title; + SpaceKey = pageSummary.space; + Url =pageSummary.url; } 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 class Space { + public Space(RemoteSpaceSummary space) { + Key = space.key; + Name = space.name; + } + public string Key { + get; + set; + } + public string Name { + get; + set; + } } #endregion public class ConfluenceConnector { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ConfluenceConnector)); private const string AUTH_FAILED_EXCEPTION_NAME = "com.atlassian.confluence.rpc.AuthenticationFailedException"; - + private static ConfluenceConfiguration config = IniConfig.GetIniSection(); private string credentials = null; private DateTime loggedInTime = DateTime.Now; private bool loggedIn = false; private ConfluenceSoapServiceService confluence; private int timeout; private string url; - private Dictionary userMap = new Dictionary(); + private CacheHelper pageCache = new CacheHelper("confluencepage", 60*config.Timeout); public ConfluenceConnector(string url, int timeout) { this.url = url; @@ -68,6 +114,7 @@ namespace Confluence { ~ConfluenceConnector() { logout(); } + /// /// Internal login which catches the exceptions /// @@ -143,8 +190,10 @@ namespace Confluence { } } - public bool isLoggedIn() { - return loggedIn; + public bool isLoggedIn { + get { + return loggedIn; + } } public void addAttachment(long pageId, string mime, string comment, string filename, byte[] buffer) { @@ -158,9 +207,84 @@ namespace Confluence { } public Page getPage(string spaceKey, string pageTitle) { - checkCredentials(); - RemotePage page = confluence.getPage(credentials, spaceKey, pageTitle); + RemotePage page = null; + string cacheKey = spaceKey + pageTitle; + if (pageCache.Exists(cacheKey)) { + page = pageCache.Get(cacheKey); + } + if (page == null) { + checkCredentials(); + page = confluence.getPage(credentials, spaceKey, pageTitle); + pageCache.Add(cacheKey, page); + } return new Page(page); } + + public Page getPage(long pageId) { + RemotePage page = null; + string cacheKey = "" + pageId; + + if (pageCache.Exists(cacheKey)) { + page = pageCache.Get(cacheKey); + } + if (page == null) { + checkCredentials(); + page = confluence.getPage(credentials, pageId); + pageCache.Add(cacheKey, page); + } + return new Page(page); + } + + 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 List getSpaceSummaries() { + checkCredentials(); + RemoteSpaceSummary [] spaces = confluence.getSpaces(credentials); + List returnSpaces = new List(); + foreach(RemoteSpaceSummary space in spaces) { + returnSpaces.Add(new Space(space)); + } + returnSpaces.Sort((x, y) => string.Compare(x.Name, y.Name)); + return returnSpaces; + } + + public List getPageChildren(Page parentPage) { + checkCredentials(); + List returnPages = new List(); + RemotePageSummary[] pages = confluence.getChildren(credentials, parentPage.id); + foreach(RemotePageSummary page in pages) { + returnPages.Add(new Page(page)); + } + returnPages.Sort((x, y) => string.Compare(x.Title, y.Title)); + return returnPages; + } + + public List getPageSummaries(Space space) { + checkCredentials(); + List returnPages = new List(); + RemotePageSummary[] pages = confluence.getPages(credentials, space.Key); + foreach(RemotePageSummary page in pages) { + returnPages.Add(new Page(page)); + } + returnPages.Sort((x, y) => string.Compare(x.Title, y.Title)); + return returnPages; + } + + public List searchPages(string query, string space) { + checkCredentials(); + List results = new List(); + foreach(RemoteSearchResult searchResult in confluence.search(credentials, query, 20)) { + LOG.DebugFormat("Got result of type {0}", searchResult.type); + if ("page".Equals(searchResult.type)) { + results.Add(new Page(searchResult, space)); + } + } + return results; + } } } diff --git a/GreenshotConfluencePlugin/ConfluenceConfiguration.cs b/GreenshotConfluencePlugin/ConfluenceConfiguration.cs index 313452a27..5897c775b 100644 --- a/GreenshotConfluencePlugin/ConfluenceConfiguration.cs +++ b/GreenshotConfluencePlugin/ConfluenceConfiguration.cs @@ -19,49 +19,55 @@ * along with this program. If not, see . */ using System; -using System.Collections.Generic; -using System.Windows.Forms; - using GreenshotPlugin.Core; +using IniFile; namespace GreenshotConfluencePlugin { /// /// Description of ConfluenceConfiguration. /// + [Serializable] [IniSection("Confluence", Description="Greenshot Confluence Plugin configuration")] public class ConfluenceConfiguration : IniSection { public const string DEFAULT_POSTFIX = "/rpc/soap-axis/confluenceservice-v1?wsdl"; public const string DEFAULT_PREFIX = "http://"; - private const string DEFAULT_URL = DEFAULT_PREFIX + "confluence" + DEFAULT_POSTFIX; + private const string DEFAULT_URL = DEFAULT_PREFIX + "confluence"; [IniProperty("Url", Description="Url to Confluence system, including wsdl.", DefaultValue=DEFAULT_URL)] - public string Url; + public string Url { + get; + set; + } [IniProperty("Timeout", Description="Session timeout in minutes", DefaultValue="30")] - public int Timeout; + public int Timeout { + get; + set; + } [IniProperty("UploadFormat", Description="What file type to use for uploading", DefaultValue="png")] - public OutputFormat UploadFormat; + public OutputFormat UploadFormat { + get; + set; + } [IniProperty("UploadJpegQuality", Description="JPEG file save quality in %.", DefaultValue="80")] - public int UploadJpegQuality; - - /// - /// A form for username/password - /// - /// bool true if OK was pressed, false if cancel - public bool ShowConfigDialog() { - SettingsForm settingsForm = new SettingsForm(); - settingsForm.Url = Url; - settingsForm.UploadFormat = UploadFormat.ToString(); - DialogResult result = settingsForm.ShowDialog(); - if (result == DialogResult.OK) { - if (!settingsForm.Url.Equals(Url) || !settingsForm.UploadFormat.Equals(UploadFormat.ToString())) { - Url = settingsForm.Url; - UploadFormat = (OutputFormat)Enum.Parse(typeof(OutputFormat), settingsForm.UploadFormat); - } - IniConfig.Save(); - return true; - } - return false; - } + public int UploadJpegQuality { + get; + set; + } + [IniProperty("OpenPageAfterUpload", Description="Open the page where the picture is uploaded after upload", DefaultValue="True")] + 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; + } + [IniProperty("SearchSpaceKey", Description="Key of last space that was searched for")] + public string SearchSpaceKey { + get; + set; + } } } diff --git a/GreenshotConfluencePlugin/ConfluenceDestination.cs b/GreenshotConfluencePlugin/ConfluenceDestination.cs new file mode 100644 index 000000000..b19fa33ef --- /dev/null +++ b/GreenshotConfluencePlugin/ConfluenceDestination.cs @@ -0,0 +1,176 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Diagnostics; +using System.Drawing; +using System.IO; +using System.Threading; +using System.Windows; + +using Confluence; +using Greenshot.Plugin; +using GreenshotPlugin.Core; +using IniFile; + +namespace GreenshotConfluencePlugin { + /// + /// Description of JiraDestination. + /// + public class ConfluenceDestination : AbstractDestination { + private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ConfluenceDestination)); + private static ConfluenceConfiguration config = IniConfig.GetIniSection(); + private static Image confluenceIcon = null; + private ILanguage lang = Language.GetInstance(); + private Confluence.Page page; + + static ConfluenceDestination() { + Uri confluenceIconUri = new Uri("/GreenshotConfluencePlugin;component/Images/Confluence.ico", UriKind.Relative); + using (Stream iconStream = Application.GetResourceStream(confluenceIconUri).Stream) { + confluenceIcon = Image.FromStream(iconStream); + } + } + + public ConfluenceDestination() { + + } + public ConfluenceDestination(Confluence.Page page) { + this.page = page; + } + + public override string Designation { + get { + return "Confluence"; + } + } + + public override string Description { + get { + if (page == null) { + return lang.GetString(LangKey.upload_menu_item); + } else { + return lang.GetString(LangKey.upload_menu_item) + ": \"" + page.Title + "\""; + } + } + } + + public override bool isDynamic { + get { + return true; + } + } + + public override bool isActive { + get { + return !string.IsNullOrEmpty(config.Url); + } + } + + public override Image DisplayIcon { + get { + return confluenceIcon; + } + } + + public override IEnumerable DynamicDestinations() { + if (!ConfluencePlugin.ConfluenceConnector.isLoggedIn) { + yield break; + } + List currentPages = ConfluenceUtils.GetCurrentPages(); + if (currentPages == null || currentPages.Count == 0) { + yield break; + } + List dynamicDestinations = new List(); + foreach(Confluence.Page currentPage in currentPages) { + yield return new ConfluenceDestination(currentPage); + } + } + + public override bool ExportCapture(ISurface surface, ICaptureDetails captureDetails) { + // force password check to take place before the pages load + if (!ConfluencePlugin.ConfluenceConnector.isLoggedIn) { + return false; + } + + Page selectedPage = page; + string filename = ConfluencePlugin.Host.GetFilename(config.UploadFormat, captureDetails); + if (page == null) { + ConfluenceUpload confluenceUpload = new ConfluenceUpload(filename); + Nullable dialogResult = confluenceUpload.ShowDialog(); + if (dialogResult.HasValue && dialogResult.Value) { + selectedPage = confluenceUpload.SelectedPage; + filename = confluenceUpload.Filename; + } else { + return false; + } + } + if (selectedPage != null) { + using (Image image = surface.GetImageForExport()) { + bool uploaded = upload(image, selectedPage, filename); + if (uploaded) { + surface.SendMessageEvent(this, SurfaceMessageTyp.Info, ConfluencePlugin.Host.CoreLanguage.GetFormattedString("exported_to", Description)); + surface.Modified = false; + return true; + } + } + } + + return false; + } + + private bool upload(Image image, Page page, string filename) { + using (MemoryStream stream = new MemoryStream()) { + ConfluencePlugin.Host.SaveToStream(image, stream, config.UploadFormat, config.UploadJpegQuality); + byte [] buffer = stream.GetBuffer(); + try { + ConfluencePlugin.ConfluenceConnector.addAttachment(page.id, "image/" + config.UploadFormat.ToString().ToLower(), null, filename, buffer); + LOG.Debug("Uploaded to Confluence."); + if (config.CopyWikiMarkupForImageToClipboard) { + int retryCount = 2; + while (retryCount >= 0) { + try { + Clipboard.SetText("!" + filename + "!"); + break; + } catch (Exception ee) { + if (retryCount == 0) { + LOG.Error(ee); + } else { + Thread.Sleep(100); + } + } finally { + --retryCount; + } + } + } + if (config.OpenPageAfterUpload) { + Process.Start(page.Url); + } else { + System.Windows.MessageBox.Show(lang.GetString(LangKey.upload_success)); + } + return true; + } catch(Exception e) { + System.Windows.MessageBox.Show(lang.GetString(LangKey.upload_failure) + " " + e.Message); + } + } + return false; + } + } +} diff --git a/GreenshotConfluencePlugin/ConfluencePlugin.cs b/GreenshotConfluencePlugin/ConfluencePlugin.cs new file mode 100644 index 000000000..ec43c4b39 --- /dev/null +++ b/GreenshotConfluencePlugin/ConfluencePlugin.cs @@ -0,0 +1,148 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Diagnostics; +using System.Drawing; +using System.IO; +using System.Windows; + +using Confluence; +using Greenshot.Plugin; +using GreenshotPlugin.Core; +using IniFile; +using TranslationByMarkupExtension; + +namespace GreenshotConfluencePlugin { + /// + /// This is the ConfluencePlugin base code + /// + public class ConfluencePlugin : IGreenshotPlugin { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ConfluencePlugin)); + private static ConfluenceConnector confluenceConnector = null; + private static PluginAttribute ConfluencePluginAttributes; + private static ConfluenceConfiguration config = null; + private static ILanguage lang = Language.GetInstance(); + private static IGreenshotHost host; + + public static ConfluenceConnector ConfluenceConnector { + get { + if (confluenceConnector == null) { + if (config.Url.Contains("soap-axis")) { + confluenceConnector = new ConfluenceConnector(config.Url, config.Timeout); + } else { + confluenceConnector = new ConfluenceConnector(config.Url + ConfluenceConfiguration.DEFAULT_POSTFIX, config.Timeout); + } + } + try { + if (!confluenceConnector.isLoggedIn) { + confluenceConnector.login(); + } + } catch (Exception e) { + MessageBox.Show(lang.GetFormattedString(LangKey.login_error, e.Message)); + } + return confluenceConnector; + } + } + + public static IGreenshotHost Host { + get { + return host; + } + } + + public ConfluencePlugin() { + } + + public IEnumerable Destinations() { + yield return new ConfluenceDestination(); + } + + public IEnumerable Processors() { + yield break; + } + + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + /// Use the IGreenshotPluginHost interface to register events + /// Use the ICaptureHost interface to register in the MainContextMenu + /// My own attributes + public virtual bool Initialize(IGreenshotHost pluginHost, PluginAttribute myAttributes) { + host = pluginHost; + ConfluencePluginAttributes = myAttributes; + + // Register configuration (don't need the configuration itself) + config = IniConfig.GetIniSection(); + if(config.IsDirty) { + IniConfig.Save(); + } + TranslationManager.Instance.TranslationProvider = new LanguageXMLTranslationProvider(); + //resources = new ComponentResourceManager(typeof(JiraPlugin)); + return true; + } + + public virtual void Shutdown() { + LOG.Debug("Confluence Plugin shutdown."); + if (confluenceConnector != null) { + confluenceConnector.logout(); + } + } + + /// + /// Implementation of the IPlugin.Configure + /// + public virtual void Configure() { + ConfluenceConfiguration clonedConfig = config.Clone(); + ConfluenceConfigurationForm configForm = new ConfluenceConfigurationForm(clonedConfig); + Nullable dialogResult = configForm.ShowDialog(); + if (dialogResult.HasValue && dialogResult.Value) { + // copy the new object to the old... + clonedConfig.CloneTo(config); + IniConfig.Save(); + confluenceConnector.logout(); + confluenceConnector = null; + } + } + + public void upload(IImageEditor imageEditor, Page page, string filename) { + using (MemoryStream stream = new MemoryStream()) { + imageEditor.SaveToStream(stream, config.UploadFormat, config.UploadJpegQuality); + byte [] buffer = stream.GetBuffer(); + try { + confluenceConnector.addAttachment(page.id, "image/" + config.UploadFormat.ToString().ToLower(), null, filename, buffer); + imageEditor.Surface.Modified = false; + LOG.Debug("Uploaded to Confluence."); + if (config.CopyWikiMarkupForImageToClipboard) { + System.Windows.Clipboard.SetText("!" + filename + "!"); + } + if (config.OpenPageAfterUpload) { + Process.Start(page.Url); + } else { + System.Windows.MessageBox.Show(lang.GetString(LangKey.upload_success)); + } + } catch(Exception e) { + System.Windows.MessageBox.Show(lang.GetString(LangKey.upload_failure) + " " + e.Message); + } + } + } + } +} diff --git a/GreenshotConfluencePlugin/ConfluencePluginBase.cs b/GreenshotConfluencePlugin/ConfluencePluginBase.cs deleted file mode 100644 index 1ece49e4b..000000000 --- a/GreenshotConfluencePlugin/ConfluencePluginBase.cs +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Drawing.Imaging; -using System.IO; -using System.Text; -using System.Windows.Forms; - -using Confluence; -using Greenshot.Plugin; -using GreenshotPlugin.Core; - -namespace GreenshotConfluencePlugin { - /// - /// This is the ConfluencePlugin base code - /// - public class ConfluencePlugin : IGreenshotPlugin { - private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ConfluencePlugin)); - private ILanguage lang = Language.GetInstance(); - private IGreenshotPluginHost host; - private ICaptureHost captureHost = null; - private ConfluenceConnector confluenceConnector = null; - private PluginAttribute myAttributes; - private ConfluenceConfiguration config = null; - - public ConfluencePlugin() { - } - - /// - /// Implementation of the IGreenshotPlugin.Initialize - /// - /// Use the IGreenshotPluginHost interface to register events - /// Use the ICaptureHost interface to register in the MainContextMenu - /// My own attributes - public virtual void Initialize(IGreenshotPluginHost pluginHost, ICaptureHost captureHost, PluginAttribute myAttributes) { - this.host = (IGreenshotPluginHost)pluginHost; - this.captureHost = captureHost; - this.myAttributes = myAttributes; - host.OnImageEditorOpen += new OnImageEditorOpenHandler(ImageEditorOpened); - - // Register configuration (don't need the configuration itself) - config = IniConfig.GetIniSection(); - if(config.IsDirty) { - IniConfig.Save(); - } - } - - public virtual void Shutdown() { - LOG.Debug("Plugin shutdown."); - host.OnImageEditorOpen -= new OnImageEditorOpenHandler(ImageEditorOpened); - if (confluenceConnector != null) { - confluenceConnector.logout(); - } - } - - /// - /// Implementation of the IPlugin.Configure - /// - public virtual void Configure() { - config.ShowConfigDialog(); - } - - /// - /// This will be called when Greenshot is shutting down - /// - /// - /// - public void Closing(object sender, FormClosingEventArgs e) { - LOG.Debug("Application closing, calling logout of jira!"); - Shutdown(); - } - - /// - /// Implementation of the OnImageEditorOpen event - /// Using the ImageEditor interface to register in the plugin menu - /// - private void ImageEditorOpened(object sender, ImageEditorOpenEventArgs eventArgs) { - ToolStripMenuItem toolStripMenuItem = eventArgs.ImageEditor.GetPluginMenuItem(); - ToolStripMenuItem item = new ToolStripMenuItem(); - item.Text = "Upload to Confluence"; - item.Tag = eventArgs.ImageEditor; - item.Click += new System.EventHandler(EditMenuClick); - toolStripMenuItem.DropDownItems.Add(item); - } - - - /// - /// This will be called when the menu item in the Editor is clicked - /// - public void EditMenuClick(object sender, EventArgs eventArgs) { - ToolStripMenuItem item = (ToolStripMenuItem)sender; - IImageEditor imageEditor = (IImageEditor)item.Tag; - - if (confluenceConnector == null) { - confluenceConnector = new ConfluenceConnector(config.Url, config.Timeout); - } - - ConfluenceForm confluenceForm = new ConfluenceForm(confluenceConnector); - if (confluenceConnector.isLoggedIn()) { - confluenceForm.setFilename(host.GetFilename(config.UploadFormat, imageEditor.CaptureDetails)); - DialogResult result = confluenceForm.ShowDialog(); - if (result == DialogResult.OK) { - using (MemoryStream stream = new MemoryStream()) { - imageEditor.SaveToStream(stream, config.UploadFormat, config.UploadJpegQuality); - byte [] buffer = stream.GetBuffer(); - try { - confluenceForm.upload(buffer); - LOG.Debug("Uploaded to Confluence."); - MessageBox.Show(lang.GetString(LangKey.upload_success)); - } catch(Exception e) { - MessageBox.Show(lang.GetString(LangKey.upload_failure) + " " + e.Message); - } - } - } - } - } - } -} diff --git a/GreenshotConfluencePlugin/ConfluenceUtils.cs b/GreenshotConfluencePlugin/ConfluenceUtils.cs new file mode 100644 index 000000000..38e5b046d --- /dev/null +++ b/GreenshotConfluencePlugin/ConfluenceUtils.cs @@ -0,0 +1,157 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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.Diagnostics; +using System.Text.RegularExpressions; +using System.Windows.Automation; + +using GreenshotPlugin.Core; +using Confluence; + +namespace GreenshotConfluencePlugin { + /// + /// Description of ConfluenceUtils. + /// + public class ConfluenceUtils { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ConfluenceUtils)); + + public static List GetCurrentPages() { + List pages = new List(); + Regex pageIdRegex = new Regex(@"pageId=(\d+)"); + Regex spacePageRegex = new Regex(@"\/display\/([^\/]+)\/([^#]+)"); + foreach(string browserurl in GetBrowserUrls()) { + string url = null; + try { + url = Uri.UnescapeDataString(browserurl).Replace("+", " "); + } catch { + LOG.WarnFormat("Error processing URL: {0}", browserurl); + continue; + } + MatchCollection pageIdMatch = pageIdRegex.Matches(url); + if (pageIdMatch != null && pageIdMatch.Count > 0) { + long pageId = long.Parse(pageIdMatch[0].Groups[1].Value); + try { + bool pageDouble = false; + foreach(Confluence.Page page in pages) { + if (page.id == pageId) { + pageDouble = true; + LOG.DebugFormat("Skipping double page with ID {0}", pageId); + break; + } + } + if (!pageDouble) { + Confluence.Page page = ConfluencePlugin.ConfluenceConnector.getPage(pageId); + LOG.DebugFormat("Adding page {0}", page.Title); + pages.Add(page); + } + continue; + } 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) { + string space = spacePageMatch[0].Groups[1].Value; + string title = spacePageMatch[0].Groups[2].Value; + if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(space)) { + continue; + } + if (title.EndsWith("#")) { + title = title.Substring(0, title.Length-1); + } + try { + bool pageDouble = false; + foreach(Confluence.Page page in pages) { + if (page.Title.Equals(title)) { + LOG.DebugFormat("Skipping double page with title {0}", title); + pageDouble = true; + break; + } + } + if (!pageDouble) { + Confluence.Page page = ConfluencePlugin.ConfluenceConnector.getPage(space, title); + LOG.DebugFormat("Adding page {0}", page.Title); + pages.Add(page); + + } + continue; + } catch (Exception ex) { + // Preventing security problems + LOG.DebugFormat("Couldn't get page details for space {0} / title {1}", space, title); + LOG.Warn(ex); + } + } + } + } + return pages; + } + + private static IEnumerable GetBrowserUrls() { + HashSet urls = new HashSet(); + + // FireFox + foreach(Process firefox in Process.GetProcessesByName("firefox")) { + LOG.DebugFormat("Checking process {0}", firefox.Id); + foreach(AutomationElement rootElement in AutomationElement.RootElement.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ProcessIdProperty, firefox.Id))) { + Condition condCustomControl = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Custom); + //AutomationElement rootElement = AutomationElement.FromHandle(firefox.MainWindowHandle); + var collection = rootElement.FindAll(TreeScope.Children, condCustomControl); + if (collection == null || collection.Count == 0) { + continue; + } + AutomationElement firstCustomControl = collection[collection.Count - 1]; + if (firstCustomControl == null) { + continue; + } + AutomationElement secondCustomControl = firstCustomControl.FindFirst(TreeScope.Children, condCustomControl); + if (secondCustomControl == null) { + continue; + } + foreach (AutomationElement thirdElement in secondCustomControl.FindAll(TreeScope.Children, condCustomControl)) { + foreach (AutomationElement fourthElement in thirdElement.FindAll(TreeScope.Children, condCustomControl)) { + Condition condDocument = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Document); + AutomationElement docElement = fourthElement.FindFirst(TreeScope.Children, condDocument); + if (docElement != null) { + foreach (AutomationPattern pattern in docElement.GetSupportedPatterns()) { + if (docElement.GetCurrentPattern(pattern) is ValuePattern) { + string url = (docElement.GetCurrentPattern(pattern) as ValuePattern).Current.Value.ToString(); + urls.Add(url); + } + } + } + } + } + } + } + + foreach(string url in IEHelper.GetIEUrls()) { + urls.Add(url); + } + + return urls; + } + + } +} diff --git a/GreenshotConfluencePlugin/EnumDisplayer.cs b/GreenshotConfluencePlugin/EnumDisplayer.cs new file mode 100644 index 000000000..f46a07d12 --- /dev/null +++ b/GreenshotConfluencePlugin/EnumDisplayer.cs @@ -0,0 +1,104 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2011 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/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; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Globalization; +using System.Reflection; +using System.Windows.Data; + +using GreenshotPlugin.Core; + +namespace GreenshotConfluencePlugin { + public class EnumDisplayer : IValueConverter { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(EnumDisplayer)); + private ILanguage lang = Language.GetInstance(); + + private Type type; + private IDictionary displayValues; + private IDictionary reverseValues; + + public EnumDisplayer() { + } + + public EnumDisplayer(Type type) { + this.Type = type; + } + + public Type Type { + get { return type; } + set { + if (!value.IsEnum) { + throw new ArgumentException("parameter is not an Enumerated type", "value"); + } + this.type = value; + } + } + + public ReadOnlyCollection DisplayNames { + get { + this.reverseValues = (IDictionary) Activator.CreateInstance(typeof(Dictionary<,>).GetGenericTypeDefinition().MakeGenericType(typeof(string),type)); + + this.displayValues = (IDictionary)Activator.CreateInstance(typeof(Dictionary<,>).GetGenericTypeDefinition().MakeGenericType(type, typeof(string))); + + var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static); + foreach (var field in fields) { + DisplayKeyAttribute[] a = (DisplayKeyAttribute[])field.GetCustomAttributes(typeof(DisplayKeyAttribute), false); + + string displayKey = GetDisplayKeyValue(a); + object enumValue = field.GetValue(null); + + string displayString = null; + if (displayKey != null && lang.hasKey(displayKey)) { + displayString = lang.GetString(displayKey); + } if (displayKey != null) { + displayString = displayKey; + } else { + displayString = enumValue.ToString(); + } + + if (displayString != null) { + displayValues.Add(enumValue, displayString); + reverseValues.Add(displayString, enumValue); + } + } + return new List((IEnumerable)displayValues.Values).AsReadOnly(); + } + } + + private 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) { + return displayValues[value]; + } + + object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { + return reverseValues[value]; + } + } +} diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml b/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml new file mode 100644 index 000000000..862d55115 --- /dev/null +++ b/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + +