private void WriteSummaryFile(string _filename_w_ext, ref StringBuilder _sb) { if (_sb == null) { return; } if (string.IsNullOrEmpty(_filename_w_ext)) { return; } DXFDistributedDecoder.FinalizeFileContent(ref _sb); string content_summary = _sb.ToString(); try { using (FileStream fs = File.Create(_filename_w_ext)) { byte[] content_B = System.Text.Encoding.UTF8.GetBytes(content_summary); fs.Write(content_B, 0, content_B.Length); } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error saving simultan file: " + _filename_w_ext, MessageBoxButton.OK, MessageBoxImage.Error); } finally { this.write_in_progress = true; } }
public void ReleaseFiles(bool _save_changes) { if (_save_changes) { // modifies this.loaded_file_records this.SaveFiles(); } // release locks on files StringBuilder sb_new = new StringBuilder(); foreach (PartialFileRecord fr in this.loaded_file_records) { if (DXFDistributedDecoder.HasEditingRights(this.manager, fr.Manager)) { fr.NrLocks--; } fr.AddToExport(ref sb_new); } // ... release the watcher this.ReleaseWatcher(); // ... modify the summary file accordingly this.WriteSummaryFile(this.SummaryFileName, ref sb_new); // reset internal state this.SetFileManagementContent(null, ComponentManagerType.GUEST); this.COMP_Factory.ClearRecord(); }
public void AddToExport(ref StringBuilder _sb) { if (_sb == null) { return; } _sb.AppendLine(((int)ParamStructCommonSaveCode.ENTITY_START).ToString()); // 0 string path_rel = DXFDistributedDecoder.ExtractRelativeNameFromAbsolute(this.FileName); _sb.AppendLine(path_rel); // file name _sb.AppendLine(((int)ParamStructCommonSaveCode.ENTITY_KEY).ToString()); // 904 _sb.AppendLine(ComponentUtils.ComponentManagerTypeToLetter(this.Manager)); // role that can modify the file _sb.AppendLine(((int)ParamStructCommonSaveCode.TIME_STAMP).ToString()); // 902 _sb.AppendLine(this.LastModified.ToString(ParamStructTypes.DT_FORMATTER)); // last modified _sb.AppendLine(((int)ParamStructCommonSaveCode.X_VALUE).ToString()); // 910 _sb.AppendLine(this.NrLocks.ToString()); // nrumber of locks on this file }
private void ParseSummaryFile() { switch (this.FCode) { case (int)ParamStructCommonSaveCode.ENTITY_START: if (this.current_file_record != null) { this.loaded_file_records.Add(this.current_file_record); } this.current_file_record = new PartialFileRecord(); this.current_file_record.FileName = DXFDistributedDecoder.ReconstructAbsolutePathFromRelative(this.SummaryFileName, this.FValue); break; case (int)ParamStructCommonSaveCode.ENTITY_KEY: if (this.current_file_record != null) { this.current_file_record.Manager = ComponentUtils.StringToComponentManagerType(this.FValue); } break; case (int)ParamStructCommonSaveCode.TIME_STAMP: if (this.current_file_record != null) { DateTime dt_tmp; bool success = DateTime.TryParse(this.FValue, ParamStructTypes.DT_FORMATTER, System.Globalization.DateTimeStyles.None, out dt_tmp); if (success) { this.current_file_record.LastModified = dt_tmp; } } break; case (int)ParamStructCommonSaveCode.X_VALUE: if (this.current_file_record != null) { int nr_locks; bool success = Int32.TryParse(this.FValue, out nr_locks); this.current_file_record.NrLocks = nr_locks; } break; } }
/// <summary> /// Attempts to merge two summary files. It compares the file records they contain by NAME only. /// Assumes that if a file is in RECORD 1 (own) but not in the RECORD 2 (from other source) and its manager is the current user of RECORD 1, it should be kept. /// If a file is in RECORD 1 (own) but not in the RECORD 2 (from other source) and its manager is NOT the current user of RECORD 1, the file should be deleted. This means /// that references or mappings to components in it made from components in other files will be lost. /// </summary> /// <param name="_dec_1_to_override"></param> /// <param name="_dec_2"></param> /// <returns></returns> public static ProjectMergeResult MergeSummaryFiles(DXFDistributedDecoder _dec_1_to_override, DXFDistributedDecoder _dec_2) { if (_dec_1_to_override == null || _dec_2 == null) { return(ProjectMergeResult.NULL_INPUT_ERROR); } bool ok_1 = _dec_1_to_override.LoadSummaryFileOnly(); bool ok_2 = _dec_2.LoadSummaryFileOnly(); if (!ok_1 || !ok_2) { return(ProjectMergeResult.IO_ERROR); } if (!(Utils.StringUtils.UnQualifiedFileNamesEqual(_dec_1_to_override.SummaryFileName, _dec_2.SummaryFileName))) { return(ProjectMergeResult.PROJECT_FILE_NAME_MISMATCH); } // sort the file records SortedDictionary <ComponentManagerType, PartialFileRecord> sorted_records_1 = new SortedDictionary <ComponentManagerType, PartialFileRecord>(); foreach (PartialFileRecord pfr in _dec_1_to_override.loaded_file_records) { sorted_records_1.Add(pfr.Manager, pfr); } SortedDictionary <ComponentManagerType, PartialFileRecord> sorted_records_2 = new SortedDictionary <ComponentManagerType, PartialFileRecord>(); foreach (PartialFileRecord pfr in _dec_2.loaded_file_records) { sorted_records_2.Add(pfr.Manager, pfr); } // compare the file records List <PartialFileRecord> merged_records = new List <PartialFileRecord>(); for (int i = 0; i < Enum.GetNames(typeof(ComponentManagerType)).Length; i++) { ComponentManagerType m = (ComponentManagerType)i; if (sorted_records_1.ContainsKey(m) && !sorted_records_2.ContainsKey(m)) { if (m != _dec_1_to_override.manager) { // someone else deleted this record -> so skip it } else { // possibly I created this record -> so keep it merged_records.Add(sorted_records_1[m]); } } else if (!sorted_records_1.ContainsKey(m) && sorted_records_2.ContainsKey(m)) { if (m != _dec_1_to_override.manager) { // someone else created this record -> so KEEP it merged_records.Add(sorted_records_2[m]); } else { // possibly I deleted this record -> so SKIP it } } else if (sorted_records_1.ContainsKey(m) && sorted_records_2.ContainsKey(m)) { if (!(Utils.StringUtils.UnQualifiedFileNamesEqual(sorted_records_1[m].FileName, sorted_records_2[m].FileName))) { return(ProjectMergeResult.SINGLE_FILE_NAME_MISMATCH); } // take own record merged_records.Add(sorted_records_1[m]); } } // re-write the summary file _dec_1_to_override.loaded_file_records = merged_records; StringBuilder sb_new = new StringBuilder(); foreach (PartialFileRecord fr in _dec_1_to_override.loaded_file_records) { // fr.NrLocks = (DXFDistributedDecoder.HasEditingRights(_dec_1_to_override.manager, fr.Manager)) ? 1 : 0; fr.NrLocks = 0; fr.AddToExport(ref sb_new); } _dec_1_to_override.WriteSummaryFile(_dec_1_to_override.SummaryFileName, ref sb_new); return(ProjectMergeResult.OK); }
public void LoadFiles(bool _use_a_watcher = true) { if (!File.Exists(this.SummaryFileName)) { return; } try { // read and parse file this.FStream = new StreamReader(this.SummaryFileName); bool reached_eof = false; while (this.HasNext()) { this.Next(); if (this.FValue == ParamStructTypes.EOF) { reached_eof = true; if (this.current_file_record != null) { this.loaded_file_records.Add(this.current_file_record); } this.ReleaseRessources(); break; } this.ParseSummaryFile(); } if (!reached_eof) { this.ReleaseRessources(); } // load components from the files according to user role and ... StringBuilder sb_new = new StringBuilder(); DXFDecoder dxf_decoder = new DXFDecoder(this.MV_Factory, this.P_Factory, this.COMP_Factory); foreach (PartialFileRecord fr in this.loaded_file_records) { if (File.Exists(fr.FileName)) { // adjust the locks on the file (06.02.2017) bool lock_edit = true; this.nr_locks_record[(int)fr.Manager] = fr.NrLocks; if (DXFDistributedDecoder.HasEditingRights(this.manager, fr.Manager)) { lock_edit = (fr.NrLocks > 0); this.nr_locks_record[(int)fr.Manager] = fr.NrLocks + 1; fr.NrLocks++; } dxf_decoder.LoadFromFile(fr.FileName, lock_edit); } fr.AddToExport(ref sb_new); } dxf_decoder.DoDeferredOperations(); // connects components and networks saved in different partial files this.COMP_Factory.RestoreReferencesWithinRecord(); this.COMP_Factory.MakeParameterOutsideBoundsVisible(); // ... modify the summary file accordingly this.WriteSummaryFile(this.SummaryFileName, ref sb_new); this.FileRecordsOpen = true; // ... set a watcher on the file if (_use_a_watcher) { this.SetWatcher(); } } catch (Exception ex) { this.ReleaseRessources(); MessageBox.Show(ex.Message, "Error reading simultan file: " + this.SummaryFileName, MessageBoxButton.OK, MessageBoxImage.Error); } }
// writing the summary file (smn: SIMULTAN) // ---------------------------------------------------------------------- // code 0 : ENTITY_START // value : file name (e.g. architecture: 'ComponentRecord_01ARC.dxf') // code 904: ENTITY_KEY // value : role that can open the file with writing access (e.g. administrator: '@') // code 902: TIME_STAMP // value : last modified // code 910: X_VALUE // value : 1 if locked, 0 if unlocked (this is set during file open, according to role) // only the files corsponding to the manager role can be replaced // NO !!! (added 01.09.2016) // all files can be replaced: user w/o writing access can still have supervizing or release access public void SaveFiles(bool _unlock_the_summary_file = false) { if (this.loaded_file_records.Count == 0) { return; } if (string.IsNullOrEmpty(this.SummaryFileName)) { return; } if (this.SummaryFileName.Length < 5) { return; } StringBuilder sb = new StringBuilder(); string filename_wo_ext = this.SummaryFileName.Substring(0, this.SummaryFileName.Length - ParamStructFileExtensions.FILE_EXT_PROJECT.Length - 1); // create the export stringS Dictionary <ComponentManagerType, StringBuilder> exports = this.COMP_Factory.ExportRecordDistributed(); // prepare for checking the state of the single files (init w ZERO) List <int> single_file_state = new List <int>(ComponentUtils.MANAGER_TYPE_OPENING_SIGNATURE_NONE); // save the file records foreach (var entry in exports) { // changed 01.09.2016 to allow for release and supervize actions to be recorded //if (DXFDistributedDecoder.HasEditingRights(this.manager, entry.Key)) //{ // check if the locks are set correctly, if a new single file is to be created (added 07.02.2017) if (DXFDistributedDecoder.HasEditingRights(this.manager, entry.Key) && this.nr_locks_record[(int)entry.Key] == 0) { this.nr_locks_record[(int)entry.Key] = 1; } // save file PartialFileRecord record = this.WriteSingleFile(filename_wo_ext, this.nr_locks_record[(int)entry.Key], entry.Key, entry.Value); single_file_state[(int)entry.Key] = 1; // replace record, if it exists; otherwise just add PartialFileRecord pfr = this.loaded_file_records.Find(x => x.Manager == entry.Key); if (pfr != null) { this.loaded_file_records.Remove(pfr); } this.loaded_file_records.Add(record); //} } // clean up old file records (e.g. when the writing rights of components change a record may become obsolete) for (int c = 0; c < single_file_state.Count; c++) { if (single_file_state[c] > 0) { continue; } // get rid of the record and of the file PartialFileRecord pfr = this.loaded_file_records.Find(x => x.Manager == (ComponentManagerType)c); if (pfr != null) { this.loaded_file_records.Remove(pfr); this.DeleteSingleFile(filename_wo_ext, (ComponentManagerType)c); } } // ... modify the summary file accordingly this.SingleFileNames = new List <string>(); foreach (PartialFileRecord fr in this.loaded_file_records) { if (_unlock_the_summary_file) { fr.NrLocks = 0; } fr.AddToExport(ref sb); this.SingleFileNames.Add(fr.FileName); } this.WriteSummaryFile(this.SummaryFileName, ref sb); }
private void OnSummaryFileChanged(object sender, FileSystemEventArgs e) { // reload the summary file to update the number of locks if (this.SummaryFileName == null) { return; } if (!File.Exists(this.SummaryFileName)) { return; } string uqfn = DXFDistributedDecoder.GetUnQualifiedFileName(this.SummaryFileName); // prepare to calculate the difference btw the previous and current state of the summary file List <PartialFileRecord> prev_loaded_file_records = new List <PartialFileRecord>(this.loaded_file_records); // reset this.current_file_record = null; this.loaded_file_records = new List <PartialFileRecord>(); // debug string prefix = "[*]"; #if DEBUG prefix = "[D]"; #else prefix = "[R]"; #endif // re-load try { // read and parse file using (FileStream fs = new FileStream(this.SummaryFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { this.FStream = new StreamReader(fs); bool reached_eof = false; while (this.HasNext()) { this.Next(); if (this.FValue == ParamStructTypes.EOF) { reached_eof = true; if (this.current_file_record != null) { this.loaded_file_records.Add(this.current_file_record); } this.ReleaseRessources(); break; } this.ParseSummaryFile(); } if (!reached_eof) { this.ReleaseRessources(); } } foreach (PartialFileRecord fr in this.loaded_file_records) { if (File.Exists(fr.FileName)) { this.nr_locks_record[(int)fr.Manager] = fr.NrLocks; } } // calculate difference if (this.write_in_progress) { this.write_in_progress = false; } else { PartialRecordState diff = PartialFileRecord.CompareRecordStates(prev_loaded_file_records, this.loaded_file_records); if (diff == PartialRecordState.UPDATED) { MessageBox.Show("Another user updated the project!", prefix + "Project File State: " + uqfn, MessageBoxButton.OK, MessageBoxImage.Warning); } else if (diff == PartialRecordState.STRUCTURE_CHANGED) { MessageBox.Show("Another user changed the structure of the project!", prefix + "Project File State: " + uqfn, MessageBoxButton.OK, MessageBoxImage.Warning); } } } catch (System.IO.IOException ioex) { // happens when another process is using the file (e.g. GIT repo copying process) // do not user a watcher when saving with GIT - not necessary this.ReleaseWatcher(); string io_tmp = ioex.Message; } catch (Exception ex) { this.ReleaseRessources(); string tmp = ex.Message; //MessageBox.Show(ex.Message, prefix + "Error re-reading simultan file: " + uqfn, // MessageBoxButton.OK, MessageBoxImage.Error); } }