PageRenderTime 53ms CodeModel.GetById 2ms app.highlight 40ms RepoModel.GetById 1ms app.codeStats 0ms

/RPS 4/Config.cs

http://github.com/marijnkampf/Visual-C---Random-Photo-Screensaver
C# | 1120 lines | 942 code | 84 blank | 94 comment | 191 complexity | c338654b862653d1a0eeeff7e77c1bcc MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1using System;
   2using System.Collections.Generic;
   3using System.ComponentModel;
   4using System.Data;
   5using System.Drawing;
   6using System.Text;
   7using System.Threading.Tasks;
   8using System.Threading;
   9using System.Windows.Forms;
  10using System.Diagnostics;
  11using System.Security.Permissions;
  12using System.Configuration;
  13using System.IO;
  14using System.Data.SQLite;
  15//using System.Data.SQLite.Linq;
  16using System.Data.Linq;
  17using System.Linq;
  18using System.Data.Linq.Mapping;
  19using System.Collections;
  20//using System.DirectoryServices;
  21//using System.Management;
  22using Newtonsoft.Json;
  23using Microsoft.Win32;
  24using System.Net;
  25/***
  26 * 
  27 * TODO: Reflect changes made in config.html into this.persistant!!!
  28 * 
  29 * 
  30 * 
  31 * 
  32 * Consider optimising by storing all values from html in c# array?
  33 * this.folders: takes 0.0002ms - 0.0005ms
  34 * this.browser.Document.GetElementById(id).InnerHtml takes 55.1357ms first request and 0.2303ms - 0.3389ms consequtive requests
  35 * 
  36 ***/
  37
  38namespace RPS {
  39    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
  40    [System.Runtime.InteropServices.ComVisibleAttribute(true)]
  41
  42    public partial class Config : Form {
  43
  44        public enum Order { Random = 1, Sequential = 0 };
  45
  46        private bool configInitialised = false;
  47
  48        private Dictionary<string, object> persistant;
  49        DBConnector dbConnector;
  50        //SQLiteConnection connection;
  51
  52        private Screensaver screensaver;
  53
  54        private Dictionary<string, object> trackChanges = new Dictionary<string, object>() {
  55           {"folders", null},
  56           {"excludedSubfolders", null},
  57           {"excludeAllSubfolders", null},
  58           {"ignoreHiddenFiles", null},
  59           {"ignoreHiddenFolders", null},
  60           {"imageExtensions", null},
  61           {"videoExtensions", null},
  62           {"rawExtensions", null},
  63        };
  64
  65        public long maxMonitorDimension = 0;
  66
  67        public jsonFolder effects;
  68
  69        private bool checkUpdates = false;
  70        private bool downloadUpdates = false;
  71        private bool newVersionAvailable = false;
  72
  73        private Stopwatch downloadProgress = new Stopwatch();
  74        //private bool installUpdates = false;
  75
  76        //public WebBrowser browser;
  77
  78        //private delegate void AddBrowser();
  79
  80        public Config(Screensaver screensaver) {
  81            this.screensaver = screensaver;
  82            this.InitializeComponent();
  83            this.browser.ObjectForScripting = this;
  84            this.browser.AllowWebBrowserDrop = false;
  85            foreach (Screen screen in Screen.AllScreens) {
  86                this.maxMonitorDimension = Math.Max(Math.Max(this.maxMonitorDimension, screen.Bounds.Width), screen.Bounds.Height);
  87            }
  88        }
  89
  90        public SQLiteConnection connectToDB() {
  91            this.dbConnector = new DBConnector(Constants.selectProgramAppDataFolder(Constants.PersistantConfigFileName), Constants.SettingsDefinition, false);
  92            //return new SQLiteConnection("Data Source=" + path + ";Version=3;");
  93            return this.dbConnector.connection;
  94        }
  95
  96        public void saveDebug() {
  97            string path = this.browser.Url.LocalPath.Replace(Constants.ConfigHtmlFile, "_C_" + DateTime.Now.ToString("yyyyMMddhhmmss") + ".html");
  98            File.WriteAllText(path, this.browser.Document.GetElementsByTagName("HTML")[0].OuterHtml);
  99        }
 100
 101        public string jsFileBrowserDialog(string filename, string filter) {
 102            OpenFileDialog dialog = new System.Windows.Forms.OpenFileDialog();
 103            if (filename == null) filename = "";
 104            else dialog.InitialDirectory = Path.GetFullPath(filename);
 105            dialog.FileName = Path.GetFileName(filename);
 106            if (filter != null && filter.Length > 0) {
 107                dialog.Filter = filter;
 108            }
 109            if (dialog.ShowDialog() == DialogResult.OK) {
 110                return dialog.FileName;
 111            } else {
 112                return filename;
 113            }
 114        }
 115
 116
 117        public string jsFolderBrowserDialog(string path) {
 118            FolderBrowserDialog dialog = new System.Windows.Forms.FolderBrowserDialog();
 119            dialog.SelectedPath = path;
 120            if (dialog.ShowDialog() == DialogResult.OK) {
 121                return dialog.SelectedPath;
 122            } else {
 123                return path;
 124            }
 125        }
 126
 127        public string jsRawConverterAvailable(string path) {
 128            if (File.Exists(path)) return "true";
 129            else return "false";
 130        }
 131
 132        public string jsGetUFRawLocation() {
 133            string path = (string) Registry.GetValue("HKEY_CURRENT_USER\\Software\\Microsoft\\IntelliPoint\\AppSpecific\\ufraw.exe", "Path", null);
 134            path = path.Replace("ufraw.exe", "ufraw-batch.exe");
 135            if (path != null && path.Length > 0) {
 136                if (File.Exists(path)) {
 137                    return path;
 138                }
 139            }
 140            return null;
 141        }
 142
 143        public void jsInputChanged(string id, string value) {
 144            this.setPersistant(id, value, false);
 145        }
 146
 147        public void jsSetSelectedEffects(string jsonEffects) {
 148            this.effects = JsonConvert.DeserializeObject<jsonFolder>(jsonEffects);
 149            this.persistant["effects"] = jsonEffects;
 150        }
 151
 152        public void jsOpenExternalLink(string href) {
 153            Utils.RunTaskScheduler("OpenURL", "explorer.exe", "\"" + href + "\"");
 154        }
 155
 156        public string jsGetSelectedEffects() {
 157            return JsonConvert.SerializeObject(this.effects);
 158        }
 159
 160        public string jsGetFilters() {
 161            try {
 162                return this.getPersistantString("filters");
 163            } catch(System.Collections.Generic.KeyNotFoundException e) {
 164                return null;
 165            }
 166        }
 167
 168        public string jsGetFilterColumns() {
 169            Dictionary<string, ColumnInfo> columns;
 170            columns = Constants.FileNodesDefinition.columns.Union(Constants.MetadataDefinition.columns)
 171                .ToLookup(pair => pair.Key, pair => pair.Value)
 172                .ToDictionary(group => group.Key, group => group.First());
 173            return JsonConvert.SerializeObject(columns/*, Newtonsoft.Json.Formatting.Indented*/);
 174        }
 175
 176        public void jsOpenProgramAppDataFolder() {
 177            if (Utils.RunTaskScheduler(@"OpenInExplorer", "explorer.exe", "\"" + Constants.selectProgramAppDataFolder("") + "\"")) {
 178                //this.monitors[i].showInfoOnMonitor("Opened in Explorer Window", false, true);
 179            }
 180        }
 181
 182        public void setBrowserBodyClasses(WebBrowser browser, Screensaver.Actions action) {
 183            setBrowserBodyClasses(browser, action, null);
 184        }
 185
 186        public static void setBrowserBodyClasses(WebBrowser browser, Screensaver.Actions action, string classes) {
 187            HtmlElementCollection elems = browser.Document.GetElementsByTagName("body");
 188            foreach (HtmlElement elem in elems) {
 189                switch (action) {
 190                    case Screensaver.Actions.Preview: classes += " preview"; break;
 191                    case Screensaver.Actions.Config: classes += " config"; break;
 192                    case Screensaver.Actions.Screensaver: classes += " screensaver"; break;
 193                    case Screensaver.Actions.Test: classes += " test"; break;
 194                    case Screensaver.Actions.Slideshow: classes += " slideshow"; break;
 195                }
 196                classes += " IE" + browser.Version.Major;
 197                if (browser.Version.Major < 8) classes += " lowIE";
 198                elem.SetAttribute("className", elem.GetAttribute("className") + classes);
 199            }
 200        }
 201
 202        public void loadPersistantConfig() {
 203            if (this.screensaver.monitors != null) this.loadPersistantConfig(this.screensaver.monitors.Length);
 204            else this.loadPersistantConfig(Screen.AllScreens.Length);
 205        }
 206
 207        public void loadPersistantConfig(int nrMonitors) {
 208            #if (DEBUG)
 209                this.screensaver.debugLog.Add("loadPersistantConfig(" + nrMonitors + ")");
 210            #endif
 211
 212            //SQLiteConnection connection = 
 213            this.connectToDB();
 214            this.persistant = new Dictionary<string, object>();
 215
 216            DataContext context = new DataContext(this.dbConnector.connection);
 217            var items = context.GetTable<Setting>();
 218            foreach(Setting item in items) {
 219                this.persistant.Add(item.Key, item.Value);
 220            }
 221            if (!this.persistant.ContainsKey("filterNrLines")) this.persistant["filterNrLines"] = 0;
 222
 223            object regvalue = Registry.GetValue("HKEY_CURRENT_USER\\" + Constants.regkeyGPURendering, Constants.regkeyExecutable, 0);
 224            bool gpuRendering = (regvalue != null && (int)regvalue == 1);
 225            if (this.persistant.ContainsKey("gpuRendering")) this.persistant["gpuRendering"] = gpuRendering;
 226            else this.persistant.Add("gpuRendering", gpuRendering);
 227            
 228            //this.browser.Document.InvokeScript("initMonitorsAndFilterCount", new string[] { Convert.ToString(Screen.AllScreens.Length), Convert.ToString(this.persistant["filterNrLines"]) });
 229            this.browser.Document.InvokeScript("initMonitors", new string[] { Convert.ToString(Screen.AllScreens.Length) });
 230            
 231            if (!this.persistant.ContainsKey("folders") || this.persistant["folders"] == null || this.getPersistantString("folders").Trim().Length == 0) { 
 232                string path = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures) + Environment.NewLine + 
 233                                                        Environment.GetFolderPath(Environment.SpecialFolder.MyVideos);
 234                if (!this.persistant.ContainsKey("folders")) {
 235                    this.persistant.Add("folders", path);
 236                } else {
 237                    this.persistant["folders"] = path;
 238                }
 239            }
 240
 241            if (!this.persistant.ContainsKey("rawFolder") || this.persistant["rawFolder"] == null || Convert.ToString(this.persistant["rawFolder"]).Trim().Length == 0) {
 242                string path = Path.Combine(
 243                    Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), 
 244                    AppSettings.Name,
 245                    Constants.RawCacheFolder
 246                );
 247                    
 248                if (!this.persistant.ContainsKey("rawFolder")) {
 249                    this.persistant.Add("rawFolder", path);
 250                } else {
 251                    this.persistant["rawFolder"] = path;
 252                }
 253            }
 254
 255            if (this.persistant.ContainsKey("effects") && this.persistant["effects"] != null && Convert.ToString(this.persistant["effects"]) != "null" && Convert.ToString(this.persistant["effects"]).Trim().Length > 0) {
 256                this.effects = JsonConvert.DeserializeObject<jsonFolder>(Convert.ToString(this.persistant["effects"]));
 257            } else {
 258                this.effects = new jsonFolder();
 259            }
 260            string jsonPath = Constants.getDataFolder(Constants.EffectsJsonFile);
 261            if (File.Exists(jsonPath)) {
 262                //this.effects = new jsonFolder();
 263                JsonSerializer serializer = new JsonSerializer();
 264                serializer.NullValueHandling = NullValueHandling.Ignore;
 265                using (StreamReader sr = new StreamReader(jsonPath))
 266                using (JsonReader reader = new JsonTextReader(sr)) {
 267                    jsonFolder newEffects = serializer.Deserialize<jsonFolder>(reader);
 268                    this.effects.mergeChildren(newEffects);
 269                }
 270            }
 271
 272            HtmlElementCollection hec = this.GetElementsByTagName("input");
 273            foreach (HtmlElement e in hec) {
 274                if (this.persistant.ContainsKey(e.GetAttribute("id")) || (e.GetAttribute("type") == "radio" && this.persistant.ContainsKey(e.GetAttribute("name")))) {
 275                    switch (e.GetAttribute("type")) {
 276                        case "checkbox":
 277                            if (this.getPersistantBool(e.GetAttribute("id")) == true) {
 278                                e.SetAttribute("checked", "true");
 279                            } else {
 280                                e.SetAttribute("checked", "");
 281                            }
 282                            break;
 283                        case "radio":
 284                            if (this.getPersistantString(e.GetAttribute("name")) == e.GetAttribute("value")) {
 285                                e.SetAttribute("checked", "true");
 286                            }
 287                            break;
 288                        default:
 289                            e.SetAttribute("value", this.getPersistantString(e.GetAttribute("id")));
 290                            break;
 291                    }
 292                } else {
 293                    switch (e.GetAttribute("type")) {
 294                        case "checkbox":
 295                            this.persistant[e.GetAttribute("id")] =  this.getDomCheckboxValue(e.GetAttribute("id"));
 296                        break;
 297                        case "radio":
 298                            this.persistant[e.GetAttribute("name")] =  this.getDomRadioValue(e.GetAttribute("name"));
 299                        break;
 300                        default:
 301                            this.persistant[e.GetAttribute("id")] =  this.getDomValue(e.GetAttribute("id"));
 302                        break;
 303                    }
 304                    
 305                    // Set persistant value with default
 306                }
 307            }
 308
 309            hec = this.browser.Document.GetElementsByTagName("textarea");
 310            foreach (HtmlElement e in hec) {
 311                if (this.persistant.ContainsKey(e.GetAttribute("id"))) {
 312                    e.SetAttribute("value", Utils.HtmlDecode(Convert.ToString(this.persistant[e.GetAttribute("id")])));
 313                } else {
 314                    this.persistant[e.GetAttribute("id")] = Utils.HtmlDecode(this.getDomValue(e.GetAttribute("id")));
 315                }
 316            }
 317
 318            hec = this.browser.Document.GetElementsByTagName("select");
 319            foreach (HtmlElement e in hec) {
 320                if (this.persistant.ContainsKey(e.GetAttribute("id"))) {
 321                    e.SetAttribute("value", Convert.ToString(this.persistant[e.GetAttribute("id")]));
 322                } else {
 323                    this.persistant[e.GetAttribute("id")] = this.getDomValue(e.GetAttribute("id"));
 324                }
 325            }
 326
 327            string classes = null;
 328            if (nrMonitors > 1) classes += "multi ";
 329            if (this.screensaver.readOnly) classes += "readonly ";
 330
 331            Config.setBrowserBodyClasses(this.browser, this.screensaver.action, classes);
 332
 333            this.browser.Document.InvokeScript("persistantConfigLoaded", new string[] { Convert.ToString(Screen.AllScreens.Length) });
 334
 335            if (this.screensaver.action == Screensaver.Actions.Preview && this.screensaver.monitors != null) {
 336                this.screensaver.monitors[0].defaultShowHide();
 337            }
 338
 339        }
 340
 341        public string jsonAllPersistant() {
 342            if (this.persistant != null) {
 343                return JsonConvert.SerializeObject(this.persistant, Newtonsoft.Json.Formatting.Indented);
 344            }
 345            return null;
 346        }
 347
 348        public bool savePersistantConfig() {
 349            if (this.persistant != null) {
 350                this.persistant["effects"] = JsonConvert.SerializeObject(this.effects);
 351                this.persistant["filters"] = Convert.ToString(this.browser.Document.InvokeScript("getJsonFilters"));
 352                if (this.screensaver.action != Screensaver.Actions.Config) {
 353                    for (int i = 0; i < this.screensaver.monitors.Length; i++) {
 354                        this.persistant["historyM" + Convert.ToString(i)] = JsonConvert.SerializeObject(this.screensaver.monitors[i].historyLastEntries(Convert.ToInt32(this.getPersistant("rememberLast"))));
 355                        this.persistant["historyOffsetM" + Convert.ToString(i)] = Convert.ToString(this.screensaver.monitors[i].offset);
 356                    }
 357                }
 358
 359                this.connectToDB();
 360                SQLiteTransaction transaction = null;
 361                try {
 362                    transaction = this.dbConnector.connection.BeginTransaction(true);
 363                } catch (System.Data.SQLite.SQLiteException se) {
 364                    this.screensaver.showInfoOnMonitors("Error: " + se.Message, true);
 365                    return false;
 366                }
 367                foreach (var p in this.persistant) {
 368                    SQLiteCommand insertSQL = new SQLiteCommand("INSERT OR REPLACE INTO Setting (key, value) VALUES (@key, @value);", this.dbConnector.connection);
 369                    insertSQL.Parameters.AddWithValue("@key", p.Key);
 370                    insertSQL.Parameters.AddWithValue("@value", p.Value);
 371                    insertSQL.ExecuteNonQuery();
 372                }
 373                transaction.Commit();
 374            }
 375            return true;
 376        }
 377 
 378        public void Message(string Text) {
 379            MessageBox.Show(Text);
 380        }
 381
 382        public HtmlElementCollection GetElementsByTagName(string name) {
 383            return (HtmlElementCollection)this.browser.Invoke(new Func<HtmlElementCollection>(() => this.browser.Document.GetElementsByTagName(name)));
 384        }
 385
 386        /****
 387         * Called from config.js
 388         ****/
 389        public void jsApplyFilter(string filter) {
 390            if (this.screensaver.fileNodes != null) {
 391                try { 
 392                    this.screensaver.fileNodes.setFilterSQL(filter);
 393                } catch (System.Data.SQLite.SQLiteException e) {
 394                    this.clearFilter();
 395                    this.setDomValue("useFilter", "false");
 396                    MessageBox.Show(e.Message + Environment.NewLine + "Correct fault and re-apply filter", "Filter fault", MessageBoxButtons.OK, MessageBoxIcon.Error);
 397                }
 398            }
 399        }
 400
 401        public void jsClearFilter(string jsDummy) {
 402            this.clearFilter();
 403            this.setDomValue("useFilter", "false");
 404        }
 405
 406        public void clearFilter() {
 407            if (this.screensaver.fileNodes != null) this.screensaver.fileNodes.clearFilter();
 408        }
 409
 410        public bool resetWallpaper() {
 411            Wallpaper wallpaper = new Wallpaper(this.screensaver);
 412            wallpaper.resetDefaultWallpaper();
 413            return true;
 414        }
 415
 416        public bool jsSetGPURendering() {
 417            if (this.getPersistantBool("gpuRendering")) {
 418                Registry.SetValue("HKEY_CURRENT_USER\\" + Constants.regkeyGPURendering, Constants.regkeyExecutable, 1, RegistryValueKind.DWord);
 419                Registry.SetValue("HKEY_CURRENT_USER\\" + Constants.regkeyGPURendering, Constants.regkeyLauncher, 1, RegistryValueKind.DWord);
 420            } else {
 421                RegistryKey regKey = Registry.CurrentUser.OpenSubKey(Constants.regkeyGPURendering, true);
 422                if (regKey != null) {
 423                    regKey.DeleteValue(Constants.regkeyExecutable, false);
 424                    regKey.DeleteValue(Constants.regkeyLauncher, false);
 425
 426                }
 427            }
 428            return false;
 429        }
 430
 431        /****
 432         * Called from config.js
 433         * dumdum variable is used to avoid calling the function when testing with
 434         * if (typeof(window.external.getInitialFoldersJSON) !== "undefined") in JavaScript
 435         ****/
 436        public string getInitialFoldersJSON(bool dumdum) {
 437            List<jsonFolder> folders = new List<jsonFolder>();
 438            //MessageBox.Show("getInitialFoldersJSON()");
 439            //            folders.Add(new jsonFolder());
 440            //          folders.Add(new jsonFolder(Environment.GetFolderPath(Environment.SpecialFolder.MyVideos)));
 441            /*
 442                        jsonFolder network = new jsonFolder("Network");
 443                        network.key = "\\";
 444                        folders.Add(network);
 445                        DirectoryEntry root = new DirectoryEntry("WinNT:");
 446                        foreach (DirectoryEntry networkComputers in root.Children) {
 447                            foreach (DirectoryEntry networkComputer in networkComputers.Children) {
 448                                if (networkComputer.Name != "Schema") {
 449                                    jsonFolder networked = new jsonFolder(networkComputer.Name);
 450                                    networked.lazy = true;
 451                                    network.children.Add(networked);
 452
 453                                    try {
 454                                        ManagementObjectSearcher searcher =
 455                                            new ManagementObjectSearcher("root\\CIMV2",
 456                                            "SELECT * FROM Win32_Share");
 457
 458                                        foreach (ManagementObject queryObj in searcher.Get()) {
 459                                            Debug.WriteLine("-----------------------------------");
 460                                            Debug.WriteLine("Win32_Share instance");
 461                                            Debug.WriteLine("-----------------------------------");
 462                                            Debug.WriteLine("Name: {0}", queryObj["Name"]);
 463                                        }
 464                                    } catch (ManagementException e) {
 465                                        MessageBox.Show("An error occurred while querying for WMI data: " + e.Message);
 466                                    }
 467                                    //textBox1.Text += computer.Name + "\r\n";
 468                                }
 469                            }
 470                        }
 471                        */
 472            jsonFolder computer = new jsonFolder("Computer");
 473            computer.expanded = true;
 474            folders.Add(computer);
 475            DriveInfo[] info = DriveInfo.GetDrives();
 476
 477            foreach (DriveInfo di in info) {
 478                string drive = "(" + di.Name.Replace("\\", "") + ")";
 479                jsonFolder f = new jsonFolder(drive);
 480                f.lazy = true;
 481                f.key = di.Name;
 482
 483                string extraInfo = "";
 484                if (di.IsReady) {
 485                    extraInfo += di.VolumeLabel + " ";
 486                } else {
 487                    f.unselectable = true;
 488                    f.extraClasses = "dim";
 489                }
 490                switch (di.DriveType) {
 491                    case DriveType.Removable:
 492                        if (extraInfo == "") extraInfo += "Removable Disk ";
 493                        break;
 494                }
 495                if (extraInfo != "") f.title = extraInfo + f.title;
 496                computer.children.Add(f);
 497            }
 498
 499            if (this.persistant == null || this.getPersistant("folders") == null) {
 500                this.loadPersistantConfig();
 501            }
 502
 503            foreach (string folder in Convert.ToString(this.getPersistant("folders")).Split(new string[] { Environment.NewLine, "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries)) {
 504                if (folder.Substring(0, 2) == "\\\\") {
 505                    string[] parts = folder.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries);
 506                    int i = 0;
 507                    jsonFolder network = new jsonFolder("Network");
 508                    folders.Add(network);
 509                    jsonFolder node = network;
 510                    while (i < parts.Length) {
 511                        jsonFolder newNode = new jsonFolder(parts[i]);
 512                        node.children.Add(newNode);
 513                        i++;
 514                        if (i == parts.Length) {
 515                            newNode.selected = true;
 516                            jsonFolder dummy = new jsonFolder("dummy");
 517                            dummy.selected = false;
 518                            //dummy.unselectable = false;
 519                            dummy.extraClasses = "hidden";
 520                            node.children.Add(dummy);
 521                        }
 522                        node = newNode;
 523                    }
 524                } else {
 525                    jsonFolder node = computer;
 526                    string basePath = "";
 527                    string[] parts = folder.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries);
 528
 529                    int i = 0;
 530                    while (i < parts.Length) {
 531                        string key = parts[i].ToLower();
 532                        if (key.IndexOf(':') > -1) key = key.ToUpper() + "\\";
 533                        jsonFolder newNode = node.hasChild(key);
 534
 535                        if (newNode == null) {
 536                            // Add children if not found
 537                            node.children.AddRange(this.getFolder(basePath));
 538                            node = node.hasChild(key);
 539                            if (node == null) break; // Escape while loop if still not found
 540                        } else {
 541                            node = newNode;
 542                        }
 543                        //node.expanded = true;
 544                        node.selected = true;
 545                        basePath += parts[i] + "\\";
 546                        i++;
 547                    }
 548                    if (node != null) node.selected = true;
 549                }
 550            }
 551            return JsonConvert.SerializeObject(folders);
 552
 553        }
 554
 555        public List<jsonFolder> getFolder(string folder) {
 556            List<jsonFolder> children = new List<jsonFolder>();
 557            if (!Directory.Exists(folder)) return children;
 558            string[] dirs = Directory.GetDirectories(folder);
 559            foreach (string dir in dirs) {
 560                try {
 561                    FileInfo fi = new FileInfo(dir);
 562                    if ((fi.Attributes & FileAttributes.Hidden) != FileAttributes.Hidden) {
 563                        jsonFolder d = new jsonFolder(fi.Name.ToLower());
 564                        d.lazy = (Directory.GetDirectories(dir).Length > 0);
 565                        children.Add(d);
 566                    }
 567                } catch (Exception e) {
 568                    Debug.WriteLine("getFolder " + e.Message);
 569                    // No access
 570                }
 571            }
 572            return children;
 573        }
 574
 575        public string getFolderJSON(string folder) {
 576            return JsonConvert.SerializeObject(this.getFolder(folder));
 577        }
 578
 579        public string getEffectsJSON() {
 580            return JsonConvert.SerializeObject(this.effects);
 581
 582        }
 583
 584        public string getRandomEffect() {
 585            string json = null;
 586            if (this.getPersistantBool("useTransitions") && this.effects != null) {
 587                jsonFolder effect = jsonFolder.getRandomSelected(this.effects.children);
 588                jsonFolder direction = null;
 589                if (effect == null) {
 590                    json = "{\"effect\":\"fade\", \"duration\":100}";
 591                } else { 
 592                    json += "{\"effect\":\"" + effect.key + "\"";
 593                    if (effect.children.Count > 0) {
 594                        direction = jsonFolder.getRandomSelected(effect.children);
 595                        if (direction != null) json += ", \"direction\":\"" + direction.title.ToLower() + "\"";
 596                    }
 597                    json += ", \"duration\":1000}";
 598                }
 599            }
 600            return json;
 601        }
 602
 603        public string InvokeScriptOnMonitor(int monitor, string script, string parameters) {
 604            string s = null;
 605            if (this.screensaver.monitors != null) for (int i = 0; i < this.screensaver.monitors.Length; i++) {
 606                if (monitor == Screensaver.CM_ALL || monitor == i) {
 607                    s += Convert.ToString(this.screensaver.monitors[i].InvokeScript(script, parameters.Split(';')));
 608                }
 609            }
 610            return s;
 611        }
 612
 613        private HtmlElement getElementById(string id) {
 614            // Make thread safe 
 615            try {
 616                return (HtmlElement)this.browser.Invoke(new Func<HtmlElement>(() => this.browser.Document.GetElementById(id)));
 617            } catch (Exception e) {
 618                Debug.WriteLine("getElementById" + e.Message);
 619                return null;
 620            }
 621        }
 622
 623        /***
 624         * This function assumes that <div id="#name#"> encapsulates
 625         *  <input type="radio" name="#name# value=...> lines
 626         ***/
 627        private string getDomRadioValue(string id) {
 628            HtmlElement he = (HtmlElement)this.browser.Invoke(new Func<HtmlElement>(() => this.browser.Document.GetElementById(id)));
 629            if (he != null) {
 630                HtmlElementCollection hec = he.GetElementsByTagName("input");
 631                foreach (HtmlElement e in hec) {
 632                    if (e.GetAttribute("type").ToLower() == "radio" && e.GetAttribute("checked").ToLower() == "true") {
 633                        return e.GetAttribute("value");
 634                    }
 635                }
 636            }
 637            return null;
 638        }
 639
 640        private bool getDomCheckboxValue(string id) {
 641            HtmlElement he = this.getElementById(id);
 642            if (he == null) return false;
 643            switch (he.TagName.ToLower()) {
 644                case "input":
 645                    return (bool)he.GetAttribute("checked").ToLower().Equals("true");
 646                break;
 647                default:
 648                    Debug.WriteLine("getCheckboxValue called on non checkbox");
 649                break;
 650            }
 651            return false;
 652        }
 653
 654        public bool persistantLoaded() {
 655            return this.persistant != null;
 656        }
 657
 658        public bool hasPersistantKey(string key) {
 659            return this.persistant.ContainsKey(key);
 660        }
 661
 662        public void setPersistant(string key, object value) {
 663            this.setPersistant(key, value, true);
 664        }
 665
 666        public void setPersistant(string key, object value, bool updateDom) {
 667            if (key == null) {
 668                this.screensaver.showInfoOnMonitors("Invalid configuration key: null", true);
 669            } else { 
 670                this.persistant[key] = value;
 671                if (updateDom) this.setDomValue(key, Convert.ToString(value));
 672            }
 673        }
 674
 675        public object getPersistant(string key) {
 676            if (this.persistant == null || !this.persistant.ContainsKey(key)) throw new KeyNotFoundException(key);
 677            return persistant[key];
 678        }
 679
 680        public bool getPersistantBool(string key) {
 681            if (!this.persistant.ContainsKey(key)) throw new KeyNotFoundException(key);
 682            if (this.persistant[key].GetType() == typeof(bool)) {
 683                return (bool)this.persistant[key];
 684            }
 685            switch (Convert.ToString(this.persistant[key])) {
 686                case "True": case "true": case "1": 
 687                    return true; 
 688                break;
 689                case "False": case "false": case "0": 
 690                    return false;
 691                break;
 692            }
 693            throw new Exception("Can't cast keys '" + key + "' value " + this.persistant[key] + key + " to boolean");
 694        }
 695
 696        public string getPersistantString(string key) {
 697            return Convert.ToString(this.getPersistant(key));
 698        }
 699
 700        public bool syncMonitors() {
 701            if (this.persistant == null) return false;
 702            return this.getPersistantBool("syncScreens");
 703        }
 704
 705        public Config.Order changeOrder() {
 706            if (this.getOrder() == Config.Order.Random) {
 707                //this.checkCheckbox("orderSequential");
 708                this.setPersistant("order", Config.Order.Sequential);
 709                return Config.Order.Sequential;
 710            } else {
 711                //this.checkCheckbox("orderRandom");
 712                this.setPersistant("order", Config.Order.Random);
 713                return Config.Order.Random;
 714            }
 715//            return null;
 716        }
 717
 718        public Config.Order getOrder() {
 719            if (this.getPersistant("order").GetType() == typeof(string)) {
 720                switch (this.getPersistantString("order")) {
 721                    case "random": case "1":
 722                        return Config.Order.Random;
 723                    break;
 724                    default:
 725                        return Config.Order.Sequential;
 726                    break;
 727                }
 728            } else {
 729                if ((Config.Order)Enum.Parse(typeof(Config.Order), this.getPersistantString("order")) == Config.Order.Random) return Config.Order.Random;
 730                else return Config.Order.Sequential;
 731            }
 732        }
 733
 734        public void setInnerHTML(string id, string html) {
 735            HtmlElement he = this.getElementById(id);
 736            if (he != null) {
 737                he.InnerHtml = html;
 738            }
 739        }
 740
 741        public void setDomValue(string id, string value) {
 742            HtmlElement he = this.getElementById(id);
 743            if (he != null) {
 744                switch (he.TagName.ToLower()) {
 745                    case "textarea":
 746                        he.InnerHtml = Utils.HtmlDecode(value);
 747                    break;
 748                    default:
 749                        switch (he.GetAttribute("type").ToLower()) {
 750                            case "radio":
 751                                //he.SetAttribute("value", value);
 752                                if (value == "checked" || value == he.GetAttribute("value").ToLower()) {
 753                                    he.SetAttribute("checked", "true");
 754                                } else {
 755                                    he.SetAttribute("checked", "");
 756                                }
 757                            break;                            
 758                            case "checkbox":
 759                                if (value == "false") {
 760                                    he.SetAttribute("checked", "");
 761                                } else {
 762                                    he.SetAttribute("checked", "true");
 763                                }
 764                            break;
 765                            default:
 766                                he.SetAttribute("value", value);
 767                            break;
 768                        }
 769                    break;
 770                }
 771            }
 772        }
 773
 774        public string getDomValue(string id) {
 775            HtmlElement he = this.getElementById(id);
 776            if (he == null) return null;
 777            try {
 778                switch (he.TagName.ToLower()) {
 779                    case "textarea":
 780                        return Utils.HtmlDecode(he.InnerHtml);
 781                        //return he.InnerHtml;
 782                    break;
 783                    default:
 784                        return he.GetAttribute("value");
 785                    break;
 786                }
 787            } catch (System.Runtime.InteropServices.COMException co) {
 788                //this.screensaver.showInfoOnMonitors("Error getPersistant(" + id + ")\n" + Convert.ToString(co.Message));
 789                return null;
 790            }
 791            return null;
 792        }
 793
 794        
 795        public void Config_FormClosing(object sender, FormClosingEventArgs e) {
 796            if (screensaver.action == Screensaver.Actions.Config) {
 797                this.savePersistantConfig();
 798                Application.Exit();
 799            } else if (!this.screensaver.applicationClosing) {
 800                if (!this.syncMonitors()) {
 801                    // restart timer in-case sync option has changed.
 802                    for (int i = 1; i < this.screensaver.monitors.Length; i++) {
 803                        this.screensaver.monitors[i].timer.Start();
 804                    }
 805                }
 806                //Console.Beep();
 807                this.Hide();
 808                e.Cancel = true;
 809            } 
 810        }
 811
 812        public void ConfigDocumentCompleted(object sender, System.Windows.Forms.WebBrowserDocumentCompletedEventArgs e) {
 813            if (this.screensaver.action == Screensaver.Actions.Wallpaper) {
 814                this.screensaver.initForScreensaverAndWallpaper();
 815                Wallpaper wallpaper = new Wallpaper(this.screensaver);
 816                wallpaper.generateWallpaper();
 817                Application.Exit();
 818            } else {
 819                this.screensaver.initializeMonitors();
 820                if (!this.configInitialised) {
 821                    this.setInnerHTML("version", Constants.getNiceVersion());
 822                    this.setInnerHTML("versionIE", "(IE:" + this.browser.Version.Major.ToString() + "." + this.browser.Version.Minor.ToString() + ")");
 823                    this.browser.Document.InvokeScript("initFancyTreeFolder");
 824                    this.browser.Document.InvokeScript("initFancyTreeTransitions");
 825                    this.configInitialised = true;
 826                }
 827            }
 828        }
 829
 830        private void setCurrentTrackChanges() {
 831            List<string> keys = new List<string>(this.trackChanges.Keys);
 832            for (int i = 0; i < keys.Count; i++) {
 833                this.trackChanges[keys[i]] = this.getPersistant(keys[i]);
 834            }
 835        }
 836
 837        private bool checkTrackChangesChanged() {
 838            List<string> keys = new List<string>(this.trackChanges.Keys);
 839            for (int i = 0; i < keys.Count; i++) {
 840                if (this.trackChanges[keys[i]] != this.getPersistant(keys[i])) return true;
 841            }
 842            return false;
 843        }
 844            
 845        public bool? isUpdateNewer() {
 846            if (this.webUpdateCheck.Document != null) {
 847                HtmlElement he = this.webUpdateCheck.Document.GetElementById("download");
 848                if (he != null) {
 849                    Version update = new Version(he.GetAttribute("data-version"));
 850                    return (this.screensaver.version.CompareTo(update) < 0);
 851                }
 852            }
 853            return null;
 854        }
 855
 856        public string updateFilename() {
 857            if (this.webUpdateCheck.Document != null) {
 858                HtmlElement he = this.webUpdateCheck.Document.GetElementById("download");
 859                if (he != null) {
 860                    return Convert.ToString(Path.Combine(Constants.getUpdateFolder(), Path.GetFileName(he.GetAttribute("href"))));
 861                }
 862            }
 863            return null;
 864        }
 865
 866        public string updateDownloadUrl() {
 867            if (this.webUpdateCheck.Document != null) {
 868                HtmlElement he = this.webUpdateCheck.Document.GetElementById("download");
 869                if (he != null) {
 870                    return he.GetAttribute("href");
 871                }
 872            }
 873            return null;
 874        }
 875
 876        public string updateFileMD5() {
 877            if (this.webUpdateCheck.Document != null) {
 878                HtmlElement he = this.webUpdateCheck.Document.GetElementById("download");
 879                if (he != null) {
 880                    return Convert.ToString(he.GetAttribute("data-md5"));
 881                }
 882            }
 883            return null;
 884        }
 885        
 886
 887        public void installUpdate() {
 888            if (this.webUpdateCheck.Document != null) {
 889                HtmlElement he = this.webUpdateCheck.Document.GetElementById("download");
 890                if (he != null) {
 891                    try {
 892                        Utils.RunTaskScheduler(@"Run" + AppSettings.Abbr + "Update", Convert.ToString(Path.Combine(Constants.getUpdateFolder(), Path.GetFileName(he.GetAttribute("href")))), null);
 893                        this.screensaver.OnExit();
 894                        this.showUpdateInfo("Running installer");
 895                    } catch (System.ComponentModel.Win32Exception we) {
 896                        this.screensaver.showInfoOnMonitors(AppSettings.Abbr + " update cancelled" + Environment.NewLine + we.Message, true, true);
 897
 898                        string clickOrKey = "Press 'U' key to update";
 899                        if (this.getPersistant("mouseSensitivity") == "none" || this.screensaver.action == Screensaver.Actions.Config) clickOrKey = "Click to install now";
 900                        this.screensaver.showUpdateInfo(AppSettings.Abbr + " " + he.GetAttribute("data-version") + " downloaded<br/><a class='exit external' target='_blank' href='file://" + Path.Combine(Constants.getUpdateFolder(), Path.GetFileName(he.GetAttribute("href"))) + "'>" + clickOrKey + "</a>.");
 901
 902                        this.screensaver.resetMouseMove();
 903                    } 
 904                    return;
 905                }
 906            }
 907            this.showUpdateInfo("Nothing to install");
 908        }
 909
 910        private void DownloadProgress(object sender, DownloadProgressChangedEventArgs e) {
 911            if (!this.downloadProgress.IsRunning) this.downloadProgress.Start();
 912            if (this.downloadProgress.ElapsedMilliseconds > 250) { 
 913                if (this.screensaver.action == Screensaver.Actions.Config) {
 914                    //this.downloadProgressIndicator(e.ProgressPercentage);
 915                } else {
 916                    this.screensaver.monitors[0].downloadProgressIndicator(e.ProgressPercentage);
 917                }
 918                this.downloadProgress.Reset();
 919                this.downloadProgress.Start();
 920            }
 921        }
 922
 923        void DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) {
 924            //WebBrowser wbCheckUpdate = sender as WebBrowser;
 925            HtmlElement he = this.webUpdateCheck.Document.GetElementById("download");
 926            string updatePath = Path.Combine(Constants.getUpdateFolder(), Path.GetFileName(he.GetAttribute("href")));
 927            if (!Utils.VerifyMD5(updatePath, he.GetAttribute("data-md5"))) {
 928                // <a href='" + he.GetAttribute("href") + "'>
 929                this.showUpdateInfo("Download " + he.GetAttribute("data-version") + " failed<br/>Please U key to start download manually.");
 930                return;
 931            }
 932            if (this.getPersistantString("checkUpdates") == "yes") this.installUpdate();
 933            else {
 934                string message = AppSettings.Abbr + " " + he.GetAttribute("data-version") + " downloaded<br/><a class='exit external' target='_blank' href='file://" + updatePath + "'>";
 935                if (this.getPersistant("mouseSensitivity") == "none" || this.screensaver.action == Screensaver.Actions.Config) {
 936                    message += "Click to install now</a>";
 937                } else {
 938                    message += "Press 'U' key to update</a><div class='small'>(Ctrl + U to ignores this update)</div>";
 939                }
 940                this.screensaver.showUpdateInfo(message);
 941            }
 942        }
 943
 944        public void showUpdateInfo(string info) {
 945            HtmlElement he = this.browser.Document.GetElementById("update");
 946            he.InnerHtml = info.Replace("<br/>", " ");
 947            if (this.screensaver.action != Screensaver.Actions.Config) {
 948                this.screensaver.showUpdateInfo(info);
 949            }
 950        }
 951
 952        private Uri getUpdateUri() {
 953            string param = "?v=" + Constants.getNiceVersion();
 954            if (this.screensaver.config.getPersistantBool("disableGoAn")) param = "?track=no";
 955            return new Uri(AppSettings.UpdateCheckURL + param);
 956        }
 957
 958        public string getUpdateVersion() {
 959            if (this.webUpdateCheck.Url.Equals(this.getUpdateUri())) {
 960                HtmlElement he = this.webUpdateCheck.Document.GetElementById("download");
 961                return he.GetAttribute("data-version");
 962            }
 963            return null;
 964        }
 965        
 966        private void webUpdateCheck_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {
 967            if (this.webUpdateCheck.Url.Equals(this.getUpdateUri())) {
 968                HtmlElement he = this.webUpdateCheck.Document.GetElementById("download");
 969                if (he != null) {
 970                    Version ignore = null;
 971                    Version compareTo = this.screensaver.version;
 972                    //he.Get
 973                    Version update;
 974                    try {
 975                        update = new Version(he.GetAttribute("data-version"));
 976                    } catch (Exception ex) {
 977                        this.screensaver.showInfoOnMonitors("Error detecting latest version" + Environment.NewLine + ex.Message, true, true);
 978                        return;
 979                    }
 980                    if (this.getPersistantBool("ignoreUpdate")) {
 981                        try {
 982                            ignore = new Version(this.getPersistantString("ignoreVersion"));
 983                        } catch (Exception) { }
 984                        if (ignore != null && compareTo.CompareTo(ignore) < 0) {
 985                            compareTo = ignore;
 986                        }
 987                    }
 988                    if (!this.getPersistantBool("betaVersion")) {
 989                        // Revision number = 0 for alpha release, 
 990                        // Revision number != 0 indicates beta / release candidate version
 991                        update = new Version(update.Major, update.Minor, update.Build);
 992                    }
 993                    this.newVersionAvailable = (compareTo.CompareTo(update) < 0);
 994
 995                    if (this.newVersionAvailable) {
 996                        if (this.downloadUpdates) {
 997                            string downloadedUpdateLocalPath = Path.Combine(Constants.getUpdateFolder(), Path.GetFileName(he.GetAttribute("href")));
 998                            if (!File.Exists(downloadedUpdateLocalPath) || !Utils.VerifyMD5(downloadedUpdateLocalPath, he.GetAttribute("data-md5"))) {
 999                                if (File.Exists(downloadedUpdateLocalPath)) File.Delete(downloadedUpdateLocalPath);
1000                                this.showUpdateInfo("<div class='downloadProgress'><div class='downloadLabel'>Downloading update: " + update.ToString() + "</div><div class='downloadProgress' style='width: 0%'></div>");
1001                                Directory.CreateDirectory(Path.GetDirectoryName(downloadedUpdateLocalPath));//.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), Constants.DownloadFolder));
1002                                WebClient client = new WebClient();
1003                                client.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadFileCompleted);
1004                                client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgress);
1005                                client.DownloadFileAsync(new Uri(he.GetAttribute("href")), downloadedUpdateLocalPath);
1006                                return;
1007                            } else {
1008                                this.DownloadFileCompleted(this, null);
1009                            }
1010                        } else {
1011                            this.showUpdateInfo("Update available<br/><a href='" + he.GetAttribute("href") + "'>Download " + AppSettings.Abbr + " " + he.GetAttribute("data -version-text") + "</a>");
1012                        }
1013                    } else if (this.screensaver.showUpdateStatus) {
1014                        this.screensaver.showAllUpToDate();
1015                    }
1016                }
1017            }
1018        }
1019        
1020        public void timerCheckUpdates_Tick(object sender, EventArgs e) {
1021            this.timerCheckUpdates.Enabled = false;
1022            if (this.screensaver.action != Screensaver.Actions.Preview) {
1023                string update;
1024                try {
1025                    update = this.getPersistantString("checkUpdates");
1026                } catch (KeyNotFoundException knfe) {
1027                    // Try again in a bit
1028                    this.timerCheckUpdates.Interval *= 2;
1029                    this.timerCheckUpdates.Enabled = true;
1030                    return;
1031                }
1032                switch (update) {
1033                    case "yes":
1034                    case "download":
1035                        this.checkUpdates = true;
1036                        this.downloadUpdates = true;
1037                        break;
1038                    case "notify":
1039                        this.checkUpdates = true;
1040                        break;
1041                }
1042                if (this.checkUpdates) {
1043                    //bgwCheckUpdate.DoWork();
1044                    //bgwCheckUpdate.RunWorkerAsync();
1045                    this.webUpdateCheck.Url = this.getUpdateUri();
1046                }
1047            }
1048        }
1049
1050        private void Config_VisibleChanged(object sender, EventArgs e) {
1051            if (this.Visible && this.screensaver.action != Screensaver.Actions.Config) {
1052                this.setCurrentTrackChanges();
1053            } else if (this.screensaver.action != Screensaver.Actions.Config) {
1054                // Hiding
1055                if (this.checkTrackChangesChanged()) {
1056                    if (this.trackChanges["ignoreHiddenFiles"] != this.getPersistant("ignoreHiddenFiles") || this.trackChanges["ignoreHiddenFolders"] != this.getPersistant("ignoreHiddenFolders")) {
1057                        this.screensaver.showInfoOnMonitors("Emptying Media Database", true, false);
1058                        this.screensaver.fileNodes.purgeMediaDatabase();
1059                        this.screensaver.showInfoOnMonitors("Media Database Emptied", true, true);
1060                    } else {
1061                        this.screensaver.showInfoOnMonitors("", true, false);
1062                    }
1063                    this.screensaver.fileNodes.restartBackgroundWorkerImageFolder();
1064                }
1065            }
1066            if (this.Visible) {
1067                Cursor.Show();
1068            } else {
1069                Cursor.Hide();
1070            }
1071        }
1072        /*        
1073                private void Config_Resize(object sender, EventArgs e) {
1074 

Large files files are truncated, but you can click here to view the full file