public void Show() { if (_path != null && AFile.ExistsAsFile(_path)) { AExec.TryRun(_path); } }
//protected override void OnGotFocus(EventArgs e) { _c.Focus(); } /// <summary> /// Loads existing or new workspace. /// If fails, shows a task dialog with several choices - retry, load another, create new, cancel. If then fails, ends process. /// Sets Model and Text properties of the main form. Updates recent files. /// By default runs startup script. /// </summary> /// <param name="wsDir"> /// Workspace's directory. The directory should contain file "files.xml" and subdirectory "files". /// If null, loads the last used workspace (its path is in settings). /// If the setting does not exist, uses AFolders.ThisAppDocuments + @"Main". /// If the file does not exist, copies from AFolders.ThisApp + @"Default\Workspace". /// </param> public FilesModel ZLoadWorkspace(string wsDir = null) { wsDir ??= Program.Settings.workspace; if(wsDir.NE()) wsDir = AFolders.ThisAppDocuments + "Main"; var xmlFile = wsDir + @"\files.xml"; var oldModel = _model; FilesModel m = null; _isNewWorkspace = false; g1: try { //SHOULDDO: if editor runs as admin, the workspace directory should be write-protected from non-admin processes. if(_isNewWorkspace = !AFile.ExistsAsFile(xmlFile)) { AFile.Copy(AFolders.ThisAppBS + @"Default\Workspace", wsDir); } _model?.UnloadingWorkspace(); //saves all, closes documents, sets current file = null m = new FilesModel(_c, xmlFile); _c.Model = m; } catch(Exception ex) { m?.Dispose(); m = null; //AOutput.Write($"Failed to load '{wsDir}'. {ex.Message}"); switch(ADialog.ShowError("Failed to load workspace", wsDir, "1 Retry|2 Load another|3 Create new|0 Cancel", owner: this, expandedText: ex.ToString())) { case 1: goto g1; case 2: m = ZLoadAnotherWorkspace(); break; case 3: m = ZLoadNewWorkspace(); break; } if(m != null) return m; if(_model != null) return _model; Environment.Exit(1); } oldModel?.Dispose(); Program.Model = _model = m; //CONSIDER: unexpand path if(wsDir != Program.Settings.workspace) { if(Program.Settings.workspace != null) { var ar = Program.Settings.recentWS ?? Array.Empty<string>(); int i = Array.IndexOf(ar, wsDir); if(i >= 0) ar = ar.RemoveAt(i); Program.Settings.recentWS = ar.InsertAt(0, Program.Settings.workspace); } Program.Settings.workspace = wsDir; } Program.MainForm.ZSetTitle(); if(Program.Loaded >= EProgramState.LoadedWorkspace) { ZOpenDocuments(); ZModel.RunStartupScripts(); } return _model; }
async void _ConvertTypeLibrary(object tlDef, object button) { string comDll = null; switch (tlDef) { case string path: comDll = path; break; case _RegTypelib r: //can be several locales var aloc = new List <string>(); //registry keys like "0" or "409" var aloc2 = new List <string>(); //locale names for display in the list dialog using (var verKey = Registry.ClassesRoot.OpenSubKey($@"TypeLib\{r.guid}\{r.version}")) { foreach (var s1 in verKey.GetSubKeyNames()) { int lcid = s1.ToInt(0, out int iEnd, STIFlags.IsHexWithout0x); if (iEnd != s1.Length) { continue; //"FLAGS" etc; must be hex number without 0x } aloc.Add(s1); var s2 = "Neutral"; if (lcid > 0) { try { s2 = new CultureInfo(lcid).DisplayName; } catch { s2 = s1; } } aloc2.Add(s2); } } string locale; if (aloc.Count == 1) { locale = aloc[0]; } else { int i = ADialog.ShowList(aloc2, "Locale", owner: this); if (i == 0) { return; } locale = aloc[i - 1]; } comDll = r.GetPath(locale); if (comDll == null || !AFile.ExistsAsFile(comDll)) { ADialog.ShowError(comDll == null ? "Failed to get file path." : "File does not exist.", owner: this); return; } break; } await Task.Run(() => { this.Enabled = false; AOutput.Write($"Converting COM type library to .NET assembly."); try { if (_convertedDir == null) { _convertedDir = AFolders.Workspace + @".interop\"; AFile.CreateDirectory(_convertedDir); } List <string> converted = new List <string>(); Action <string> callback = s => { AOutput.Write(s); if (s.Starts("Converted: ")) { s.RegexMatch(@"""(.+?)"".$", 1, out s); converted.Add(s); } }; int rr = AExec.RunConsole(callback, AFolders.ThisAppBS + "Au.Net45.exe", $"/typelib \"{_convertedDir}|{comDll}\"", encoding: Encoding.UTF8); if (rr == 0) { foreach (var v in converted) { if (!_meta.com.Contains(v)) { _meta.com.Add(v); } } AOutput.Write(@"<>Converted and saved in <link>%AFolders.Workspace%\.interop<>."); _Added(button, _meta.com); } } catch (Exception ex) { ADialog.ShowError("Failed to convert type library", ex.ToStringWithoutStack(), owner: this); } this.Enabled = true; }); }
/// <summary> /// Opens XML file and creates toolbars/menus/submenus from XML tags. /// </summary> /// <param name="xmlFile">XML file containing menus/toolbars without user customizations.</param> /// <param name="xmlFileCustom">XML file containing user customizations. It will be created or updated when saving customizations.</param> /// <param name="tsRenderer"></param> public void BuildAll(string xmlFile, string xmlFileCustom, ToolStripRenderer tsRenderer = null) { Debug.Assert(_xStrips == null); if (_xStrips != null) { throw new InvalidOperationException(); } _xmlFileDefault = xmlFile; _xmlFileCustom = xmlFileCustom; try { _xStrips = AExtXml.LoadElem(xmlFile); } catch (Exception ex) { ADialog.ShowError("Failed to load file", ex.ToString()); throw; } XElement xCustom = null; if (AFile.ExistsAsFile(_xmlFileCustom)) { try { xCustom = AExtXml.LoadElem(_xmlFileCustom); } catch (Exception e) { AOutput.Write("Failed to load file", _xmlFileCustom, e.Message); } } Size imageScalingSize = Au.Util.ADpi.SmallIconSize_; //if high DPI, auto scale images //create top-level toolstrips (menu bar and toolbars), and call _AddChildItems to add items and create drop-down menus and submenus _inBuildAll = true; bool isMenu = true; foreach (var xe in _xStrips.Elements().ToArray()) //info: ToArray() because _MergeCustom replaces XML elements of custom toolbars { string name = xe.Name.LocalName; var x = xe; if (xCustom != null) { _MergeCustom(xCustom, ref x, name, isMenu); } ToolStrip t; if (isMenu) { t = MenuBar = new Util.AMenuStrip(); } else { var cts = new Util.AToolStrip(); Toolbars.Add(name, cts); t = cts; switch (name) { case "Custom1": _tsCustom1 = cts; break; case "Custom2": _tsCustom2 = cts; break; } } t.SuspendLayout(); t.Tag = x; t.Text = t.Name = name; //t.AllowItemReorder = true; //don't use, it's has bugs etc, we know better how to do it if (tsRenderer != null) { t.Renderer = tsRenderer; } if (isMenu) { t.Padding = new Padding(); //remove menu bar paddings } else { } if (imageScalingSize.Height != 16) { t.ImageScalingSize = imageScalingSize; //info: all submenus will inherit it from menubar } _AddChildItems(x, t, isMenu); t.ResumeLayout(false); isMenu = false; } _inBuildAll = false; }
//Loads and parses XML. Creates the _aX lists, _firstSplit and the tree structure. void _LoadXmlAndCreateLayout(string xmlFileDefault, string xmlFileCustomized) { //We have 1 or 2 XML files containing panel/toolbar layout. //xmlFileDefault contains default XML. It eg can be in AFolders.ThisApp. //xmlFileCustomized contains previously saved XML (user-modified layout). //At first try to load xmlFileCustomized. If it does not exist or is invalid, load xmlFileDefault; or get missing data from xmlFileDefault, if possible. //Also loads xmlFileDefault when xmlFileCustomized XML does not match panels of new app version and cannot resolve it (eg some panels removed). bool usesDefaultXML = false; string xmlFile = xmlFileCustomized, xmlVersion = null, outInfo = null; for (int i = 0; i < 2; i++) { if (i == 0) { if (!AFile.ExistsAsFile(xmlFile)) { continue; } } else { usesDefaultXML = true; xmlFile = xmlFileDefault; } bool fileLoaded = false; try { var x = AExtXml.LoadElem(xmlFile); fileLoaded = true; if (!usesDefaultXML) { xmlVersion = x.Attr("version"); } x = x.Element("split"); //THIS DOES THE MAIN JOB _firstSplit = new _Split(this, null, x); if (_aPanel.Count < _initControls.Count) //more panels added in this app version { if (usesDefaultXML) { throw new Exception("debug1"); } _GetPanelXmlFromDefaultFile(xmlFileDefault); } break; //speed: xml.Load takes 170 microseconds. //tested: XML can be added to Application Settings, but var xml=Properties.Settings.Default.PanelsXML takes 61 MILLIseconds. } catch (Exception e) { var sErr = $"Failed to load file '{xmlFile}'.\r\n\t{e.ToStringWithoutStack()}"; if (usesDefaultXML) { _xmlFile = null; ADialog.ShowError("Cannot load panel/toolbar layout.", $"{sErr}\r\n\r\nReinstall the application."); Environment.Exit(1); } else { //probably in this version there are less panels, most likely when downgraded. Or the file is corrupt. if (fileLoaded && xmlVersion != _asmVersion) { outInfo = "Info: this application version resets the panel/toolbar layout, sorry."; } else { AWarning.Write(sErr, -1); } } _aSplit.Clear(); _aTab.Clear(); _aPanel.Clear(); } } //if(usesDefaultXML || xmlVersion == _asmVersion) return; if (outInfo != null) { AOutput.Write(outInfo); } }
static bool ProcessHtmlFile(ref string s, bool isApi, string siteDir) { int nr = 0; if (isApi) { //Remove the <au><!--<code>*xml*</code>--></au> enclosing. nr += s.RegexReplace(@"<au><!--(<code>.+?</code>)--></au>", @"$1", out s); //Link Method(parameters) -> Type.Method. And remove #jump. Works for properties too. //Exclude those in auto-generated tables of class methods and properties. nr += s.RegexReplace(@"(<a class=""xref"" href=""Au\.(?:Types\.|Triggers\.|Util\.)?+([\w\.\-]+\.\w+)\.html)#\w+"">.+?</a>(?!\s*</td>\s*<td class=""markdown level1 summary"">)", @"$1"">$2</a>", out s); //the same for enum nr += s.RegexReplace(@"(<a class=""xref"" href=""Au\.(?:Types\.|Triggers\.|Util\.)?+(\w+)\.html)#\w+"">(\w+</a>)", @"$1"">$2.$3", out s); //note: enums must not be nested in types //In class member pages, in title insert a link to the type. nr += s.RegexReplace(@"<h1\b[^>]* data-uid=""(Au\.(?:Types\.|Triggers\.|Util\.)?+([\w\.`]+))\.\w+\*?""[^>]*>(?:Method|Property|Field|Event|Operator|Constructor) (?=\w)", m => m.ExpandReplacement(@"$0<a href=""$1.html"">$2</a>.").Replace("`", "-"), out s); //Remove anchor from the first hidden overload <hr>, to prevent scrolling. nr += s.RegexReplace(@"(</h1>\s*<hr class=""overload"") id="".+?"" data-uid="".+?""", @"$1", out s); //Add "(+ n overloads)" link in h1 and "(next/top)" links in h2 if need. if (s.RegexFindAll(@"<h2 class=""overload"" id=""(.+?)"".*?>Overload", out var a) && a.Length > 1) { var b = new StringBuilder(); int jPrev = 0; for (int i = 0; i < a.Length; i++) { bool first = i == 0, last = i == a.Length - 1; int j = first ? s.Find("</h1>") : a[i].End; b.Append(s, jPrev, j - jPrev); jPrev = j; b.Append("<span style='font-size:14px; font-weight: 400; margin-left:20px;'>("); if (first) { b.Append("+ ").Append(a.Length - 1).Append(" "); } var href = last ? "top" : a[i + 1][1].Value; b.Append("<a href='#").Append(href).Append("'>"); if (first) { b.Append("overload").Append(a.Length == 2 ? "" : "s"); } else { b.Append(last ? "back to top" : "next"); } b.Append("</a>)</span>"); } b.Append(s, jPrev, s.Length - jPrev); s = b.ToString(); nr++; } } else { //in .md we use this for links to api: [Class]() or [Class.Func](). // DocFX converts it to <a href="">Class</a> etc without warning. // Now convert it to a working link. nr += s.RegexReplace(@"<a href="""">(.+?)</a>", m => { var k = m[1].Value; string href = null; foreach (var ns in s_ns) { if (AFile.ExistsAsFile(siteDir + "/api/" + ns + k + ".html")) { href = "../api/" + ns + k + ".html"; break; } } if (href == null) { AOutput.Write($"cannot resolve link: [{k}]()"); return(m.Value); } return(m.ExpandReplacement($@"<a href=""{href}"">$1</a>")); }, out s); } //<msdn>...</msdn> -> <a href="google search"> nr += s.RegexReplace(@"<msdn>(.+?)</msdn>", @"<a href=""https://www.google.com/search?q=site:docs.microsoft.com+$1"">$1</a>", out s); //javascript renderTables() replacement, to avoid it at run time. Also remove class table-striped. nr += s.RegexReplace(@"(?s)<table(>.+?</table>)", @"<div class=""table-responsive""><table class=""table table-bordered table-condensed""$1</div>", out s); //the same for renderAlerts nr += s.RegexReplace(@"<div class=""(NOTE|TIP|WARNING|IMPORTANT|CAUTION)\b", o => { string k = "info"; switch (o[1].Value[0]) { case 'W': k = "warning"; break; case 'I': case 'C': k = "danger"; break; } return(o.Value + " alert alert-" + k); }, out s); //replace something in syntax code blocks nr += s.RegexReplace(@"(?<=<div class=""codewrapper"">)\s*<pre><code.+?(?=</code></pre>)", m => { var k = m.Value; k = k.RegexReplace(@"\(\w+\)0", @"0"); k = k.RegexReplace(@"default\([^)?]+\? *\)", @"null"); k = k.RegexReplace(@"default\(.+?\)", @"default"); return(k); } , out s); //nr += s.RegexReplace(@"", @"", out s); return(nr > 0); }
/// <summary> /// Loads image and returns its data in .bmp file format. /// Returns null if fails, for example file not found or invalid Base64 string. /// </summary> /// <param name="s">Depends on t. File path or resource name without prefix or Base64 image data without prefix.</param> /// <param name="t">Image type and string format.</param> /// <param name="searchPath">Use <see cref="AFile.SearchPath"/></param> /// <remarks>Supports environment variables etc. If not full path, searches in <see cref="AFolders.ThisAppImages"/>.</remarks> public static byte[] BmpFileDataFromString(string s, ImageType t, bool searchPath = false) { //AOutput.Write(t, s); try { switch (t) { case ImageType.Bmp: case ImageType.PngGifJpg: case ImageType.Cur: if (searchPath) { s = AFile.SearchPath(s, AFolders.ThisAppImages); if (s == null) { return(null); } } else { if (!APath.IsFullPathExpandEnvVar(ref s)) { return(null); } s = APath.Normalize(s, AFolders.ThisAppImages); if (!AFile.ExistsAsFile(s)) { return(null); } } break; } switch (t) { case ImageType.Base64CompressedBmp: return(AConvert.Decompress(Convert.FromBase64String(s))); case ImageType.Base64PngGifJpg: using (var stream = new MemoryStream(Convert.FromBase64String(s), false)) { return(_ImageToBytes(Image.FromStream(stream))); } case ImageType.Resource: return(_ImageToBytes(AResources.GetAppResource(s) as Image)); case ImageType.Bmp: return(File.ReadAllBytes(s)); case ImageType.PngGifJpg: return(_ImageToBytes(Image.FromFile(s))); case ImageType.Ico: case ImageType.IconLib: case ImageType.ShellIcon: case ImageType.Cur: return(_IconToBytes(s, t == ImageType.Cur, searchPath)); } } catch (Exception ex) { ADebug.Print(ex.Message + " " + s); } return(null); }
static void _CreateDoc(string dbFile, string dir1, string dir2) { AFile.Delete(dbFile); using var d = new ASqlite(dbFile, sql: "PRAGMA page_size = 8192;"); //8192 makes file smaller by 2-3 MB. using var trans = d.Transaction(); d.Execute("CREATE TABLE doc (name TEXT PRIMARY KEY, xml TEXT)"); using var statInsert = d.Statement("INSERT INTO doc VALUES (?, ?)"); using var statDupl = d.Statement("SELECT xml FROM doc WHERE name=?"); var haveRefs = new List <string>(); var uniq = new Dictionary <string, string>(); //name -> asmName //using var textFile = File.CreateText(Path.ChangeExtension(dbFile, "txt")); //test. Compresses almost 2 times better than db. _AddDir(dir1, "WindowsBase"); _AddDir(dir2); statInsert.BindAll(".", string.Join("\n", haveRefs)).Step(); trans.Commit(); d.Execute("VACUUM"); AOutput.Write("Created " + dbFile); void _AddDir(string dir, params string[] skip) { foreach (var f in AFile.EnumDirectory(dir)) { if (f.IsDirectory) { continue; } if (!f.Name.Ends(".xml", true)) { continue; } var asmName = f.Name.RemoveSuffix(4); if (skip.Contains(asmName)) { continue; } if (!AFile.ExistsAsFile(dir + asmName + ".dll")) { AOutput.Write("<><c 0x808080>" + f.Name + "</c>"); continue; } _AddFile(asmName, f.FullPath); //break; } } void _AddFile(string asmName, string xmlFile) { //AOutput.Write(asmName); haveRefs.Add(asmName); var xr = AExtXml.LoadElem(xmlFile); foreach (var e in xr.Descendants("member")) { var name = e.Attr("name"); //remove <remarks> and <example>. Does not save much space, because .NET xmls don't have it. foreach (var v in e.Descendants("remarks").ToArray()) { v.Remove(); } foreach (var v in e.Descendants("example").ToArray()) { v.Remove(); } using var reader = e.CreateReader(); reader.MoveToContent(); var xml = reader.ReadInnerXml(); //AOutput.Write(name, xml); //textFile.WriteLine(name); textFile.WriteLine(xml); textFile.WriteLine("\f"); if (uniq.TryGetValue(name, out var prevRef)) { if (!statDupl.Bind(1, name).Step()) { throw new AuException(); } var prev = statDupl.GetText(0); if (xml != prev && asmName != "System.Linq") { AOutput.Write($"<>\t{name} already defined in {prevRef}\r\n<c 0xc000>{prev}</c>\r\n<c 0xff0000>{xml}</c>"); } statDupl.Reset(); } else { statInsert.BindAll(name, xml).Step(); uniq.Add(name, asmName); } statInsert.Reset(); } } }