From 7066a5e6ee9b216cdb7a3e9cff18f9a551f2ee5a Mon Sep 17 00:00:00 2001 From: RKrom Date: Wed, 22 Sep 2010 09:41:19 +0000 Subject: [PATCH] Refactoring for new patterns and added the other projects to the solution, so refactoring is always made over all files. git-svn-id: http://svn.code.sf.net/p/greenshot/code/trunk@895 7dccd23d-a4a3-4e1f-8c07-b4c1b4018ab4 --- Greenshot/Forms/CaptureForm.cs | 3 +- Greenshot/Forms/MainForm.cs | 5 +- Greenshot/Greenshot.sln | 28 ++- Greenshot/releases/innosetup/setup.iss | 6 +- GreenshotCore/Forms/SaveImageFileDialog.cs | 1 + GreenshotCore/Forms/SettingsForm.cs | 38 ++-- GreenshotCore/Helpers/FilenameHelper.cs | 226 +++++++++++++++++---- 7 files changed, 247 insertions(+), 60 deletions(-) diff --git a/Greenshot/Forms/CaptureForm.cs b/Greenshot/Forms/CaptureForm.cs index b6a7a97f4..54929abff 100644 --- a/Greenshot/Forms/CaptureForm.cs +++ b/Greenshot/Forms/CaptureForm.cs @@ -335,7 +335,8 @@ namespace Greenshot.Forms { bool fileWritten = false; if (captureDestinations.Contains(CaptureDestination.File)) { string filename = FilenameHelper.GetFilenameFromPattern(conf.OutputFileFilenamePattern, conf.OutputFileFormat, captureDetails); - fullPath = Path.Combine(conf.OutputFilePath,filename); + 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 diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs index 286f03457..28c82c1dd 100644 --- a/Greenshot/Forms/MainForm.cs +++ b/Greenshot/Forms/MainForm.cs @@ -607,10 +607,11 @@ namespace Greenshot { /// private void ContextMenuDoubleClick(object sender, EventArgs eventArgs) { string path; + string configPath = FilenameHelper.FillVariables(conf.OutputFilePath); if (lastImagePath != null && Directory.Exists(lastImagePath)) { path = lastImagePath; - } else if (Directory.Exists(conf.OutputFilePath)) { - path = conf.OutputFilePath; + } else if (Directory.Exists(configPath)) { + path = configPath; } else { // What do I open when nothing can be found? Right, nothing... return; diff --git a/Greenshot/Greenshot.sln b/Greenshot/Greenshot.sln index c22ca1a22..87a30fcff 100644 --- a/Greenshot/Greenshot.sln +++ b/Greenshot/Greenshot.sln @@ -1,4 +1,5 @@ -Microsoft Visual Studio Solution File, Format Version 10.00 + +Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 # SharpDevelop 3.2.0.5777 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GreenshotCore", "..\GreenshotCore\GreenshotCore.csproj", "{BDC408EE-DEA1-4474-B59D-7F05757B12EC}" @@ -17,6 +18,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Greenshot", "Greenshot.cspr {0A07500E-7404-48D7-8789-7EB2A23E0DD5} = {0A07500E-7404-48D7-8789-7EB2A23E0DD5} EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GreenshotJiraPlugin", "..\GreenshotJiraPlugin\GreenshotJiraPlugin.csproj", "{19FEEF09-313F-43C7-819D-F1BCA782B08B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GreenshotConfluencePlugin", "..\GreenshotConfluencePlugin\GreenshotConfluencePlugin.csproj", "{C3052651-598A-44E2-AAB3-2E41311D50F9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GreenshotFlickrPlugin", "..\GreenshotFlickrPlugin\GreenshotFlickrPlugin.csproj", "{56828D7F-F227-41EC-8873-CC32A23A1783}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Greenshot-RunAtOutput-Plugin", "..\Greenshot-RunAtOutput-Plugin\Greenshot-RunAtOutput-Plugin.csproj", "{47F23C86-604E-4CC3-8767-B3D4088F30BB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -43,6 +52,21 @@ Global {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 + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|Any CPU.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}.Release|Any CPU.Build.0 = Release|x86 + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|Any CPU.ActiveCfg = Release|x86 + {56828D7F-F227-41EC-8873-CC32A23A1783}.Debug|Any CPU.Build.0 = Debug|x86 + {56828D7F-F227-41EC-8873-CC32A23A1783}.Debug|Any CPU.ActiveCfg = Debug|x86 + {56828D7F-F227-41EC-8873-CC32A23A1783}.Release|Any CPU.Build.0 = Release|x86 + {56828D7F-F227-41EC-8873-CC32A23A1783}.Release|Any CPU.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}.Release|Any CPU.Build.0 = Release|x86 + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|Any CPU.ActiveCfg = Release|x86 EndGlobalSection EndGlobal - diff --git a/Greenshot/releases/innosetup/setup.iss b/Greenshot/releases/innosetup/setup.iss index 3b4b045d2..9f6a181b2 100644 --- a/Greenshot/releases/innosetup/setup.iss +++ b/Greenshot/releases/innosetup/setup.iss @@ -26,8 +26,8 @@ Source: ..\additional_files\*; DestDir: {app}; Flags: overwritereadonly recurses 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; ;JIRA Plugin -;Source: ..\..\bin\Release\Plugins\GreenshotJiraPlugin\*; DestDir: {app}\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -;Source: ..\..\bin\Release\Languages\Plugins\GreenshotJiraPlugin\*; DestDir: {app}\Languages\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\bin\Release\Plugins\GreenshotJiraPlugin\*; DestDir: {app}\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: ..\..\bin\Release\Languages\Plugins\GreenshotJiraPlugin\*; DestDir: {app}\Languages\Plugins\GreenshotJiraPlugin; Components: plugins\jira; 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; @@ -107,7 +107,7 @@ nl.ocr=OCR Plugin (heeft Microsoft Office 2003 of 2007 nodig) [Components] Name: "plugins"; Description: "Plugins"; Types: Full Name: "plugins\ocr"; Description: {cm:ocr}; Types: Full; Check: CheckMODI -;Name: "plugins\jira"; Description: "JIRA Plugin"; Types: Full +Name: "plugins\jira"; Description: "JIRA Plugin"; Types: Full Name: "plugins\titlefix"; Description: {cm:titlefix}; Types: Full ;Name: "plugins\flickr"; Description: "Flickr Plugin"; Types: Full [Code] diff --git a/GreenshotCore/Forms/SaveImageFileDialog.cs b/GreenshotCore/Forms/SaveImageFileDialog.cs index 92dd6a116..71ac839a0 100644 --- a/GreenshotCore/Forms/SaveImageFileDialog.cs +++ b/GreenshotCore/Forms/SaveImageFileDialog.cs @@ -204,6 +204,7 @@ namespace Greenshot.Forms { private string GetRootDirFromConfig() { string rootDir =conf.OutputFilePath; + rootDir = FilenameHelper.FillVariables(rootDir); // the idea was to let the user choose whether to suggest the dir // configured in the settings dialog or just remember the latest path. // however, we'd need an extra option for this, making the settings dialog diff --git a/GreenshotCore/Forms/SettingsForm.cs b/GreenshotCore/Forms/SettingsForm.cs index d272a2d70..8ec770962 100644 --- a/GreenshotCore/Forms/SettingsForm.cs +++ b/GreenshotCore/Forms/SettingsForm.cs @@ -158,7 +158,7 @@ namespace Greenshot { // Check the settings and somehow visibly mark when something is incorrect private bool CheckSettings() { bool settingsOk = true; - if(!Directory.Exists(textbox_storagelocation.Text)) { + if(!Directory.Exists(FilenameHelper.FillVariables(textbox_storagelocation.Text))) { textbox_storagelocation.BackColor = Color.Red; settingsOk = false; } else { @@ -259,17 +259,21 @@ namespace Greenshot { IniConfig.Save(); - // Check if the Run for all is set - if(!StartupHelper.checkRunAll()) { - // If not set the registry according to the settings - if (checkbox_autostartshortcut.Checked) { - StartupHelper.setRunUser(); + try { + // Check if the Run for all is set + if(!StartupHelper.checkRunAll()) { + // If not set the registry according to the settings + if (checkbox_autostartshortcut.Checked) { + StartupHelper.setRunUser(); + } else { + StartupHelper.deleteRunUser(); + } } else { + // The run key for Greenshot is set for all users, delete the local version! StartupHelper.deleteRunUser(); } - } else { - // The run key for Greenshot is set for all users, delete the local version! - StartupHelper.deleteRunUser(); + } catch (Exception e) { + LOG.Warn("Problem checking registry, ignoring for now: ", e); } } @@ -278,14 +282,22 @@ namespace Greenshot { } void Settings_okayClick(object sender, System.EventArgs e) { - SaveSettings(); - this.Close(); + if (CheckSettings()) { + SaveSettings(); + this.Close(); + } else { + this.tabcontrol.SelectTab(this.tab_output); + } } void BrowseClick(object sender, System.EventArgs e) { - this.folderBrowserDialog1.SelectedPath = this.textbox_storagelocation.Text; + // Get the storage location and replace the environment variables + this.folderBrowserDialog1.SelectedPath = FilenameHelper.FillVariables(this.textbox_storagelocation.Text); if(this.folderBrowserDialog1.ShowDialog() == DialogResult.OK) { - this.textbox_storagelocation.Text = this.folderBrowserDialog1.SelectedPath; + // 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))) { + this.textbox_storagelocation.Text = this.folderBrowserDialog1.SelectedPath; + } } CheckSettings(); } diff --git a/GreenshotCore/Helpers/FilenameHelper.cs b/GreenshotCore/Helpers/FilenameHelper.cs index c5a4f4603..9fbc6b697 100644 --- a/GreenshotCore/Helpers/FilenameHelper.cs +++ b/GreenshotCore/Helpers/FilenameHelper.cs @@ -21,6 +21,7 @@ using System; using System.Collections; using System.IO; +using System.Text.RegularExpressions; using System.Windows.Forms; using Greenshot.Capturing; @@ -30,6 +31,8 @@ using Greenshot.Plugin; namespace Greenshot.Helpers { public class FilenameHelper { + private static readonly Regex VAR_REGEXP = new Regex(@"\${(?[^:}]+)[:]?(?[^}]*)}", RegexOptions.Compiled); + private static readonly Regex SPLIT_REGEXP = new Regex(";(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", RegexOptions.Compiled); private const int MAX_TITLE_LENGTH = 80; private static CoreConfiguration conf = IniConfig.GetIniSection(); @@ -93,55 +96,200 @@ namespace Greenshot.Helpers { return FillPattern(pattern, captureDetails) + "." + imageFormat; } - private static string FillPattern(string initialPattern, ICaptureDetails captureDetails) { - string pattern = string.Copy(initialPattern); - // Default use "now" for the capture taken - DateTime captureTaken = DateTime.Now; - // Use default application name for title - string title = Application.ProductName; + /// + /// This method will be called by the regexp.replace as a MatchEvaluator delegate! + /// + /// What are we matching? + /// The detail, can be null + /// + private static string MatchVarEvaluator(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars) { + // some defaults + int padWidth = 0; + int startIndex = 0; + int endIndex = 0; + char padChar = ' '; + string dateFormat = "yyyy-MM-dd HH-mm-ss"; - // Check if we have capture details - if (captureDetails != null) { - captureTaken = captureDetails.DateTime; - if (captureDetails.Title != null) { - title = captureDetails.Title; - if (title.Length > MAX_TITLE_LENGTH) { - title = title.Substring(0, MAX_TITLE_LENGTH); + string replaceValue = ""; + string variable = match.Groups["variable"].Value; + string parameters = match.Groups["parameters"].Value; + + if (parameters != null && parameters.Length > 0) { + string []parms = SPLIT_REGEXP.Split(parameters); + foreach(string parameter in parms) { + switch (parameter.Substring(0,1)) { + case "p": + string []padParams = parameter.Substring(1).Split(new char[] {','}); + try { + padWidth = int.Parse(padParams[0]); + } catch {}; + if (padParams.Length > 1) { + padChar = padParams[1][0]; + } + break; + case "d": + dateFormat = parameter.Substring(1); + if (dateFormat.StartsWith("\"")) { + dateFormat = dateFormat.Substring(1); + } + if (dateFormat.EndsWith("\"")) { + dateFormat = dateFormat.Substring(0, dateFormat.Length-1); + } + break; + case "s": + string range=parameter.Substring(1); + string []rangelist = range.Split(new char[] {','}); + if (rangelist.Length > 0) { + try { + startIndex = int.Parse(rangelist[0]); + } catch { + // Ignore + } + } + if (rangelist.Length > 1) { + try { + endIndex = int.Parse(rangelist[1]); + } catch { + // Ignore + } + } + break; + } + } + } + if (processVars != null && processVars.Contains(variable)) { + replaceValue = (string)processVars[variable]; + } else if (userVars != null && userVars.Contains(variable)) { + replaceValue = (string)userVars[variable]; + } else if (machineVars != null && machineVars.Contains(variable)) { + replaceValue = (string)machineVars[variable]; + } else { + // Handle other variables + // Default use "now" for the capture take´n + DateTime capturetime = DateTime.Now; + // Use default application name for title + string title = Application.ProductName; + + // Check if we have capture details + if (captureDetails != null) { + capturetime = captureDetails.DateTime; + if (captureDetails.Title != null) { + title = captureDetails.Title; + if (title.Length > MAX_TITLE_LENGTH) { + title = title.Substring(0, MAX_TITLE_LENGTH); + } + } + } + switch(variable) { + case "domain": + replaceValue = Environment.UserDomainName; + break; + case "user": + replaceValue = Environment.UserName; + break; + case "hostname": + replaceValue = Environment.MachineName; + break; + case "YYYY": + replaceValue = capturetime.Year.ToString(); + break; + case "MM": + replaceValue = capturetime.Month.ToString(); + break; + case "DD": + replaceValue = capturetime.Day.ToString(); + break; + case "hh": + replaceValue = capturetime.Hour.ToString(); + break; + case "mm": + replaceValue = capturetime.Minute.ToString(); + break; + case "ss": + replaceValue = capturetime.Second.ToString(); + break; + case "now": + replaceValue = DateTime.Now.ToString(dateFormat); + break; + case "capturetime": + replaceValue = capturetime.ToString(dateFormat); + break; + case "NUM": + conf.OutputFileIncrementingNumber = conf.OutputFileIncrementingNumber++; + IniConfig.Save(); + replaceValue = conf.OutputFileIncrementingNumber.ToString(); + if (padWidth == 0) { + padWidth = -6; + padChar = '0'; + } + + break; + case "title": + replaceValue = MakeFilenameSafe(title); + break; + } + } + // do substring + if (startIndex != 0 || endIndex != 0) { + if (startIndex < 0) { + startIndex = replaceValue.Length + startIndex; + } + if (endIndex < 0) { + endIndex = replaceValue.Length + endIndex; + } + if (endIndex != 0) { + try { + replaceValue = replaceValue.Substring(startIndex, endIndex); + } catch { + // Ignore + } + } else { + try { + replaceValue = replaceValue.Substring(startIndex); + } catch { + // Ignore } } } - pattern = pattern.Replace("%YYYY%",captureTaken.Year.ToString()); - pattern = pattern.Replace("%MM%", zeroPad(captureTaken.Month.ToString(), 2)); - pattern = pattern.Replace("%DD%", zeroPad(captureTaken.Day.ToString(), 2)); - pattern = pattern.Replace("%hh%", zeroPad(captureTaken.Hour.ToString(), 2)); - pattern = pattern.Replace("%mm%", zeroPad(captureTaken.Minute.ToString(), 2)); - pattern = pattern.Replace("%ss%", zeroPad(captureTaken.Second.ToString(), 2)); - pattern = pattern.Replace("%domain%", Environment.UserDomainName); - pattern = pattern.Replace("%user%", Environment.UserName); - pattern = pattern.Replace("%hostname%", Environment.MachineName); - if(pattern.Contains("%NUM%")) { - uint num = conf.OutputFileIncrementingNumber++; - IniConfig.Save(); - pattern = pattern.Replace("%NUM%", zeroPad(num.ToString(), 6)); - } - // Use the last as it "might" have some nasty strings in it. - pattern = pattern.Replace("%title%", MakeFilenameSafe(title)); + // do padding + if (padWidth >0) { + replaceValue = replaceValue.PadRight(padWidth, padChar); + } else if (padWidth < 0) { + replaceValue = replaceValue.PadLeft(-padWidth, padChar); + } + return replaceValue; + } + + /// + /// "Simply" fill the pattern with environment variables + /// + /// String with pattern ${var} + /// Filled string + public static string FillVariables(string pattern) { + IDictionary processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); + IDictionary userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); + IDictionary machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); + + return VAR_REGEXP.Replace(pattern, + new MatchEvaluator(delegate(Match m) { return MatchVarEvaluator(m, null, processVars, userVars, machineVars); }) + ); + } + + private static string FillPattern(string pattern, ICaptureDetails captureDetails) { + IDictionary processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); + IDictionary userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); + IDictionary machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); try { - // Use MakeFQFilenameSafe so people can still use path characters for the name - return MakeFQFilenameSafe(pattern); + return VAR_REGEXP.Replace(pattern, + new MatchEvaluator(delegate(Match m) { return MatchVarEvaluator(m, captureDetails, processVars, userVars, machineVars); }) + ); } catch (Exception e) { // adding additional data for bug tracking - e.Data.Add("title", title); - e.Data.Add("pattern", initialPattern); - e.Data.Add("filename", pattern); + e.Data.Add("title", captureDetails.Title); + e.Data.Add("pattern", pattern); throw e; } } - - private static string zeroPad(string input, int chars) { - while(input.Length < chars) input = "0" + input; - return input; - } } }