/// <summary> /// Shows a <see cref="SaveFileDialog"/> allowing the user to enter or select a scenario /// section file to save to.</summary> /// <param name="section"> /// A <see cref="ScenarioSection"/> value indicating the scenario section that the file /// represents.</param> /// <param name="file"> /// The file initially selected in the dialog, relative to the current <see /// cref="FilePaths.CommonFolder"/>.</param> /// <returns> /// A <see cref="RootedPath"/> wrapping the absolute file path selected by the user, or an /// empty path if the user cancelled the dialog.</returns> /// <exception cref="InvalidEnumArgumentException"> /// <paramref name="section"/> is not a valid <see cref="ScenarioSection"/> value. /// </exception> /// <remarks> /// The specified <paramref name="file"/> may be a null reference or an empty string to /// indicate that no file should be initially selected. The dialog initially shows the /// default folder for the specified <paramref name="section"/>, unless overriden by an /// absolute <paramref name="file"/> path.</remarks> public static RootedPath SaveSectionDialog(ScenarioSection section, string file) { string directory = FilePaths.GetSectionFolder(section); return(SaveDialog(Strings.TitleSectionSave, Strings.FilterSection, 1, "xml", FilePaths.CreateCommonPath(file), directory)); }
/// <summary> /// Updates the "Subsection Locations" display for the specified <see /// cref="ScenarioSection"/>, which must be a subsection.</summary> /// <param name="section"> /// A <see cref="ScenarioSection"/> value indicating the scenario subsection to update. /// </param> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="section"/> equals <see cref="ScenarioSection.Master"/>.</exception> /// <exception cref="InvalidEnumArgumentException"> /// <paramref name="section"/> is not a valid <see cref="ScenarioSection"/> value. /// </exception> /// <remarks> /// <b>UpdatePath</b> updates the "Subsection Locations" line corresponding to the specified /// <paramref name="section"/> to reflect its <see cref="SectionTabItem.DataChanged"/> flag /// and its file path within the current <see cref="MasterSection"/>.</remarks> public void UpdateSubsection(ScenarioSection section) { switch (section) { case ScenarioSection.Master: ThrowHelper.ThrowArgumentOutOfRangeExceptionWithFormat("section", section, Tektosyne.Strings.ArgumentEquals, ScenarioSection.Master); break; case ScenarioSection.Images: case ScenarioSection.Variables: case ScenarioSection.Entities: case ScenarioSection.Factions: case ScenarioSection.Areas: // show or hide change marker for section int index = (int)section; var tabPage = MainWindow.Instance.GetTabPage(section); this._dataChangedLabels[index].Visibility = (tabPage.DataChanged ? Visibility.Visible : Visibility.Hidden); // show file path or "(inline)" for section RootedPath path = MasterSection.Instance.SectionPaths.GetPath(section); this._sectionPathBoxes[index].Text = (path.IsEmpty ? Global.Strings.LabelInline : path.RelativePath); break; default: ThrowHelper.ThrowInvalidEnumArgumentException( "section", (int)section, typeof(ScenarioSection)); break; } }
/// <summary> /// Shows an <see cref="OpenFileDialog"/> allowing the user to enter or select a scenario /// section file to open.</summary> /// <param name="section"> /// A <see cref="ScenarioSection"/> value indicating the scenario section that the file /// represents.</param> /// <param name="file"> /// The file initially selected in the dialog, relative to the current <see /// cref="FilePaths.CommonFolder"/>.</param> /// <param name="create"> /// <c>true</c> if the user may enter nonexistent file names; or <c>false</c> if the user /// may only select an existing file.</param> /// <returns> /// A <see cref="RootedPath"/> wrapping the absolute file path selected by the user, or an /// empty path if the user cancelled the dialog.</returns> /// <exception cref="InvalidEnumArgumentException"> /// <paramref name="section"/> is not a valid <see cref="ScenarioSection"/> value. /// </exception> /// <remarks> /// The specified <paramref name="file"/> may be a null reference or an empty string to /// indicate that no file should be initially selected. The dialog initially shows the /// default folder for the specified <paramref name="section"/>, unless overriden by an /// absolute <paramref name="file"/> path.</remarks> public static RootedPath OpenSectionDialog( ScenarioSection section, string file, bool create) { string directory = FilePaths.GetSectionFolder(section); return(OpenDialog(Strings.TitleSectionOpen, Strings.FilterSection, "xml", FilePaths.CreateCommonPath(file), directory, create)); }
/// <summary> /// Gets the default folder for the specified <see cref="ScenarioSection"/>.</summary> /// <param name="section"> /// A <see cref="ScenarioSection"/> value indicating the scenario section whose default /// folder to return.</param> /// <returns> /// The absolute path to the default folder for the specified <paramref name="section"/>. /// </returns> /// <exception cref="InvalidEnumArgumentException"> /// <paramref name="section"/> is not a valid <see cref="ScenarioSection"/> value. /// </exception> /// <remarks> /// All <see cref="ScenarioSection"/> default folders are located below <see /// cref="ScenarioFolder"/>, except for the <see cref="ScenarioSection.Images"/> section /// which is located directly below <see cref="CommonFolder"/>.</remarks> internal static string GetSectionFolder(ScenarioSection section) { switch (section) { case ScenarioSection.Areas: return(Path.Combine(ScenarioFolder, "Areas")); case ScenarioSection.Entities: return(Path.Combine(ScenarioFolder, "Entities")); case ScenarioSection.Factions: return(Path.Combine(ScenarioFolder, "Factions")); case ScenarioSection.Images: return(Path.Combine(CommonFolder, "Images")); case ScenarioSection.Master: return(ScenarioFolder); case ScenarioSection.Variables: return(Path.Combine(ScenarioFolder, "Variables")); default: ThrowHelper.ThrowInvalidEnumArgumentException( "section", (int)section, typeof(ScenarioSection)); return(null); } }
/// <summary> /// Returns the absolute path to the specified XML scenario section file.</summary> /// <param name="section"> /// A <see cref="ScenarioSection"/> value indicating the scenario section associated with /// the specified <paramref name="file"/>.</param> /// <param name="file"> /// An absolute or relative file path to an XML scenario section file.</param> /// <returns> /// A <see cref="RootedPath"/> wrapping the absolute path to the specified XML scenario /// section <paramref name="file"/>.</returns> /// <exception cref="InvalidEnumArgumentException"> /// <paramref name="section"/> is not a valid <see cref="ScenarioSection"/> value. /// </exception> /// <remarks> /// <b>GetSectionFile</b> returns the specified <paramref name="file"/> if it contains an /// absolute path; otherwise, a file path below the default folder for the specified /// <paramref name="section"/>.</remarks> public static RootedPath GetSectionFile(ScenarioSection section, string file) { string directory = GetSectionFolder(section); return(CreateCommonPath(directory, file)); }
/// <summary> /// Changes or deletes all occurrences of the specified identifier in the specified /// collection or in the entire scenario.</summary> /// <typeparam name="TValue"> /// The type of all values in the specified <paramref name="collection"/>. The type of all /// keys is assumed to be <see cref="String"/>.</typeparam> /// <param name="collection"> /// The <see cref="ICollection{T}"/> whose elements to process. This must be either an <see /// cref="IDictionary{TKey, TValue}"/> or an <see cref="IList{T}"/> holding <see /// cref="KeyValuePair{TKey, TValue}"/> elements.</param> /// <param name="oldId"> /// The identifier to remove from <paramref name="collection"/> or from the current /// scenario.</param> /// <param name="newId"><para> /// The identifier to store with all values of <paramref name="oldId"/> in <paramref /// name="collection"/> or in the current scenario. /// </para><para>-or-</para><para> /// A null reference to delete all elements with <paramref name="oldId"/> from <paramref /// name="collection"/> or from the current scenario.</para></param> /// <returns> /// <c>true</c> if the user confirmed the change; otherwise, <c>false</c>.</returns> /// <exception cref="ArgumentException"> /// <paramref name="collection"/> implements neither <see cref="IDictionary{TKey, TValue}"/> /// nor <see cref="IList{T}"/>.</exception> /// <exception cref="ArgumentNullException"> /// <paramref name="collection"/> is a null reference.</exception> /// <exception cref="ArgumentNullOrEmptyException"> /// <paramref name="oldId"/> is a null reference or an empty string.</exception> /// <remarks><para> /// <b>ProcessAllIdentifiers</b> invokes <see /// cref="MasterSection.ProcessIdentifierBySection"/> to count all occurrences of the /// specified <paramref name="oldId"/> in the current scenario. /// </para><para> /// If any occurrences are found, <b>ProcessAllIdentifiers</b> asks the user if all of them /// should be deleted or changed to the specified <paramref name="newId"/>, or only those in /// the specified <paramref name="collection"/>, or if the entire operation should be /// cancelled. /// </para><para> /// If the user cancels, <b>ProcessAllIdentifiers</b> returns <c>false</c> without changing /// any data. Otherwise, the requested changes are performed using either /// <b>ProcessIdentifierBySection</b> or <see cref="CollectionsUtility.ChangeKey"/>. In the /// first case, the Hexkit Editor tab pages managing the changed scenario sections, if any, /// are also flagged as containing unsaved changes.</para></remarks> public static bool ProcessAllIdentifiers <TValue>( ICollection <KeyValuePair <String, TValue> > collection, string oldId, string newId) { if (collection == null) { ThrowHelper.ThrowArgumentNullException("collection"); } if (String.IsNullOrEmpty(oldId)) { ThrowHelper.ThrowArgumentNullOrEmptyException("oldId"); } // check if required interface is available IDictionary <String, TValue> dictionary = collection as IDictionary <String, TValue>; IList <KeyValuePair <String, TValue> > list = collection as IList <KeyValuePair <String, TValue> >; if (dictionary == null && list == null) { ThrowHelper.ThrowArgumentException("collection", Tektosyne.Strings.ArgumentNotInTypes + "IDictionary, IList"); } // count all occurrences of old key MasterSection scenario = MasterSection.Instance; int[] found = scenario.ProcessIdentifierBySection(oldId, oldId); int totalFound = found[(int)ScenarioSection.Master]; // ask to change those occurrences, if any MessageBoxResult result = MessageBoxResult.No; if (totalFound > 1) { string dialogText = (newId == null ? Global.Strings.DialogIdentifierDelete : Global.Strings.DialogIdentifierChange); result = MessageBox.Show(MainWindow.Instance, String.Format(ApplicationInfo.Culture, dialogText, totalFound - 1), Global.Strings.TitleIdentifierReferenced, MessageBoxButton.YesNoCancel, MessageBoxImage.Question); // process identifiers throughout scenario if (result == MessageBoxResult.Yes) { scenario.ProcessIdentifierBySection(oldId, newId); for (int i = 0; i < found.Length; i++) { if (found[i] == 0) { continue; } ScenarioSection section = (ScenarioSection)i; MainWindow.Instance.GetTabPage(section).DataChanged = true; } } } // process identifiers in specified collection only if (result == MessageBoxResult.No) { if (dictionary != null) { CollectionsUtility.ProcessKey(dictionary, oldId, newId); } else { CollectionsUtility.ProcessKey(list, oldId, newId); } } // allow user to abort if a dialog came up return(result != MessageBoxResult.Cancel); }