/// <summary> /// Deletes a selected col w/ confirmation. /// </summary> /// <param name="sender"><c><see cref="it_DeleteHead"/></c></param> /// <param name="e"></param> void editcolclick_DeleteHead(object sender, EventArgs e) { int selc = Table.getSelectedCol(); const string head = _warnColhead + " Are you sure you want to delete the selected col ..."; using (var ib = new Infobox(Infobox.Title_infor, head, Table.Fields[selc - 1], InfoboxType.Info, InfoboxButtons.CancelYes)) { if (ib.ShowDialog(this) == DialogResult.OK) { Obfuscate(); DrawRegulator.SuspendDrawing(Table); steadystate(); Table.DeleteCol(selc); it_freeze1.Enabled = Table.ColCount > 1; it_freeze2.Enabled = Table.ColCount > 2; DrawRegulator.ResumeDrawing(Table); Obfuscate(false); } } }
/// <summary> /// Applies a text-edit via <c><see cref="_editor"/></c>. /// </summary> /// <param name="select"><c>true</c> to focus the <c>YataGrid</c></param> /// <seealso cref="YataGrid.editresultaccept()"><c>YataGrid.editresultaccept()</c></seealso> internal void editresultaccept(bool @select = false) { //logfile.Log("Propanel.editresultaccept()"); bool sanitized = false; Cell cell = _grid[_r, _c]; if (_editor.Text != cell.text) { sanitized = _grid.ChangeCellText(cell, _editor); // does a text-check _grid.Invalidator(YataGrid.INVALID_GRID | YataGrid.INVALID_FROZ); } else if (cell.loadchanged) { _grid.ClearLoadchanged(cell); } editresultcancel(@select); if (sanitized) { using (var ib = new Infobox(Infobox.Title_warni, "The text that was submitted has been altered.", null, InfoboxType.Warn)) { ib.ShowDialog(_grid._f); } } }
/// <summary> /// Handles it-click to order row-ids. /// </summary> /// <param name="sender"> /// <list type="bullet"> /// <item><c><see cref="it_OrderRows"/></c></item> /// <item><c><see cref="it_CheckRows"/></c></item> /// </list></param> /// <param name="e"></param> /// <remarks>Fired by /// <list type="bullet"> /// <item>2daOps|Order rows <c>[Ctrl+d]</c></item> /// <item>2daOps|Test rows <c>[Ctrl+t]</c> /// <c><see cref="opsclick_TestOrder()">opsclick_TestOrder()</see></c></item> /// </list></remarks> void opsclick_Order(object sender, EventArgs e) { string title, head; InfoboxType ibt; int changed = order(); if (changed != 0) { layout(); title = Infobox.Title_warni; head = changed + " id" + (changed == 1 ? String.Empty : "s") + " corrected."; ibt = InfoboxType.Warn; } else { title = Infobox.Title_infor; head = "Row order is Okay - no change."; ibt = InfoboxType.Info; } using (var ib = new Infobox(title, head, null, ibt)) { ib.ShowDialog(this); } }
/// <summary> /// Checks for a quotation character and if found shows an error to the /// user. /// </summary> /// <param name="lines">an array of strings</param> /// <param name="pfe2da">the fullpath of the 2da-file</param> /// <returns><c>true</c> if a quote character is found</returns> static bool hasQuote(string[] lines, string pfe2da) { foreach (string line in lines) { foreach (char c in line) { if (c == '"') { const string head = "The 2da-file contains double-quotes. Although that can be" + " valid in a 2da-file Yata's 2da Info-grope is not coded to cope." + " Format the 2da-file (in a texteditor) to not use double-quotes" + " if you want to access it for 2da Info."; using (var ib = new Infobox(Infobox.Title_error, head, pfe2da, InfoboxType.Error)) { ib.ShowDialog(Yata.that); } return(true); } } } return(false); }
/// <summary> /// Handles a click on the Select button. Passes the current strref to /// <c>Yata</c> and closes this dialog. /// </summary> /// <param name="sender"><c><see cref="bu_Accept"/></c></param> /// <param name="e"></param> void click_btnSelect(object sender, EventArgs e) { bool proceed = _eId == TalkReader.invalid || _dict.Count == 0 || // -> talkfile not loaded, therefore user knows what he/she _dict.ContainsKey(_eId); // is doing (ie, red panel BG) so let it go through. if (!proceed) { using (var ib = new Infobox(Infobox.Title_warni, "Entry not found in the .tlk file. Proceed ...", null, InfoboxType.Warn, InfoboxButtons.CancelYes)) { proceed = ib.ShowDialog(this) == DialogResult.OK; } } if (proceed) { if (_eId != TalkReader.invalid && cb_Custo.Checked) { _eId |= TalkReader.bitCusto; } (_f as Yata)._strref = _eId.ToString(CultureInfo.InvariantCulture); Close(); } }
/// <summary> /// A generic warn-box if something goes wonky while loading a 2da-file. /// </summary> /// <param name="head">the warning</param> /// <param name="copy">copyable text</param> /// <returns>a <c>DialogResult</c> /// <list type="bullet"> /// <item><c>Cancel</c> - abort load</item> /// <item><c>OK</c> - ignore further errors and try to load the 2da-file</item> /// <item><c>Retry</c> - check for next error</item> /// </list></returns> static DialogResult ShowLoadWarning(string head, string copy) { using (var ib = new Infobox(Infobox.Title_warni, head, copy, InfoboxType.Warn, InfoboxButtons.AbortLoadNext)) { return(ib.ShowDialog(Yata.that)); } }
/// <summary> /// Requests user-confirmation when saving a file when readonly or when /// a faulty row-id is detected. /// </summary> /// <param name="head"></param> /// <returns><c>true</c> to proceed - <c>false</c> to stop</returns> bool SaveWarning(string head) { _warned = true; using (var ib = new Infobox(Infobox.Title_alert, head + " Save anyway ...", null, InfoboxType.Warn, InfoboxButtons.CancelYes)) { return(ib.ShowDialog(this) == DialogResult.OK); } }
/// <summary> /// Writes file and closes this <c>SettingsEditor</c>. /// </summary> /// <param name="sender"> /// <list type="bullet"> /// <item><c><see cref="bu_Okay"/></c></item> /// <item><c>null</c> - <c>[Ctrl+s]</c></item> /// </list></param> /// <param name="e"></param> void click_Okay(object sender, EventArgs e) { try { string pfeT = Path.Combine(Application.StartupPath, Settings.FE) + ".t"; File.WriteAllText(pfeT, rtb_Settings.Text); if (File.Exists(pfeT)) { string pfe = Path.Combine(Application.StartupPath, Settings.FE); File.Delete(pfe); File.Copy(pfeT, pfe); if (File.Exists(pfe)) { File.Delete(pfeT); using (var ib = new Infobox(Infobox.Title_infor, "Yata must be restarted for any changes to take effect.")) { ib.ShowDialog(this); } } } } catch (Exception ex) { using (var ib = new Infobox(Infobox.Title_excep, "the Settings.cfg file could not be written to the application directory.", ex.ToString(), InfoboxType.Error)) { ib.ShowDialog(this); } } finally { if (sender != null) { Close(); } } }
/// <summary> /// Pastes <c><see cref="_copyc"/></c> to the cell-fields of a selected /// col. /// </summary> /// <param name="sender"><c><see cref="it_PasteCell"/></c></param> /// <param name="e"></param> void editcolclick_PasteCol(object sender, EventArgs e) { int diff; string head; if (Table.RowCount < _copyc.Count) { diff = _copyc.Count - Table.RowCount; head = "The table has " + diff + " less row" + (diff == 1 ? String.Empty : "s") + " than the copy."; } else if (Table.RowCount > _copyc.Count) { diff = Table.RowCount - _copyc.Count; head = "The copy has " + diff + " less row" + (diff == 1 ? String.Empty : "s") + " than the table."; } else { diff = 0; head = null; } if (diff != 0) { using (var ib = new Infobox(Infobox.Title_warni, head + " Proceed ...", null, InfoboxType.Warn, InfoboxButtons.CancelYes)) { if (ib.ShowDialog(this) == DialogResult.OK) { diff = 0; } } } if (diff == 0) { Obfuscate(); DrawRegulator.SuspendDrawing(Table); Table.PasteCol(_copyc); DrawRegulator.ResumeDrawing(Table); Obfuscate(false); } }
/// <summary> /// Clears the Undo/Redo stacks. /// </summary> /// <param name="sender"><c><see cref="it_ClearUr"/></c></param> /// <param name="e"></param> /// <remarks>Fired by /// <list type="bullet"> /// <item>2daOps|Clear undo/redo</item> /// </list></remarks> void opsclick_ClearUr(object sender, EventArgs e) { // after first run (clears ~300..500kb) this appears to clear // exactly 0 bytes per Clear. long bytes = GetUsage(); Table._ur.Clear(); GC.Collect(); GC.WaitForPendingFinalizers(); bytes -= GetUsage(); string head = "Estimated memory freed : " + String.Format(CultureInfo.InvariantCulture, "{0:n0}", bytes) + " bytes"; using (var ib = new Infobox(Infobox.Title_infor, head)) ib.ShowDialog(this); }
/// <summary> /// Handles it-click to open ReadMe.txt. /// </summary> /// <param name="sender"><c><see cref="it_ReadMe"/></c></param> /// <param name="e"></param> /// <remarks>Invoked by /// <list type="bullet"> /// <item>Help|ReadMe.txt <c>[F1]</c></item> /// </list></remarks> void helpclick_Help(object sender, EventArgs e) { string pfe = Path.Combine(Application.StartupPath, "ReadMe.txt"); if (File.Exists(pfe)) { Process.Start(pfe); } else { using (var ib = new Infobox(Infobox.Title_error, "ReadMe.txt was not found in the application directory.", null, InfoboxType.Error)) { ib.ShowDialog(this); } } }
// + " Tip: tidy and save the 2da first."; /// <summary> /// Opens a text-input dialog for creating a col at a selected col-id or /// at the far right if no col is selected. /// </summary> /// <param name="sender"><c><see cref="it_CreateHead"/></c></param> /// <param name="e"></param> void editcolclick_CreateHead(object sender, EventArgs e) { const string head = _warnColhead + " Are you sure you want to create a col ..."; using (var ib = new Infobox(Infobox.Title_infor, head, null, InfoboxType.Info, InfoboxButtons.CancelYes)) { if (ib.ShowDialog(this) == DialogResult.OK) { int selc = Table.getSelectedCol(); using (var idc = new InputDialog(this, selc)) { if (idc.ShowDialog(this) == DialogResult.OK && InputDialog._colabel.Length != 0) { Obfuscate(); DrawRegulator.SuspendDrawing(Table); // create at far right if no col selected if (selc < Table.FrozenCount) // ~safety. { selc = Table.ColCount; } steadystate(); Table.CreateCol(selc); it_freeze1.Enabled = Table.ColCount > 1; it_freeze2.Enabled = Table.ColCount > 2; DrawRegulator.ResumeDrawing(Table); Obfuscate(false); } } } } }
/// <summary> /// Handles it-click on File|Close. /// </summary> /// <param name="sender"> /// <list type="bullet"> /// <item><c><see cref="it_Close"/></c></item> /// <item><c><see cref="tabit_Close"/></c></item> /// <item><c><see cref="it_Reload"/></c></item> /// <item><c><see cref="tabit_Reload"/></c></item> /// <item><c>null</c></item> /// </list></param> /// <param name="e"></param> /// <remarks>Called by /// <list type="bullet"> /// <item>File|Close <c>[F4]</c></item> /// <item>tab|Close</item> /// <item>File|Reload <c>[Ctrl+r]</c> /// <c><see cref="fileclick_Reload()">fileclick_Reload()</see></c></item> /// <item>tab|Reload /// <c><see cref="fileclick_Reload()">fileclick_Reload()</see></c></item> /// <item><c><see cref="VerifyCurrentFileState()">VerifyCurrentFileState()</see></c></item> /// </list></remarks> internal void fileclick_ClosePage(object sender, EventArgs e) { bool close = !Table.Changed; if (!close) { using (var ib = new Infobox(Infobox.Title_alert, "Data has changed. Okay to close ...", null, InfoboxType.Warn, InfoboxButtons.CancelYes)) { close = ib.ShowDialog(this) == DialogResult.OK; } } if (close) { ClosePage(Tabs.SelectedTab); } }
/// <summary> /// 1. colhead: Cancels close if the input-text is already taken by /// another colhead. /// /// 2. defaultval: /// </summary> /// <param name="sender"><c><see cref="bu_Okay"/></c></param> /// <param name="e"></param> void click_Okay(object sender, EventArgs e) { if (_selc != DEFVAL) // colhead { string[] fields = Yata.Table.Fields; for (int i = 0; i != fields.Length; ++i) { if ((_selc == -1 || _selc != i + 1) && String.Equals(fields[i], tb_Input.Text, StringComparison.OrdinalIgnoreCase)) { using (var ib = new Infobox(Infobox.Title_error, "That label is already used by another colhead.", null, InfoboxType.Error)) { ib.ShowDialog(this); } _cancel = true; } } } else // defaultval { string val = tb_Input.Text; if (!SpellcheckDefaultval(ref val)) { using (var ib = new Infobox(Infobox.Title_warni, "The text has changed.", null, InfoboxType.Warn)) { ib.ShowDialog(this); } tb_Input.Text = val; _cancel = true; } } }
/// <summary> /// Fires when user clicks Ok. Let the chips fly. /// </summary> /// <param name="sender"><c><see cref="bu_Accept"/></c></param> /// <param name="e"></param> void click_Ok(object sender, EventArgs e) { _cancel = true; var f = _f as Yata; int result; if (rb_StartAdd.Checked) { f._startCr = Int32.Parse(tb_StartAdd.Text, CultureInfo.InvariantCulture); // readonly - shall be valid. if (rb_StopFinish.Checked) { if (Int32.TryParse(tb_StopFinish.Text, out result) && (f._lengthCr = result - f._startCr + 1) > 0) { _cancel = false; } } else // rb_StopCount.Checked { if (Int32.TryParse(tb_StopCount.Text, out result) && (f._lengthCr = result) > 0) { _cancel = false; } } } else // rb_StartInsert.Checked { if (Int32.TryParse(tb_StartInsert.Text, out result) && (f._startCr = result) > -1 && f._startCr <= Yata.Table.RowCount) { if (rb_StopFinish.Checked) { if (Int32.TryParse(tb_StopFinish.Text, out result) && (f._lengthCr = result - f._startCr + 1) > 0) { _cancel = false; } } else // rb_StopCount.Checked { if (Int32.TryParse(tb_StopCount.Text, out result) && (f._lengthCr = result) > 0) { _cancel = false; } } } } if (_cancel) { using (var ib = new Infobox(Infobox.Title_error, GetDarthQuote(), null, InfoboxType.Error)) { ib.ShowDialog(this); } } else if (rb_FillCopied.Checked) { f._fillCr = Yata.CrFillType.Copied; } else if (rb_FillSelected.Checked) { f._fillCr = Yata.CrFillType.Selected; } else { f._fillCr = Yata.CrFillType.Stars; // rb_FillStars.Checked } }
/// <summary> /// Handles it-click to test row-ids. /// </summary> /// <param name="sender"><c><see cref="it_CheckRows"/></c></param> /// <param name="e"></param> /// <remarks>Fired by /// <list type="bullet"> /// <item>2daOps|Test rows <c>[Ctrl+t]</c></item> /// </list></remarks> void opsclick_TestOrder(object sender, EventArgs e) { var borks = new List <string>(); bool stop = false; int result; for (int r = 0; r != Table.RowCount; ++r) { if (!Int32.TryParse(Table[r, 0].text, out result)) { if (borks.Count == 16) // stop this Madness { stop = true; break; } borks.Add("id " + r + " is not an integer"); } else if (result != r) { if (borks.Count == 16) // stop this Madness { stop = true; break; } borks.Add("id " + r + " is out of order"); } } string title, head; string copy = String.Empty; InfoboxType ibt; if (borks.Count != 0) { foreach (string bork in borks) { if (copy.Length != 0) { copy += Environment.NewLine; } copy += bork; } title = Infobox.Title_warni; head = "Row order is borked."; ibt = InfoboxType.Warn; if (!Table.Readonly) { head += " Do you want to auto-order the ids ..."; } } else { title = Infobox.Title_infor; head = "Row order is Okay."; ibt = InfoboxType.Info; } using (var ib = new Infobox(title, (stop ? "The test has been stopped at 16 borks. " : String.Empty) + head, (copy.Length != 0 ? copy + (stop ? Environment.NewLine + "..." : String.Empty) : null), ibt, (copy.Length != 0 && !Table.Readonly ? InfoboxButtons.CancelYes : InfoboxButtons.Okay))) { if (ib.ShowDialog(this) == DialogResult.OK) { opsclick_Order(sender, e); } } }
/// <summary> /// Handles it-click to open the <c><see cref="SettingsEditor"/></c>. /// </summary> /// <param name="sender"><c><see cref="it_Settings"/></c></param> /// <param name="e"></param> void helpclick_Settings(object sender, EventArgs e) { if (_fsettings == null) { string pfe = Path.Combine(Application.StartupPath, Settings.FE); if (!File.Exists(pfe)) { const string head = "a Settings.cfg file does not exist in the application directory. Do you want to create one ..."; using (var ib = new Infobox(Infobox.Title_infor, head, null, InfoboxType.Info, InfoboxButtons.CancelYes)) { if (ib.ShowDialog(this) == DialogResult.OK) { try { using (var sw = new StreamWriter(File.Open(pfe, FileMode.Create, FileAccess.Write, FileShare.None))) { sw.WriteLine("#Help|ReadMe.txt describes these settings."); if (Settings.options == null) { Settings.CreateOptions(); } for (int i = 0; i != Settings.ids; ++i) { sw.WriteLine(Settings.options[i]); } } } catch (Exception ex) { using (var ibo = new Infobox(Infobox.Title_excep, "a Settings.cfg file could not be created in the application directory.", ex.ToString(), InfoboxType.Error)) { ibo.ShowDialog(this); } } } } } if (File.Exists(pfe)) { try { string[] lines = File.ReadAllLines(pfe); _fsettings = new SettingsEditor(this, lines); it_Settings.Checked = true; } catch (Exception ex) { // the stock MessageBox 'shall' be used if an exception is going to cause a CTD: // eg. a stock Font was disposed but the SettingsEditor needs it during its // initialization ... The app can't show a Yata-dialog in such a case; but the // stock MessageBox will pop up then ... CTD. // MessageBox.Show("The Settings.cfg file could not be read in the application directory." // + Environment.NewLine + Environment.NewLine // + ex); using (var ib = new Infobox(Infobox.Title_excep, "The Settings.cfg file could not be read in the application directory.", ex.ToString(), InfoboxType.Error)) { ib.ShowDialog(this); } } } } else { if (_fsettings.WindowState == FormWindowState.Minimized) { if (_fsettings.Maximized) { _fsettings.WindowState = FormWindowState.Maximized; } else { _fsettings.WindowState = FormWindowState.Normal; } } _fsettings.BringToFront(); } }
/// <summary> /// Tries to load a 2da-file. /// </summary> /// <returns> /// <list type="bullet"> /// <item><c><see cref="LOADRESULT_FALSE"/></c></item> /// <item><c><see cref="LOADRESULT_TRUE"/></c></item> /// <item><c><see cref="LOADRESULT_CHANGED"/></c></item> /// </list></returns> internal int LoadTable() { /* const string test = "The 2da-file contains double-quotes. Although that can be" + " valid in a 2da-file Yata's 2da Info-grope is not coded to cope." + " Format the 2da-file (in a texteditor) to not use double-quotes" + " if you want to access it for 2da Info."; + using (var ib = new Infobox(Infobox.Title_error, + test, + "A bunch of text. A bunch of text. A bunch of text. A bunch of text." + " A bunch of text. A bunch of text. A bunch of text. A bunch of text." + " A bunch of text. A bunch of text.", + InfoboxType.Error)) + { + ib.ShowDialog(_f); + } */ // � // byte[] asciiBytes = Encoding.ASCII.GetBytes("�"); // logfile.Log("� = " + asciiBytes); // foreach (var b in asciiBytes) // logfile.Log(((int)b).ToString()); // // byte[] utf8Bytes = Encoding.UTF8.GetBytes("�"); // logfile.Log("� = " + utf8Bytes); // foreach (var b in utf8Bytes) // logfile.Log(((int)b).ToString()); // logfile.Log(); // logfile.Log("default encoding= " + Encoding.GetEncoding(0)); // EncodingInfo[] encs = Encoding.GetEncodings(); // foreach (var enc in encs) // { // logfile.Log(); // logfile.Log(". enc= " + enc.Name); // logfile.Log(". DisplayName= " + enc.DisplayName); // logfile.Log(". CodePage= " + enc.CodePage); // } Lastwrite = File.GetLastWriteTime(Fullpath); _rows.Clear(); int loadresult = LOADRESULT_TRUE; string[] lines = File.ReadAllLines(Fullpath); // default decoding is UTF-8 // 0. test character decoding -> for (int i = 0; i != lines.Length; ++i) { if (lines[i].Contains("�")) { if (CodePage == -1) { CodePage = Settings._codepage; // init. } Encoding enc; if (CodePage == 0 || CheckCodepage(CodePage)) { // CodePage is default or user-valid. enc = Encoding.GetEncoding(CodePage); } else { enc = null; } using (var cpd = new CodePageDialog(_f, enc)) { int result; if (cpd.ShowDialog(_f) == DialogResult.OK && Int32.TryParse(cpd.GetCodePage(), out result) && result > -1 && result < 65536 && CheckCodepage(result)) { lines = File.ReadAllLines(Fullpath, Encoding.GetEncoding(result)); } else { return(LOADRESULT_FALSE); // silently fail. } } break; } } string line, head, copy; // 1. test for fatal errors -> if (lines.Length > LINE_VERSION) { line = lines[LINE_VERSION].Trim(); } else { line = String.Empty; } if (line != gs.TwodaVer && line != "2DA\tV2.0") // tab is not fatal - autocorrect it later { head = "The 2da-file contains an incorrect version header on its 1st line."; copy = Fullpath + Environment.NewLine + Environment.NewLine + line; using (var ib = new Infobox(Infobox.Title_error, head, copy, InfoboxType.Error, InfoboxButtons.Abort)) { ib.ShowDialog(_f); } return(LOADRESULT_FALSE); } if (lines.Length > LINE_COLABEL) { line = lines[LINE_COLABEL].Trim(); } else { line = String.Empty; } if (line.Length == 0) { head = "The 2da-file does not have any fields. Yata wants a file to have at least one colhead label on its 3rd line."; using (var ib = new Infobox(Infobox.Title_error, head, Fullpath, InfoboxType.Error, InfoboxButtons.Abort)) { ib.ShowDialog(_f); } return(LOADRESULT_FALSE); } bool quelch = false; // bypass warnings and try to load the file directly. // 2. test for Tabs -> if (Settings._strict && Settings._alignoutput != Settings.AoTabs) { for (int i = 0; i != lines.Length; ++i) { if (i != LINE_DEFAULT && lines[i].Contains("\t")) { head = "Tab characters are detected in the 2da-file. They will be replaced with space characters (or deleted where redundant) if the file is saved."; switch (ShowLoadWarning(head, Fullpath)) { case DialogResult.Cancel: return(LOADRESULT_FALSE); case DialogResult.OK: quelch = true; goto case DialogResult.Retry; case DialogResult.Retry: loadresult = LOADRESULT_CHANGED; break; } break; } } } bool autordered = false; bool whitespacewarned = false; string tr; int id = -1; int total = lines.Length; if (total < LINE_COLABEL + 1) { total = LINE_COLABEL + 1; // scan at least 3 'lines' in the file } // 3. test for ignorable/recoverable errors -> for (int i = LINE_VERSION; i != total; ++i) { if (i < lines.Length) { line = lines[i]; } else { line = String.Empty; } switch (i) { case LINE_VERSION: if (!quelch && Settings._strict) { if (line != (tr = line.Trim())) { head = "The 1st line (version header) has extraneous whitespace. It will be trimmed if the file is saved."; copy = Fullpath + Environment.NewLine + Environment.NewLine + line; switch (ShowLoadWarning(head, copy)) { case DialogResult.Cancel: return(LOADRESULT_FALSE); case DialogResult.OK: quelch = true; goto case DialogResult.Retry; case DialogResult.Retry: loadresult = LOADRESULT_CHANGED; break; } } if (!quelch && tr.Contains("\t")) { head = "The 1st line (version header) contains a tab-character. It will be corrected if the file is saved."; copy = Fullpath + Environment.NewLine + Environment.NewLine + tr; switch (ShowLoadWarning(head, copy)) { case DialogResult.Cancel: return(LOADRESULT_FALSE); case DialogResult.OK: quelch = true; goto case DialogResult.Retry; case DialogResult.Retry: loadresult = LOADRESULT_CHANGED; break; } } // if (!quelch && tr.Contains(" ")) // don't bother. This is a fatal error above. // { // head = "The header on the first line contains redundant spaces. It will be corrected if the file is saved."; // copy = Fullpath + Environment.NewLine + Environment.NewLine // + tr; // // switch (ShowLoadWarning(head, copy)) // { // case DialogResult.Cancel: // return LOADRESULT_FALSE; // // case DialogResult.OK: // quelch = true; // goto case DialogResult.Retry; // // case DialogResult.Retry: // loadresult = LOADRESULT_CHANGED; // break; // } // } } break; case LINE_DEFAULT: tr = line.Trim(); if (!quelch && Settings._strict && line != tr) { head = "The 2nd line (default value) has extraneous whitespace. It will be trimmed if the file is saved."; copy = Fullpath + Environment.NewLine + Environment.NewLine + line; switch (ShowLoadWarning(head, copy)) { case DialogResult.Cancel: return(LOADRESULT_FALSE); case DialogResult.OK: quelch = true; goto case DialogResult.Retry; case DialogResult.Retry: loadresult = LOADRESULT_CHANGED; break; } } if (tr.StartsWith("DEFAULT:", StringComparison.Ordinal)) // do not 'strict' this feedback -> { _defaultval = tr.Substring(8).TrimStart(); if (_defaultval.Length == 0) { if (!quelch) { head = "The Default is blank. The 2nd line (default value) will be cleared if the file is saved."; copy = Fullpath + Environment.NewLine + Environment.NewLine + tr; switch (ShowLoadWarning(head, copy)) { case DialogResult.Cancel: return(LOADRESULT_FALSE); case DialogResult.OK: quelch = true; goto case DialogResult.Retry; case DialogResult.Retry: if (Settings._strict) { loadresult = LOADRESULT_CHANGED; } break; } } } else { InputDialog.SpellcheckDefaultval(ref _defaultval, true); if (!quelch && Settings._strict && tr != gs.Default + _defaultval) { head = "The Default on the 2nd line has been changed."; copy = Fullpath + Environment.NewLine + Environment.NewLine + gs.Default + _defaultval; switch (ShowLoadWarning(head, copy)) { case DialogResult.Cancel: return(LOADRESULT_FALSE); case DialogResult.OK: quelch = true; goto case DialogResult.Retry; case DialogResult.Retry: loadresult = LOADRESULT_CHANGED; break; } } } } else { _defaultval = String.Empty; if (!quelch && Settings._strict && tr.Length != 0) { head = "The 2nd line (default value) in the 2da contains garbage. It will be cleared if the file is saved."; copy = Fullpath + Environment.NewLine + Environment.NewLine + line; //.Replace("\t", "\u2192") switch (ShowLoadWarning(head, copy)) { case DialogResult.Cancel: return(LOADRESULT_FALSE); case DialogResult.OK: quelch = true; goto case DialogResult.Retry; case DialogResult.Retry: loadresult = LOADRESULT_CHANGED; break; } } } break; case LINE_COLABEL: tr = line.TrimEnd(); // TODO: check for redundant whitespace at the start of the line also // flag Changed if found ... if (!quelch && Settings._strict && line != tr) { head = "The 3nd line (colhead labels) has extraneous whitespace. It will be trimmed if the file is saved."; copy = Fullpath + Environment.NewLine + Environment.NewLine + line; switch (ShowLoadWarning(head, copy)) { case DialogResult.Cancel: return(LOADRESULT_FALSE); case DialogResult.OK: quelch = true; goto case DialogResult.Retry; case DialogResult.Retry: loadresult = LOADRESULT_CHANGED; break; } } if (!quelch && Settings._strict && // line.Length shall not be 0 line[0] != 32 && // space !(line[0] == 9 && Settings._alignoutput == Settings.AoTabs)) // tab { // NOTE: This is an autocorrecting error and there was // really no need for the Bioware spec. to indent the 3rd line. // The fact it's the 3rd line alone is enough to signify // that the line is the colhead fields. head = "The 3rd line (colhead labels) is not indented properly. It will be corrected if the file is saved."; copy = Fullpath + Environment.NewLine + Environment.NewLine + line; switch (ShowLoadWarning(head, copy)) { case DialogResult.Cancel: return(LOADRESULT_FALSE); case DialogResult.OK: quelch = true; goto case DialogResult.Retry; case DialogResult.Retry: loadresult = LOADRESULT_CHANGED; break; } } tr = tr.TrimStart(); if (!quelch) { var chars = new List <char>(); // warn only once per character foreach (char character in tr) { // construct this condition in the positive and put a NOT in front of it // to avoid logical pretzels ... if (!chars.Contains(character) && !(character == 32 || // space (character == 9 && // tab (Settings._alignoutput == Settings.AoTabs || !Settings._strict)) || Util.isAsciiAlphanumericOrUnderscore(character) || (!Settings._strict && Util.isPrintableAsciiNotDoublequote(character)))) { head = "Detected a suspect character in the colhead labels ..."; copy = Fullpath + Environment.NewLine + Environment.NewLine + character; // + (character == 9 ? "\u2192" : character.ToString()); switch (ShowLoadWarning(head, copy)) { case DialogResult.Cancel: return(LOADRESULT_FALSE); case DialogResult.OK: quelch = true; break; case DialogResult.Retry: chars.Add(character); break; } } if (quelch) { break; } } } Fields = tr.Split(new char[0], StringSplitOptions.RemoveEmptyEntries); break; default: // line #3+ datarows -> tr = line.Trim(); if (tr.Length == 0) { if (!quelch && Settings._strict) { head = "A blank row is detected. It will be deleted if the file is saved."; copy = Fullpath; switch (ShowLoadWarning(head, copy)) { case DialogResult.Cancel: return(LOADRESULT_FALSE); case DialogResult.OK: quelch = true; goto case DialogResult.Retry; case DialogResult.Retry: loadresult = LOADRESULT_CHANGED; break; } } } else { ++id; if (!quelch && Settings._strict && !whitespacewarned && line != tr) { whitespacewarned = true; head = "At least one row has extraneous whitespace. This will be trimmed if the file is saved."; copy = Fullpath + Environment.NewLine + Environment.NewLine + "id " + id; switch (ShowLoadWarning(head, copy)) { case DialogResult.Cancel: return(LOADRESULT_FALSE); case DialogResult.OK: quelch = true; goto case DialogResult.Retry; case DialogResult.Retry: loadresult = LOADRESULT_CHANGED; break; } } string[] celltexts = ParseTableRow(tr); if (!quelch) // show these warnings even if not Strict. { // test for id int result; if (!Int32.TryParse(celltexts[0], out result)) { head = "The 2da-file contains an id that is not an integer."; } else if (result != id) { head = "The 2da-file contains an id that is out of order."; } else { head = null; } if (head != null) // show this warning even if Autorder true - table shall be flagged Changed { copy = Fullpath + Environment.NewLine + Environment.NewLine + "id " + id + " \u2192 " + celltexts[0]; switch (ShowLoadWarning(head, copy)) { case DialogResult.Cancel: return(LOADRESULT_FALSE); case DialogResult.OK: quelch = true; break; } } // test for matching cell-fields under cols if (!quelch) { if (celltexts.Length != Fields.Length + 1) { head = "The 2da-file contains fields that do not align with its cols."; copy = Fullpath + Environment.NewLine + Environment.NewLine + "Colcount " + (Fields.Length + 1) + Environment.NewLine + "id " + id + " fields \u2192 " + celltexts.Length; switch (ShowLoadWarning(head, copy)) { case DialogResult.Cancel: return(LOADRESULT_FALSE); case DialogResult.OK: quelch = true; break; } } } // test for an odd quantity of double-quote characters if (!quelch) { int quotes = 0; foreach (char character in tr) { if (character == '"') { ++quotes; } } if (quotes % 2 == 1) { head = "A row contains an odd quantity of double-quote characters. This could be bad ..."; copy = Fullpath + Environment.NewLine + Environment.NewLine + "id " + id; switch (ShowLoadWarning(head, copy)) { case DialogResult.Cancel: return(LOADRESULT_FALSE); case DialogResult.OK: quelch = true; break; } } } } if (Settings._autorder && id.ToString(CultureInfo.InvariantCulture) != celltexts[0]) { celltexts[0] = id.ToString(CultureInfo.InvariantCulture); autordered = true; } // NOTE: Tests for well-formed fields will be done later so that their // respective cells can be flagged as loadchanged if applicable. _rows.Add(celltexts); } break; } } if (autordered) { using (var ib = new Infobox(Infobox.Title_infor, "Row ids have been corrected.")) ib.ShowDialog(_f); loadresult = LOADRESULT_CHANGED; } if (_rows.Count == 0) // add a row of stars so grid is not left blank -> { var cells = new string[Fields.Length + 1]; // NOTE: 'Fields' does not contain the ID-col. int c = 0; if (Settings._autorder) { cells[c++] = "0"; } for (; c <= Fields.Length; ++c) { cells[c] = gs.Stars; } _rows.Add(cells); return(LOADRESULT_CHANGED); // flag the Table as changed } return(loadresult); }
/// <summary> /// Handles several it-clicks that write a <c><see cref="YataGrid"/></c> /// to a 2da-file. /// </summary> /// <param name="sender"> /// <list type="bullet"> /// <item><c><see cref="it_Save"/></c></item> /// <item><c><see cref="tabit_Save"/></c></item> /// <item><c><see cref="it_SaveAs"/></c></item> /// <item><c><see cref="it_SaveAll"/></c></item> /// <item><c>null</c></item> /// </list></param> /// <param name="e"></param> /// <remarks>Called by /// <list type="bullet"> /// <item>File|Save <c>[Ctrl+s]</c></item> /// <item>tab|Save</item> /// <item>File|SaveAs <c>[Ctrl+e]</c> <c><see cref="fileclick_SaveAs()">fileclick_SaveAs()</see></c></item> /// <item>File|SaveAll <c>[Ctrl+a]</c> <c><see cref="fileclick_SaveAll()">fileclick_SaveAll()</see></c></item> /// <item><c><see cref="VerifyCurrentFileState()">VerifyCurrentFileState()</see></c></item> /// </list></remarks> internal void fileclick_Save(object sender, EventArgs e) { bool overwrite; // force a Readonly file to overwrite itself (only if invoked by SaveAs) bool bypassReadonly; if (sender == it_SaveAs) { _table = Table; // '_pfeT' is set by caller overwrite = (_pfeT == _table.Fullpath); bypassReadonly = false; } else if (sender == it_SaveAll) { // '_table' and '_pfeT' are set by caller overwrite = false; bypassReadonly = false; } else // is rego-save or tab-save or 'FileWatcherDialog' save { _table = Table; _pfeT = _table.Fullpath; overwrite = false; if (sender == it_Save || sender == tabit_Save) { bypassReadonly = false; } else { bypassReadonly = true; // only 'VerifyCurrentFileState()' gets to bypass Readonly. } } _warned = false; if (!_table.Readonly || bypassReadonly || (overwrite && SaveWarning("The 2da-file is opened as readonly."))) { // if ((_table._sortcol == 0 && _table._sortdir == YataGrid.SORT_ASC) // || SaveWarning("The 2da is not sorted by ascending ID.")) // { if (CheckRowOrder() || SaveWarning("Faulty row ids are detected.")) { _table.Fullpath = _pfeT; SetTitlebarText(); if (!_isCreate) // stuff that's unneeded and/or unwanted when creating a 2da -> { if (overwrite) { _table.Readonly = false; // <- IMPORTANT: If a file that was opened Readonly is saved } // *as itself* it loses its Readonly flag. _table.Changed = false; _table._ur.ResetSaved(); _table.ClearLoadchanged(); // this toggles YataGrid._init - don't do that when creating a 2da if (_table == Table) { _table.Invalidator(YataGrid.INVALID_GRID | YataGrid.INVALID_FROZ); } } FileOutput.Write(_table); } // } } else if (!_warned) { using (var ib = new Infobox(Infobox.Title_error, "The 2da-file is opened as readonly.", null, InfoboxType.Error)) { ib.ShowDialog(this); } } }
/// <summary> /// Handles it-click to reload the current table. Requests /// user-confirmation if data has changed etc. /// </summary> /// <param name="sender"> /// <list type="bullet"> /// <item><c><see cref="it_Reload"/></c></item> /// <item><c><see cref="tabit_Reload"/></c></item> /// <item><c>null</c></item> /// </list></param> /// <param name="e"></param> /// <remarks>Called by /// <list type="bullet"> /// <item>File|Reload <c>[Ctrl+r]</c></item> /// <item>tab|Reload</item> /// <item><c><see cref="VerifyCurrentFileState()">VerifyCurrentFileState()</see></c></item> /// </list></remarks> internal void fileclick_Reload(object sender, EventArgs e) { if (File.Exists(Table.Fullpath)) // check 'Table.Fullpath' in case user presses [Ctrl+r] after deleting the 2da-file on the hardrive. { bool reload = !Table.Changed; if (!reload) { using (var ib = new Infobox(Infobox.Title_alert, "Data has changed. Okay to reload ...", null, InfoboxType.Warn, InfoboxButtons.CancelYes)) { reload = ib.ShowDialog(this) == DialogResult.OK; } } if (reload) { Obfuscate(); if (_diff1 == Table) { _diff1 = null; } else if (_diff2 == Table) { _diff2 = null; } _bypassVerifyFile = true; int result = Table.LoadTable(); if (result != YataGrid.LOADRESULT_FALSE) { DrawRegulator.SuspendDrawing(Table); Table._ur.Clear(); it_freeze1.Checked = it_freeze2.Checked = false; Table.Init(result == YataGrid.LOADRESULT_CHANGED, true); if (Table.Propanel != null) { Table.Controls.Remove(Table.Propanel); Table.Propanel = null; } DrawRegulator.ResumeDrawing(Table); } else { Table.Changed = false; // bypass Close warn fileclick_ClosePage(sender, e); } _bypassVerifyFile = false; if (Table != null) { Obfuscate(false); VerifyCurrentFileState(); } } } else { using (var ib = new Infobox(Infobox.Title_error, "File does not exist.", Table.Fullpath, InfoboxType.Error)) { ib.ShowDialog(this); } } }
static void Main(string[] args) { logfile.CreateLog(); // NOTE: The logfile works in debug-builds only. // To write a line to the logfile: // logfile.Log("what you want to know here"); // // The logfile ought appear in the directory with the executable. //string st = String.Empty; // debug -> //foreach (var arg in args) // st += Environment.NewLine + arg; //logfile.Log("Main() args= " + st); //logfile.Log(Environment.NewLine + "--------"); //string a = String.Empty; //for (int i = 0; i != args.Length; ++i) // a += ";" + args[i] + ";"; //logfile.Log("Main() args=" + a); Process proc = null; if (args.Length != 0) // else start a new instance of Yata { string label = Process.GetCurrentProcess().ProcessName; //int id = current.Id; //logfile.Log(". current process= " + id + " : " + label + " h= " + current.Handle); DateTime dt = DateTime.Now, dtTest; //logfile.Log(". dt= " + dt.Minute + ":" + dt.Second + ":" + dt.Millisecond); Process[] processes = Process.GetProcesses(); //logfile.Log(". qty processes= " + processes.Length); foreach (var process in processes) { //logfile.Log(". . process= " + process.Id + "\t: " + process.ProcessName); if (process.MainWindowHandle != IntPtr.Zero && // NOTE: 'current' won't have a MainWindow (ie. bypass current proc.) process.ProcessName == label) { //logfile.Log(". . . found other Yata process"); //logfile.Log(". . . h= " + process.Handle + " MainWindowHandle= " + process.MainWindowHandle); // find longest-running instance -> use it dtTest = process.StartTime; //logfile.Log(". . . dtTest= " + dtTest.Minute + ":" + dtTest.Second + ":" + dtTest.Millisecond); if (dtTest < dt) { //logfile.Log(". . . . is less"); dt = dtTest; proc = process; } //logfile.Log(". . . dt= " + dt); //logfile.Log(". . . proc h= " + proc.MainWindowHandle); } } } if (proc != null) { //logfile.Log(". FOUND INSTANCE proc= " + proc.Id + " : " + proc.ProcessName); // https://www.codeproject.com/Tips/1017834/How-to-Send-Data-from-One-Process-to-Another-in-Cs IntPtr ptrCopyData = IntPtr.Zero; try { string arg = args[0]; // create the data structure and fill with data var copyData = new Crap.COPYDATASTRUCT(); copyData.dwData = new IntPtr(Crap.CopyDataStructType); // just a number to identify the data type copyData.cbData = arg.Length + 1; // one extra byte for the \0 character copyData.lpData = Marshal.StringToHGlobalAnsi(arg); // allocate memory for the data and copy ptrCopyData = Marshal.AllocCoTaskMem(Marshal.SizeOf(copyData)); Marshal.StructureToPtr(copyData, ptrCopyData, false); // send the message IntPtr ptrWnd = proc.MainWindowHandle; Crap.SendMessage(ptrWnd, Crap.WM_COPYDATA, IntPtr.Zero, ptrCopyData); } catch (Exception ex) { using (var ib = new Infobox(Infobox.Title_excep, "Failed to send file to Yata.", ex.ToString(), InfoboxType.Error)) { ib.ShowDialog(); // this better not throw ... } } finally { // free the allocated memory after execution has returned if (ptrCopyData != IntPtr.Zero) { Marshal.FreeCoTaskMem(ptrCopyData); } } } else { if (args.Length != 0) { //logfile.Log(". pass arg to new instance"); Yata.PfeLoad = args[0]; } //else logfile.Log(". no args - start new instance"); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); // ie, use GDI aka TextRenderer class. (perhaps, read: // perhaps depends on the Control that's being drawn) Application.Run(new Yata()); Yata.PfeLoad = null; } }
/// <summary> /// Creates the <c><see cref="Row">Rows</see></c> and adds /// <c><see cref="Cell">Cells</see></c> to each <c>Row</c>. Also sets /// <c><see cref="Cell.loadchanged">Cell.loadchanged</see></c> if a /// cell-field's text was altered/corrected while loading the 2da for /// this <c>YataGrid</c>. /// </summary> void CreateRows() { RowCount = _rows.Count; bool changed = false, loadchanged; string text; bool isLoadchanged = false; for (int r = 0; r != RowCount; ++r) { changed = changed || _rows[r].Length > ColCount; // flag Changed if any field(s) get cut off. Rows.Add(new Row(r, ColCount, (r % 2 == 0) ? Brushes.Alice : Brushes.Bob, this)); for (int c = 0; c != ColCount; ++c) { loadchanged = false; if (c < _rows[r].Length) { text = _rows[r][c]; if (VerifyText(ref text, true)) { changed = loadchanged = isLoadchanged = true; } } else { text = gs.Stars; changed = loadchanged = isLoadchanged = true; } (this[r, c] = new Cell(r, c, text)).loadchanged = loadchanged; } } if (isLoadchanged) // inform user regardless of Strict setting -> { using (var ib = new Infobox(Infobox.Title_infor, "Cell-texts changed.")) ib.ShowDialog(_f); } Changed |= changed; _rows.Clear(); // done w/ '_rows' int w, wT; // adjust col-widths based on fields -> for (int c = 0; c != ColCount; ++c) { w = _wId; // start each col at min colwidth for (int r = 0; r != RowCount; ++r) { if ((text = this[r, c].text) == gs.Stars) // bingo. { wT = _wStars; } else { wT = YataGraphics.MeasureWidth(text, Font); } this[r, c]._widthtext = wT; if ((wT += _padHori * 2) > w) { w = wT; } } Cols[c].width(w); } // var threads = new Thread[ColCount]; // for (int c = 0; c != ColCount; ++c) // { // int cT = c; // threads[c] = new Thread(() => doCol(cT)); // //logfile.Log("c= " + c + " IsBackground= " + threads[c].IsBackground); // default false // threads[c].IsBackground = true; // threads[c].Start(); // } // int procs = Environment.ProcessorCount; // logfile.Log("ProcessorCount= " + procs); // var threads = new Thread[procs]; // for (int i = 0; i != procs; ++i) // { // threads[i] = new Thread(()=> doCol(0, RowCount/procs)); // wont work - a lone doCol() method would be totally thread unsafe. // } // int c0 = 0; // int c1 = ColCount / 4; // int c2 = ColCount / 2; // int c3 = ColCount * 3 / 4; // int c4 = ColCount; // // logfile.Log("c0= " + c0); // logfile.Log("c1= " + c1); // logfile.Log("c2= " + c2); // logfile.Log("c3= " + c3); // logfile.Log("c4= " + c4); // // var threads = new Thread[4]; // threads[0] = new Thread(()=> doCol0(c0,c1)); // threads[0].IsBackground = true; // threads[0].Start(); // threads[1] = new Thread(()=> doCol1(c1,c2)); // threads[1].IsBackground = true; // threads[1].Start(); // threads[2] = new Thread(()=> doCol2(c2,c3)); // threads[2].IsBackground = true; // threads[2].Start(); // threads[3] = new Thread(()=> doCol3(c3,c4)); // threads[3].IsBackground = true; // threads[3].Start(); // // foreach (var thread in threads) // thread.Join(); }