source: branches/eraser6/Eraser/Program.cs @ 750

Revision 750, 24.7 KB checked in by lowjoel, 6 years ago (diff)

-Create the RemoteExecutorClient? instance only when AddTask? is called; otherwise the instance is not used.
-Document the help action, and added documentation for the future schedule parameter to addtask

  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By:
6 *
7 * This file is part of Eraser.
8 *
9 * Eraser is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 *
18 * A copy of the GNU General Public License can be found at
19 * <http://www.gnu.org/licenses/>.
20 */
21
22using System;
23using System.Collections.Generic;
24using System.Windows.Forms;
25
26using Eraser.Manager;
27using Eraser.Util;
28using Microsoft.Win32;
29using System.IO;
30using System.Runtime.Serialization.Formatters.Binary;
31using System.Globalization;
32using System.Reflection;
33using System.Diagnostics;
34
35namespace Eraser
36{
37    static class Program
38    {
39        /// <summary>
40        /// The main entry point for the application.
41        /// </summary>
42        [STAThread]
43        static void Main(string[] commandLine)
44        {
45            //Trivial case: no command parameters
46            if (commandLine.Length == 0)
47                GUIMain(false);
48
49            //Determine if the sole parameter is --restart; if it is, start the GUI
50            //passing isRestart as true. Otherwise, we're a console application.
51            else if (commandLine.Length == 1)
52            {
53                if (commandLine[0] == "/restart" || commandLine[0] == "--restart")
54                {
55                    GUIMain(true);
56                }
57                else
58                {
59                    CommandMain(commandLine);
60                }
61            }
62
63            //The other trivial case: definitely a console application.
64            else
65                CommandMain(commandLine);
66        }
67
68        /// <summary>
69        /// Runs Eraser as a command-line application.
70        /// </summary>
71        /// <param name="commandLine">The command line parameters passed to Eraser.</param>
72        private static void CommandMain(string[] commandLine)
73        {
74            //True if the user specified a quiet command.
75            bool isQuiet = false;
76
77            try
78            {
79                CommandLineProgram program = new CommandLineProgram(commandLine);
80                isQuiet = program.Arguments.Quiet;
81
82                using (ManagerLibrary library = new ManagerLibrary(new Settings()))
83                    program.Run();
84            }
85            catch (Exception e)
86            {
87                Console.WriteLine(e.Message);
88            }
89            finally
90            {
91                //Flush the buffered output to the console
92                Console.Out.Flush();
93
94                //Don't ask for a key to press if the user specified Quiet
95                if (!isQuiet)
96                {
97                    Console.Write("\nPress any key to continue . . . ");
98                    Console.Out.Flush();
99                    Console.ReadLine();
100                }
101
102                KernelAPI.FreeConsole();
103            }
104        }
105
106        /// <summary>
107        /// Runs Eraser as a GUI application.
108        /// </summary>
109        /// <param name="isRestart">True if the program was passed the --restart
110        /// switch.</param>
111        private static void GUIMain(bool isRestart)
112        {
113            Application.EnableVisualStyles();
114            Application.SetCompatibleTextRenderingDefault(false);
115            Application.SafeTopLevelCaptionFormat = S._("Eraser");
116
117            using (ManagerLibrary library = new ManagerLibrary(new Settings()))
118            using (eraserClient = new RemoteExecutorServer())
119            {
120                //Set our UI language
121                EraserSettings settings = new EraserSettings();
122                System.Threading.Thread.CurrentThread.CurrentUICulture =
123                    new CultureInfo(settings.Language);
124
125                //Load the task list
126                if (settings.TaskList != null)
127                    using (MemoryStream stream = new MemoryStream(settings.TaskList))
128                        try
129                        {
130                            eraserClient.LoadTaskList(stream);
131                        }
132                        catch (Exception)
133                        {
134                            settings.TaskList = null;
135                            MessageBox.Show(S._("Could not load task list. All task entries have " +
136                                "been lost."), S._("Eraser"), MessageBoxButtons.OK,
137                                MessageBoxIcon.Error);
138                        }
139
140                //Create the main form
141                MainForm form = new MainForm();
142
143                //Run tasks which are meant to be run on restart
144                if (isRestart)
145                {
146                    eraserClient.QueueRestartTasks();
147                }
148
149                //Run the program
150                eraserClient.Run();
151                Application.Run(form);
152
153                //Save the task list
154                using (MemoryStream stream = new MemoryStream())
155                {
156                    eraserClient.SaveTaskList(stream);
157                    settings.TaskList = stream.ToArray();
158                }
159            }
160        }
161
162        /// <summary>
163        /// The global Executor instance.
164        /// </summary>
165        public static Executor eraserClient;
166
167        /// <summary>
168        /// Handles commands passed to the program
169        /// </summary>
170        /// <param name="arguments">The arguments to the command</param>
171        private delegate void CommandHandler(Dictionary<string, string> arguments);
172    }
173
174    class CommandLineProgram
175    {
176        #region Command Line parsing classes
177        /// <summary>
178        /// Manages a command line.
179        /// </summary>
180        public class CommandLine
181        {
182            /// <summary>
183            /// Constructor.
184            /// </summary>
185            /// <param name="cmdParams">The raw arguments passed to the program.</param>
186            public CommandLine(string[] cmdParams)
187            {
188                //Get the action.
189                if (cmdParams.Length < 1)
190                    throw new ArgumentException("An action must be specified.");
191                Action = cmdParams[0];
192
193                //Iterate over each argument, resolving them ourselves and letting
194                //subclasses resolve them if we don't know how to.
195                for (int i = 1; i != cmdParams.Length; ++i)
196                {
197                    if (IsParam(cmdParams[i], "quiet", "q"))
198                        Quiet = true;
199                    else if (!ResolveParameter(cmdParams[i]))
200                        throw new ArgumentException("Unknown argument: " + cmdParams[i]);
201                }
202            }
203
204            /// <summary>
205            /// Called when a parameter is not used by the current CommandLine object
206            /// for subclasses to handle their parameters.
207            /// </summary>
208            /// <param name="param">The parameter to resolve.</param>
209            /// <returns>Return true if the parameter was resolved and accepted.</returns>
210            virtual protected bool ResolveParameter(string param)
211            {
212                return false;
213            }
214
215            /// <summary>
216            /// Checks if the given <paramref name="parameter"/> refers to the
217            /// <paramref name="expectedParameter"/>, regardless of whether it is specified
218            /// with -, --, or /
219            /// </summary>
220            /// <param name="parameter">The parameter on the command line.</param>
221            /// <param name="expectedParameter">The parameter the program is looking for, without
222            /// the - or / prefix.</param>
223            /// <param name="shortParameter">The short parameter when used with a single hyphen,
224            /// without the - or / prefix.</param>
225            /// <returns>True if the parameter references the given expected parameter.</returns>
226            protected static bool IsParam(string parameter, string expectedParameter,
227                string shortParameter)
228            {
229                //Trivial case
230                if (parameter.Length < 1)
231                    return false;
232
233                //Extract the bits before the equal sign.
234                {
235                    int equalPos = parameter.IndexOf('=');
236                    if (equalPos != -1)
237                        parameter = parameter.Substring(0, equalPos);
238                }
239
240                //Get the first letter.
241                switch (parameter[0])
242                {
243                    case '-':
244                        //Can be a - or a --. Check for the second parameter
245                        if (parameter.Length < 2)
246                            //Nothing specified at the end... it's invalid.
247                            return false;
248
249                        if (parameter[1] == '-')
250                            return parameter.Substring(2) == expectedParameter;
251                        else if (shortParameter == null || shortParameter == string.Empty)
252                            return parameter.Substring(1) == expectedParameter;
253                        else
254                            return parameter.Substring(1) == shortParameter;
255                       
256                    case '/':
257                        //The / can be used with both long and short parameters.
258                        parameter = parameter.Substring(1);
259                        return parameter == expectedParameter || (
260                            shortParameter != null && shortParameter != string.Empty &&
261                            parameter == shortParameter
262                        );
263
264                    default:
265                        return false;
266                }
267            }
268
269            /// <summary>
270            /// Gets the list of subparameters of the parameter. Subparameters are text
271            /// after the first =, separated by commas.
272            /// </summary>
273            /// <param name="param">The subparameter text to parse.</param>
274            /// <returns>The list of subparameters in the parameter.</returns>
275            protected static List<KeyValuePair<string, string>> GetSubParameters(string param)
276            {
277                List<KeyValuePair<string, string>> result =
278                    new List<KeyValuePair<string, string>>();
279                int lastPos = 0;
280                int commaPos = (param += ',').IndexOf(',');
281
282                while (commaPos != -1)
283                {
284                    //Extract the current subparameter, and dissect the subparameter at
285                    //the first =.
286                    string subParam = param.Substring(lastPos, commaPos - lastPos);
287                    int equalPos = subParam.IndexOf('=');
288                    if (equalPos == -1)
289                        result.Add(new KeyValuePair<string, string>(subParam, null));
290                    else
291                        result.Add(new KeyValuePair<string, string>(subParam.Substring(0, equalPos),
292                            subParam.Substring(equalPos + 1)));
293
294                    //Find the next ,
295                    lastPos = ++commaPos;
296                    commaPos = param.IndexOf(',', commaPos);
297                }
298
299                return result;
300            }
301
302            /// <summary>
303            /// The action that the command line specifies.
304            /// </summary>
305            public string Action
306            {
307                get
308                {
309                    return action;
310                }
311                private set
312                {
313                    action = value;
314                }
315            }
316
317            /// <summary>
318            /// True if no console window should be created.
319            /// </summary>
320            public bool Quiet
321            {
322                get
323                {
324                    return quiet;
325                }
326                private set
327                {
328                    quiet = value;
329                }
330            }
331
332            private string action;
333            private bool quiet;
334        }
335
336        /// <summary>
337        /// Manages a command line for adding tasks to the global DirectExecutor
338        /// </summary>
339        class AddTaskCommandLine : CommandLine
340        {
341            /// <summary>
342            /// Constructor.
343            /// </summary>
344            /// <param name="cmdParams">The raw command line arguments passed to the program.</param>
345            public AddTaskCommandLine(string[] cmdParams)
346                : base(cmdParams)
347            {
348            }
349
350            protected override bool ResolveParameter(string param)
351            {
352                int equalPos = param.IndexOf('=');
353                if (IsParam(param, "method", "m"))
354                {
355                    if (equalPos == -1)
356                        throw new ArgumentException("--method must be specified with an Erasure " +
357                            "method GUID.");
358                    ErasureMethod = new Guid(param.Substring(equalPos + 1));
359                }
360                else if (IsParam(param, "recycled", "r"))
361                {
362                    targets.Add(new Task.RecycleBin());
363                }
364                else if (IsParam(param, "unused", "u"))
365                {
366                    if (equalPos == -1)
367                        throw new ArgumentException("--unused must be specified with the Volume " +
368                            "to erase.");
369
370                    //Create the UnusedSpace target for inclusion into the task.
371                    Task.UnusedSpace target = new Task.UnusedSpace();
372
373                    //Determine if cluster tips should be erased.
374                    target.EraseClusterTips = false;
375                    List<KeyValuePair<string, string>> subParams =
376                        GetSubParameters(param.Substring(equalPos + 1));
377                    foreach (KeyValuePair<string, string> kvp in subParams)
378                        if (kvp.Value == null && target.Drive == null)
379                            target.Drive = Path.GetFullPath(kvp.Key);
380                        else if (kvp.Key == "clusterTips")
381                            target.EraseClusterTips = true;
382                        else
383                            throw new ArgumentException("Unknown subparameter: " + kvp.Key);
384                    targets.Add(target);
385                }
386                else if (IsParam(param, "dir", "d") || IsParam(param, "directory", null))
387                {
388                    if (equalPos == -1)
389                        throw new ArgumentException("--directory must be specified with the " +
390                            "directory to erase.");
391
392                    //Create the base target
393                    Task.Folder target = new Task.Folder();
394
395                    //Parse the subparameters.
396                    List<KeyValuePair<string, string>> subParams =
397                        GetSubParameters(param.Substring(equalPos + 1));
398                    foreach (KeyValuePair<string, string> kvp in subParams)
399                        if (kvp.Value == null && target.Path == null)
400                            target.Path = Path.GetFullPath(kvp.Key);
401                        else if (kvp.Key == "excludeMask")
402                        {
403                            if (kvp.Value == null)
404                                throw new ArgumentException("The exclude mask must be specified " +
405                                    "if the excludeMask subparameter is specified");
406                            target.ExcludeMask = kvp.Value;
407                        }
408                        else if (kvp.Key == "includeMask")
409                        {
410                            if (kvp.Value == null)
411                                throw new ArgumentException("The include mask must be specified " +
412                                    "if the includeMask subparameter is specified");
413                            target.IncludeMask = kvp.Value;
414                        }
415                        else if (kvp.Key == "delete")
416                            target.DeleteIfEmpty = true;
417                        else
418                            throw new ArgumentException("Unknown subparameter: " + kvp.Key);
419
420                    //Add the target to the list of targets
421                    targets.Add(target);
422                }
423                else
424                {
425                    //It's just a file!
426                    Task.File target = new Task.File();
427                    target.Path = Path.GetFullPath(param);
428                    targets.Add(target);
429                }
430
431                return true;
432            }
433
434            /// <summary>
435            /// The erasure method which the user specified on the command line.
436            /// </summary>
437            public Guid ErasureMethod
438            {
439                get
440                {
441                    return erasureMethod;
442                }
443                private set
444                {
445                    erasureMethod = value;
446                }
447            }
448
449            /// <summary>
450            /// The list of targets which was specified on the command line.
451            /// </summary>
452            public List<Task.ErasureTarget> Targets
453            {
454                get
455                {
456                    return new List<Task.ErasureTarget>(targets.ToArray());
457                }
458                set
459                {
460                    targets = value;
461                }
462            }
463
464            private Guid erasureMethod;
465            private List<Task.ErasureTarget> targets = new List<Task.ErasureTarget>();
466        }
467        #endregion
468
469        /// <summary>
470        /// Constructor.
471        /// </summary>
472        /// <param name="cmdParams">The raw command line arguments passed to the program.</param>
473        public CommandLineProgram(string[] cmdParams)
474        {
475            try
476            {
477                //Parse the command line arguments.
478                if (cmdParams.Length < 1)
479                    throw new ArgumentException("An action must be specified.");
480
481                switch (cmdParams[0])
482                {
483                    case "addtask":
484                        Arguments = new AddTaskCommandLine(cmdParams);
485                        break;
486                    case "querymethods":
487                    case "help":
488                    default:
489                        Arguments = new CommandLine(cmdParams);
490                        break;
491                }
492
493                //If the user did not specify the quiet command line, then create the console.
494                if (!Arguments.Quiet)
495                    CreateConsole();
496
497                //Map actions to their handlers
498                actionHandlers.Add("addtask", AddTask);
499                actionHandlers.Add("querymethods", QueryMethods);
500                actionHandlers.Add("help", Help);
501            }
502            finally
503            {
504                if (Arguments == null || !Arguments.Quiet)
505                    CreateConsole();
506            }
507        }
508
509        /// <summary>
510        /// Runs the program, analogous to System.Windows.Forms.Application.Run.
511        /// </summary>
512        public void Run()
513        {
514            //Call the function handling the current command line.
515            actionHandlers[Arguments.Action]();
516        }
517
518        /// <summary>
519        /// Creates a console for our application, setting the input/output streams to the
520        /// defaults.
521        /// </summary>
522        private void CreateConsole()
523        {
524            if (KernelAPI.AllocConsole())
525            {
526                Console.SetOut(new StreamWriter(Console.OpenStandardOutput()));
527                Console.SetIn(new StreamReader(Console.OpenStandardInput()));
528            }
529        }
530
531        /// <summary>
532        /// Prints the command line help for Eraser.
533        /// </summary>
534        private static void CommandUsage()
535        {
536            Console.WriteLine(@"usage: Eraser <action> <arguments>
537where action is
538    help                    Show this help message.
539    addtask                 Adds tasks to the current task list.
540    querymethods            Lists all registered Erasure methods.
541
542global parameters:
543    --quiet, -q             Do not create a Console window to display progress.
544
545parameters for help:
546    eraser help
547
548    no parameters to set.
549
550parameters for addtask:
551    eraser addtask [--method=<methodGUID>] [--schedule=(now|restart)] (--recycled " +
552@"| --unused=<volume> | --dir=<directory> | [file1 [file2 [...]]])
553
554    --method, -m            The Erasure method to use.
555    --schedule, -s          The schedule the task will follow. The value must
556                            be one of:
557            now             The task will be queued for immediate execution.
558            restart         The task will be queued for execution when the
559                            computer is next restarted.
560    --recycled, -r          Erases files and folders in the recycle bin
561    --unused, -u            Erases unused space in the volume.
562        optional arguments: --unused=<drive>[,clusterTips]
563            clusterTips     If specified, the drive's files will have their
564                            cluster tips erased.
565    --dir, --directory, -d  Erases files and folders in the directory
566        optional arguments: --dir=<directory>[,e=excludeMask][,i=includeMask][,delete]
567            excludeMask     A wildcard expression for files and folders to
568                            exclude.
569            includeMask     A wildcard expression for files and folders to
570                            include.
571                            The include mask is applied before the exclude
572                            mask.
573            delete          Deletes the folder at the end of the erasure if
574                            specified.
575    file1 ... fileN         The list of files to erase.
576
577parameters for querymethods:
578    eraser querymethods
579
580    no parameters to set.
581
582All arguments are case sensitive.");
583            Console.Out.Flush();
584        }
585
586        #region Action Handlers
587        /// <summary>
588        /// The command line arguments passed to the program.
589        /// </summary>
590        public CommandLine Arguments
591        {
592            get
593            {
594                return arguments;
595            }
596            private set
597            {
598                arguments = value;
599            }
600        }
601
602        /// <summary>
603        /// Prints the help text for Eraser (with copyright)
604        /// </summary>
605        private void Help()
606        {
607            Console.WriteLine(@"Eraser {0}
608(c) 2008 The Eraser Project
609Eraser is Open-Source Software: see http://eraser.heidi.ie/ for details.
610", Assembly.GetExecutingAssembly().GetName().Version);
611
612            Console.Out.Flush();
613            CommandUsage();
614        }
615
616        /// <summary>
617        /// Lists all registered erasure methods.
618        /// </summary>
619        /// <param name="commandLine">The command line parameters passed to the program.</param>
620        private void QueryMethods()
621        {
622            //Output the header
623            const string methodFormat = "{0,-2} {1,-39} {2}";
624            Console.WriteLine(methodFormat, "", "Method", "GUID");
625            Console.WriteLine(new string('-', 79));
626
627            //Refresh the list of erasure methods
628            Dictionary<Guid, ErasureMethod> methods = ErasureMethodManager.GetAll();
629            foreach (ErasureMethod method in methods.Values)
630            {
631                Console.WriteLine(methodFormat, (method is UnusedSpaceErasureMethod) ?
632                    "U" : "", method.Name, method.GUID.ToString());
633            }
634        }
635
636        /// <summary>
637        /// Parses the command line for tasks and adds them using the
638        /// <see cref="RemoteExecutor"/> class.
639        /// </summary>
640        /// <param name="commandLine">The command line parameters passed to the program.</param>
641        private void AddTask()
642        {
643            AddTaskCommandLine arguments = (AddTaskCommandLine)Arguments;
644           
645            //Create the task, and set the method to use.
646            Task task = new Task();
647            ErasureMethod method = arguments.ErasureMethod == Guid.Empty ? 
648                ErasureMethodManager.Default :
649                ErasureMethodManager.GetInstance(arguments.ErasureMethod);
650            foreach (Task.ErasureTarget target in arguments.Targets)
651            {
652                target.Method = method;
653                task.Targets.Add(target);
654            }
655
656            //Send the task out.
657            using (Program.eraserClient = new RemoteExecutorClient())
658            {
659                if (!((RemoteExecutorClient)Program.eraserClient).Connect())
660                {
661                    //The client cannot connect to the server. This probably means
662                    //that the server process isn't running. Start an instance.
663                    Process eraserInstance = Process.Start(
664                        Assembly.GetExecutingAssembly().Location);
665                    eraserInstance.WaitForInputIdle();
666
667                    if (!((RemoteExecutorClient)Program.eraserClient).Connect())
668                        throw new Exception("Eraser cannot connect to the running " +
669                            "instance for erasures.");
670                }
671
672                Program.eraserClient.Run();
673                Program.eraserClient.AddTask(ref task);
674            }
675        }
676        #endregion
677
678        /// <see cref="Arguments"/>
679        private CommandLine arguments;
680
681        /// <summary>
682        /// The prototype of an action handler in the class which executes an
683        /// action as specified in the command line.
684        /// </summary>
685        private delegate void ActionHandler();
686
687        /// <summary>
688        /// Matches an action handler to a function in the class.
689        /// </summary>
690        private Dictionary<string, ActionHandler> actionHandlers =
691            new Dictionary<string, ActionHandler>();
692    }
693
694    internal class Settings : Manager.SettingsManager
695    {
696        /// <summary>
697        /// Registry-based storage backing for the Settings class.
698        /// </summary>
699        private class RegistrySettings : Manager.Settings
700        {
701            /// <summary>
702            /// Constructor.
703            /// </summary>
704            /// <param name="key">The registry key to look for the settings in.</param>
705            public RegistrySettings(Guid pluginID, RegistryKey key)
706            {
707                this.key = key;
708            }
709
710            public override object this[string setting]
711            {
712                get
713                {
714                    byte[] currentSetting = (byte[])key.GetValue(setting, null);
715                    if (currentSetting != null && currentSetting.Length != 0)
716                        using (MemoryStream stream = new MemoryStream(currentSetting))
717                            try
718                            {
719                                return new BinaryFormatter().Deserialize(stream);
720                            }
721                            catch (Exception)
722                            {
723                                key.DeleteValue(setting);
724                                MessageBox.Show(S._("Could not load the setting {0} for plugin {1}. " +
725                                    "The setting has been lost.", key, pluginID.ToString()),
726                                    S._("Eraser"), MessageBoxButtons.OK, MessageBoxIcon.Error);
727                            }
728
729                    return null;
730                }
731                set
732                {
733                    if (value == null)
734                    {
735                        key.DeleteValue(setting);
736                    }
737                    else
738                    {
739                        using (MemoryStream stream = new MemoryStream())
740                        {
741                            new BinaryFormatter().Serialize(stream, value);
742                            key.SetValue(setting, stream.ToArray(), RegistryValueKind.Binary);
743                        }
744                    }
745                }
746            }
747
748            /// <summary>
749            /// The GUID of the plugin whose settings this object is storing.
750            /// </summary>
751            private Guid pluginID;
752
753            /// <summary>
754            /// The registry key where the data is stored.
755            /// </summary>
756            private RegistryKey key;
757        }
758
759        public override void Save()
760        {
761        }
762
763        protected override Manager.Settings GetSettings(Guid guid)
764        {
765            //Open the registry key containing the settings
766            const string eraserKeyPath = @"SOFTWARE\Eraser\Eraser 6";
767            RegistryKey eraserKey = Registry.CurrentUser.OpenSubKey(eraserKeyPath, true);
768            if (eraserKey == null)
769                eraserKey = Registry.CurrentUser.CreateSubKey(eraserKeyPath);
770
771            RegistryKey pluginsKey = eraserKey.OpenSubKey(guid.ToString(), true);
772            if (pluginsKey == null)
773                pluginsKey = eraserKey.CreateSubKey(guid.ToString());
774
775            //Return the Settings object.
776            return new RegistrySettings(guid, pluginsKey);
777        }
778    }
779
780    internal class EraserSettings
781    {
782        public EraserSettings()
783        {
784            settings = Manager.ManagerLibrary.Instance.SettingsManager.ModuleSettings;
785        }
786
787        /// <summary>
788        /// Gets or sets the task list, serialised in binary form by the Manager assembly.
789        /// </summary>
790        public byte[] TaskList
791        {
792            get
793            {
794                return (byte[])settings["TaskList"];
795            }
796            set
797            {
798                settings["TaskList"] = value;
799            }
800        }
801
802        /// <summary>
803        /// Gets or sets the LCID of the language which the UI should be displayed in.
804        /// </summary>
805        public string Language
806        {
807            get
808            {
809                return settings["Language"] == null ? 
810                    GetCurrentCulture().Name :
811                    (string)settings["Language"];
812            }
813            set
814            {
815                settings["Language"] = value;
816            }
817        }
818
819        /// <summary>
820        /// Gets or sets whether the Shell Extension should be loaded into Explorer.
821        /// </summary>
822        public bool IntegrateWithShell
823        {
824            get
825            {
826                return settings["IntegrateWithShell"] == null ?
827                    true : (bool)settings["IntegrateWithShell"];
828            }
829            set
830            {
831                settings["IntegrateWithShell"] = value;
832            }
833        }
834
835        /// <summary>
836        /// Gets or sets a value on whether the main frame should be minimised to the
837        /// system notification area.
838        /// </summary>
839        public bool HideWhenMinimised
840        {
841            get
842            {
843                return settings["HideWhenMinimised"] == null ?
844                    true : (bool)settings["HideWhenMinimised"];
845            }
846            set
847            {
848                settings["HideWhenMinimised"] = value;
849            }
850        }
851
852        /// <summary>
853        /// Gets the current UI culture, correct to the top-level culture (i.e., English
854        /// instead of English (United Kingdom))
855        /// </summary>
856        /// <returns>The CultureInfo of the current UI culture, correct to the top level.</returns>
857        private static CultureInfo GetCurrentCulture()
858        {
859            CultureInfo culture = CultureInfo.CurrentUICulture;
860            while (culture.Parent != CultureInfo.InvariantCulture)
861                culture = culture.Parent;
862
863            return culture;
864        }
865
866        private Manager.Settings settings;
867    }
868}
Note: See TracBrowser for help on using the repository browser.