QuickImage – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 #region Using directives
2  
3 using System;
4 using System.Windows.Forms;
5 using System.Diagnostics;
6 using System.IO;
7 using System.Globalization;
8 using System.Runtime.Serialization;
9 using System.Runtime.Serialization.Formatters.Binary;
10 using Microsoft.Win32;
11 using System.Security;
12  
13 #endregion
14  
15 // Using: in the end of this file.
16  
17 namespace DocToolkit
18 {
19 #region Class DocManager
20  
21 /// <summary>
22 /// Document manager. Makes file-related operations:
23 /// open, new, save, updating of the form title,
24 /// registering of file type for Windows Shell.
25 /// Built using the article:
26 /// Creating Document-Centric Applications in Windows Forms
27 /// by Chris Sells
28 /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnforms/html/winforms09182003.asp
29 /// </summary>
30 public class DocManager
31 {
32  
33 #region Events
34  
35 public event SaveEventHandler SaveEvent;
36 public event LoadEventHandler LoadEvent;
37 public event OpenFileEventHandler OpenEvent;
38 public event EventHandler ClearEvent;
39 public event EventHandler DocChangedEvent;
40  
41 #endregion
42  
43 #region Members
44  
45 private string fileName = "";
46 private bool dirty = false;
47  
48 private Form frmOwner;
49 private string newDocName;
50 private string fileDlgFilter;
51 private string registryPath;
52 private bool updateTitle;
53  
54 private const string registryValue = "Path";
55 private string fileDlgInitDir = ""; // file dialog initial directory
56  
57 #endregion
58  
59 #region Enum
60  
61 /// <summary>
62 /// Enumeration used for Save function
63 /// </summary>
64 public enum SaveType
65 {
66 Save,
67 SaveAs
68 }
69  
70 #endregion
71  
72 #region Constructor
73  
74 /// <summary>
75 /// Initialization
76 /// </summary>
77 /// <param name="data"></param>
78 public DocManager(DocManagerData data)
79 {
80 //frmOwner = data.FormOwner;
81 // frmOwner.Closing += OnClosing;
82  
83 updateTitle = data.UpdateTitle;
84  
85 newDocName = data.NewDocName;
86  
87 fileDlgFilter = data.FileDialogFilter;
88  
89 registryPath = data.RegistryPath;
90  
91 if (!registryPath.EndsWith("\\"))
92 registryPath += "\\";
93  
94 registryPath += "FileDir";
95  
96 // attempt to read initial directory from registry
97 RegistryKey key = Registry.CurrentUser.OpenSubKey(registryPath);
98  
99 if (key != null)
100 {
101 string s = (string)key.GetValue(registryValue);
102  
103 if (!Empty(s))
104 fileDlgInitDir = s;
105 }
106 }
107  
108 #endregion
109  
110 #region Public functions and Properties
111  
112 /// <summary>
113 /// Dirty property (true when document has unsaved changes).
114 /// </summary>
115 public bool Dirty
116 {
117 get
118 {
119 return dirty;
120 }
121 set
122 {
123 dirty = value;
124 SetCaption();
125 }
126 }
127  
128 /// <summary>
129 /// Open new document
130 /// </summary>
131 /// <returns></returns>
132 public bool NewDocument()
133 {
134 if (!CloseDocument())
135 return false;
136  
137 SetFileName("");
138  
139 if (ClearEvent != null)
140 {
141 // raise event to clear document contents in memory
142 // (this class has no idea how to do this)
143 ClearEvent(this, new EventArgs());
144 }
145  
146 Dirty = false;
147  
148 return true;
149 }
150  
151 /// <summary>
152 /// Close document
153 /// </summary>
154 /// <returns></returns>
155 public bool CloseDocument()
156 {
157 if (!this.dirty)
158 return true;
159  
160 DialogResult res = MessageBox.Show(
161 frmOwner,
162 "Save changes?",
163 Application.ProductName,
164 MessageBoxButtons.YesNoCancel,
165 MessageBoxIcon.Exclamation);
166  
167 switch (res)
168 {
169 case DialogResult.Yes: return SaveDocument(SaveType.Save);
170 case DialogResult.No: return true;
171 case DialogResult.Cancel: return false;
172 default: Debug.Assert(false); return false;
173 }
174 }
175  
176 /// <summary>
177 /// Open document
178 /// </summary>
179 /// <param name="newFileName">
180 /// Document file name. Empty - function shows Open File dialog.
181 /// </param>
182 /// <returns></returns>
183 public bool OpenDocument(string newFileName)
184 {
185 // Check if we can close current file
186 if (!CloseDocument())
187 return false;
188  
189 // Get the file to open
190 if (Empty(newFileName))
191 {
192 OpenFileDialog openFileDialog1 = new OpenFileDialog();
193 openFileDialog1.Filter = fileDlgFilter;
194 openFileDialog1.InitialDirectory = fileDlgInitDir;
195  
196 DialogResult res = openFileDialog1.ShowDialog(frmOwner);
197  
198 if (res != DialogResult.OK)
199 return false;
200  
201 newFileName = openFileDialog1.FileName;
202 fileDlgInitDir = new FileInfo(newFileName).DirectoryName;
203 }
204  
205 // Read the data
206 try
207 {
208 using (Stream stream = new FileStream(
209 newFileName, FileMode.Open, FileAccess.Read))
210 {
211 // Deserialize object from text format
212 IFormatter formatter = new BinaryFormatter();
213  
214 if (LoadEvent != null) // if caller subscribed to this event
215 {
216 SerializationEventArgs args = new SerializationEventArgs(
217 formatter, stream, newFileName);
218  
219 // raise event to load document from file
220 LoadEvent(this, args);
221  
222 if (args.Error)
223 {
224 // report failure
225 if (OpenEvent != null)
226 {
227 OpenEvent(this,
228 new OpenFileEventArgs(newFileName, false));
229 }
230  
231 return false;
232 }
233  
234 // raise event to show document in the window
235 if (DocChangedEvent != null)
236 {
237 DocChangedEvent(this, new EventArgs());
238 }
239 }
240 }
241 }
242 // Catch all exceptions which may be raised from this code.
243 // Caller is responsible to handle all other exceptions
244 // in the functions invoked by LoadEvent and DocChangedEvent.
245 catch (ArgumentNullException ex) { return HandleOpenException(ex, newFileName); }
246 catch (ArgumentOutOfRangeException ex) { return HandleOpenException(ex, newFileName); }
247 catch (ArgumentException ex) { return HandleOpenException(ex, newFileName); }
248 catch (SecurityException ex) { return HandleOpenException(ex, newFileName); }
249 catch (FileNotFoundException ex) { return HandleOpenException(ex, newFileName); }
250 catch (DirectoryNotFoundException ex) { return HandleOpenException(ex, newFileName); }
251 catch (PathTooLongException ex) { return HandleOpenException(ex, newFileName); }
252 catch (IOException ex) { return HandleOpenException(ex, newFileName); }
253  
254 // Clear dirty bit, cache the file name and set the caption
255 Dirty = false;
256 SetFileName(newFileName);
257  
258 if (OpenEvent != null)
259 {
260 // report success
261 OpenEvent(this, new OpenFileEventArgs(newFileName, true));
262 }
263  
264 // Success
265 return true;
266 }
267  
268 /// <summary>
269 /// Save file.
270 /// </summary>
271 /// <param name="type"></param>
272 /// <returns></returns>
273 public bool SaveDocument(SaveType type)
274 {
275 // Get the file name
276 string newFileName = this.fileName;
277  
278 SaveFileDialog saveFileDialog1 = new SaveFileDialog();
279 saveFileDialog1.Filter = fileDlgFilter;
280  
281 if ((type == SaveType.SaveAs) ||
282 Empty(newFileName))
283 {
284  
285 if (!Empty(newFileName))
286 {
287 saveFileDialog1.InitialDirectory = Path.GetDirectoryName(newFileName);
288 saveFileDialog1.FileName = Path.GetFileName(newFileName);
289 }
290 else
291 {
292 saveFileDialog1.InitialDirectory = fileDlgInitDir;
293 saveFileDialog1.FileName = newDocName;
294 }
295  
296 DialogResult res = saveFileDialog1.ShowDialog(frmOwner);
297  
298 if (res != DialogResult.OK)
299 return false;
300  
301 newFileName = saveFileDialog1.FileName;
302 fileDlgInitDir = new FileInfo(newFileName).DirectoryName;
303 }
304  
305 // Write the data
306 try
307 {
308 using (Stream stream = new FileStream(
309 newFileName, FileMode.Create, FileAccess.Write))
310 {
311 // Serialize object to text format
312 IFormatter formatter = new BinaryFormatter();
313  
314 if (SaveEvent != null) // if caller subscribed to this event
315 {
316 SerializationEventArgs args = new SerializationEventArgs(
317 formatter, stream, newFileName);
318  
319 // raise event
320 SaveEvent(this, args);
321  
322 if (args.Error)
323 return false;
324 }
325  
326 }
327 }
328 catch (ArgumentNullException ex) { return HandleSaveException(ex, newFileName); }
329 catch (ArgumentOutOfRangeException ex) { return HandleSaveException(ex, newFileName); }
330 catch (ArgumentException ex) { return HandleSaveException(ex, newFileName); }
331 catch (SecurityException ex) { return HandleSaveException(ex, newFileName); }
332 catch (FileNotFoundException ex) { return HandleSaveException(ex, newFileName); }
333 catch (DirectoryNotFoundException ex) { return HandleSaveException(ex, newFileName); }
334 catch (PathTooLongException ex) { return HandleSaveException(ex, newFileName); }
335 catch (IOException ex) { return HandleSaveException(ex, newFileName); }
336  
337 // Clear the dirty bit, cache the new file name
338 // and the caption is set automatically
339 Dirty = false;
340 SetFileName(newFileName);
341  
342 // Success
343 return true;
344 }
345  
346 /// <summary>
347 /// Assosciate file type with this program in the Registry
348 /// </summary>
349 /// <param name="data"></param>
350 /// <returns>true - OK, false - failed</returns>
351 public bool RegisterFileType(
352 string fileExtension,
353 string progId,
354 string typeDisplayName)
355 {
356 try
357 {
358 string s = String.Format(CultureInfo.InvariantCulture, ".{0}", fileExtension);
359  
360 // Register custom extension with the shell
361 using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(s))
362 {
363 // Map custom extension to a ProgID
364 key.SetValue(null, progId);
365 }
366  
367 // create ProgID key with display name
368 using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(progId))
369 {
370 key.SetValue(null, typeDisplayName);
371 }
372  
373 // register icon
374 using (RegistryKey key =
375 Registry.ClassesRoot.CreateSubKey(progId + @"\DefaultIcon"))
376 {
377 key.SetValue(null, Application.ExecutablePath + ",0");
378 }
379  
380 // Register open command with the shell
381 string cmdkey = progId + @"\shell\open\command";
382 using (RegistryKey key =
383 Registry.ClassesRoot.CreateSubKey(cmdkey))
384 {
385 // Map ProgID to an Open action for the shell
386 key.SetValue(null, Application.ExecutablePath + " \"%1\"");
387 }
388  
389 // Register application for "Open With" dialog
390 string appkey = "Applications\\" +
391 new FileInfo(Application.ExecutablePath).Name +
392 "\\shell";
393 using (RegistryKey key =
394 Registry.ClassesRoot.CreateSubKey(appkey))
395 {
396 key.SetValue("FriendlyCache", Application.ProductName);
397 }
398 }
399 catch (ArgumentNullException ex)
400 {
401 return HandleRegistryException(ex);
402 }
403 catch (SecurityException ex)
404 {
405 return HandleRegistryException(ex);
406 }
407 catch (ArgumentException ex)
408 {
409 return HandleRegistryException(ex);
410 }
411 catch (ObjectDisposedException ex)
412 {
413 return HandleRegistryException(ex);
414 }
415 catch (UnauthorizedAccessException ex)
416 {
417 return HandleRegistryException(ex);
418 }
419  
420 return true;
421 }
422  
423 #endregion
424  
425 #region Other Functions
426  
427  
428 /// <summary>
429 /// Hanfle exception from RegisterFileType function
430 /// </summary>
431 /// <param name="ex"></param>
432 /// <returns></returns>
433 private bool HandleRegistryException(Exception ex)
434 {
435 Trace.WriteLine("Registry operation failed: " + ex.Message);
436 return false;
437 }
438  
439 ///// <summary>
440 ///// Save initial directory to the Registry
441 ///// </summary>
442 ///// <param name="sender"></param>
443 ///// <param name="e"></param>
444 //private void OnClosing(object sender, System.ComponentModel.CancelEventArgs e)
445 //{
446 // RegistryKey key = Registry.CurrentUser.CreateSubKey(registryPath);
447 // key.SetValue(registryValue, fileDlgInitDir);
448 //}
449  
450  
451 /// <summary>
452 /// Set file name and change owner's caption
453 /// </summary>
454 /// <param name="fileName"></param>
455 private void SetFileName(string fileName)
456 {
457 this.fileName = fileName;
458 SetCaption();
459 }
460  
461 /// <summary>
462 /// Set owner form caption
463 /// </summary>
464 private void SetCaption()
465 {
466 if (!updateTitle)
467 return;
468  
469 //frmOwner.Text = string.Format(
470 // CultureInfo.InvariantCulture,
471 // "{0} - {1}{2}",
472 // Application.ProductName,
473 // Empty(this.fileName) ? newDocName : Path.GetFileName(this.fileName),
474 // this.dirty ? "*" : "");
475 }
476  
477 /// <summary>
478 /// Handle exception in OpenDocument function
479 /// </summary>
480 /// <param name="ex"></param>
481 /// <param name="fileName"></param>
482 /// <returns></returns>
483 private bool HandleOpenException(Exception ex, string fileName)
484 {
485 MessageBox.Show(frmOwner,
486 "Open File operation failed. File name: " + fileName + "\n" +
487 "Reason: " + ex.Message,
488 Application.ProductName);
489  
490 if (OpenEvent != null)
491 {
492 // report failure
493 OpenEvent(this, new OpenFileEventArgs(fileName, false));
494 }
495  
496 return false;
497 }
498  
499 /// <summary>
500 /// Handle exception in SaveDocument function
501 /// </summary>
502 /// <param name="ex"></param>
503 /// <param name="fileName"></param>
504 /// <returns></returns>
505 private bool HandleSaveException(Exception ex, string fileName)
506 {
507 MessageBox.Show(frmOwner,
508 "Save File operation failed. File name: " + fileName + "\n" +
509 "Reason: " + ex.Message,
510 Application.ProductName);
511  
512 return false;
513 }
514  
515  
516 /// <summary>
517 /// Helper function - test if string is empty
518 /// </summary>
519 /// <param name="s"></param>
520 /// <returns></returns>
521 static bool Empty(string s)
522 {
523 return s == null || s.Length == 0;
524 }
525  
526 #endregion
527  
528 }
529  
530 #endregion
531  
532 #region Delegates
533  
534 public delegate void SaveEventHandler(object sender, SerializationEventArgs e);
535 public delegate void LoadEventHandler(object sender, SerializationEventArgs e);
536 public delegate void OpenFileEventHandler(object sender, OpenFileEventArgs e);
537  
538 #endregion
539  
540 #region Class SerializationEventArgs
541  
542 /// <summary>
543 /// Serialization event arguments.
544 /// Used in events raised from DocManager class.
545 /// Class contains information required to load/save file.
546 /// </summary>
547 public class SerializationEventArgs : System.EventArgs
548 {
549 private IFormatter formatter;
550 private Stream stream;
551 private string fileName;
552 private bool errorFlag;
553  
554 public SerializationEventArgs(IFormatter formatter, Stream stream,
555 string fileName)
556 {
557 this.formatter = formatter;
558 this.stream = stream;
559 this.fileName = fileName;
560 errorFlag = false;
561 }
562  
563 public bool Error
564 {
565 get
566 {
567 return errorFlag;
568 }
569 set
570 {
571 errorFlag = value;
572 }
573 }
574  
575 public IFormatter Formatter
576 {
577 get
578 {
579 return formatter;
580 }
581 }
582  
583 public Stream SerializationStream
584 {
585 get
586 {
587 return stream;
588 }
589 }
590 public string FileName
591 {
592 get
593 {
594 return fileName;
595 }
596 }
597 }
598  
599 #endregion
600  
601 #region Class OpenFileEventArgs
602  
603 /// <summary>
604 /// Open file event arguments.
605 /// Used in events raised from DocManager class.
606 /// Class contains name of file and result of Open operation.
607 /// </summary>
608 public class OpenFileEventArgs : System.EventArgs
609 {
610 private string fileName;
611 private bool success;
612  
613 public OpenFileEventArgs(string fileName, bool success)
614 {
615 this.fileName = fileName;
616 this.success = success;
617 }
618  
619 public string FileName
620 {
621 get
622 {
623 return fileName;
624 }
625 }
626  
627 public bool Succeeded
628 {
629 get
630 {
631 return success;
632 }
633 }
634 }
635  
636 #endregion
637  
638 #region class DocManagerData
639  
640 /// <summary>
641 /// Class used for DocManager class initialization
642 /// </summary>
643 public class DocManagerData
644 {
645 public DocManagerData()
646 {
647 frmOwner = null;
648 updateTitle = true;
649 newDocName = "Untitled";
650 fileDlgFilter = "All Files (*.*)|*.*";
651 registryPath = "Software\\Unknown";
652 }
653  
654 private Form frmOwner;
655 private bool updateTitle;
656 private string newDocName;
657 private string fileDlgFilter;
658 private string registryPath;
659  
660 public Form FormOwner
661 {
662 get
663 {
664 return frmOwner;
665 }
666 set
667 {
668 frmOwner = value;
669 }
670 }
671  
672 public bool UpdateTitle
673 {
674 get
675 {
676 return updateTitle;
677 }
678 set
679 {
680 updateTitle = value;
681 }
682 }
683  
684 public string NewDocName
685 {
686 get
687 {
688 return newDocName;
689 }
690 set
691 {
692 newDocName = value;
693 }
694 }
695  
696 public string FileDialogFilter
697 {
698 get
699 {
700 return fileDlgFilter;
701 }
702 set
703 {
704 fileDlgFilter = value;
705 }
706 }
707  
708 public string RegistryPath
709 {
710 get
711 {
712 return registryPath;
713 }
714 set
715 {
716 registryPath = value;
717 }
718 }
719 };
720  
721 #endregion
722 }
723  
724 #region Using
725  
726 /*
727 Using:
728  
729 1. Write class which implements program-specific tasks. This class keeps some data,
730 knows to draw itself in the form window, and implements ISerializable interface.
731 Example:
732  
733 [Serializable]
734 public class MyTask : ISerializable
735 {
736 // class members
737 private int myData;
738 // ...
739  
740 public MyTask()
741 {
742 // ...
743 }
744  
745 public void Draw(Graphics g, Rectangle r)
746 {
747 // ...
748 }
749  
750 // other functions
751 // ...
752  
753 // Serialization
754 // This function is called when file is loaded
755 protected GraphicsList(SerializationInfo info, StreamingContext context)
756 {
757 myData = info.GetInt32("myData");
758 // ...
759 }
760  
761 // Serialization
762 // This function is called when file is saved
763 public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
764 {
765 info.AddValue("myData", myData);
766 // ...
767 }
768 }
769  
770 Add member of this class to the form:
771  
772 private MyClass myClass;
773  
774  
775 2. Add the DocManager member to the owner form:
776  
777 private DocManager docManager;
778  
779 3. Add DocManager message handlers to the owner form:
780  
781 private void docManager_ClearEvent(object sender, EventArgs e)
782 {
783 // DocManager executed New command
784 // Clear here myClass or create new empty instance:
785 myClass = new MyClass();
786 Refresh();
787 }
788  
789 private void docManager_DocChangedEvent(object sender, EventArgs e)
790 {
791 // DocManager reports that document was changed (loaded from file)
792 Refresh();
793 }
794  
795 private void docManager_OpenEvent(object sender, OpenFileEventArgs e)
796 {
797 // DocManager reports about successful/unsuccessful Open File operation
798 // For example:
799  
800 if ( e.Succeeded )
801 // add e.FileName to MRU list
802 else
803 // remove e.FileName from MRU list
804 }
805  
806 private void docManager_LoadEvent(object sender, SerializationEventArgs e)
807 {
808 // DocManager asks to load document from supplied stream
809 try
810 {
811 myClass = (MyClass)e.Formatter.Deserialize(e.SerializationStream);
812 }
813 catch ( catch possible exceptions here )
814 {
815 // report error
816  
817 e.Error = true;
818 }
819 }
820  
821 private void docManager_SaveEvent(object sender, SerializationEventArgs e)
822 {
823 // DocManager asks to save document to supplied stream
824 try
825 {
826 e.Formatter.Serialize(e.SerializationStream, myClass);
827 }
828 catch ( catch possible exceptions here )
829 {
830 // report error
831  
832 e.Error = true;
833 }
834 }
835  
836 4. Initialize docManager member in the form initialization code:
837  
838 DocManagerData data = new DocManagerData();
839 data.FormOwner = this;
840 data.UpdateTitle = true;
841 data.FileDialogFilter = "MyProgram files (*.mpf)|*.mpf|All Files (*.*)|*.*";
842 data.NewDocName = "Untitled.mpf";
843 data.RegistryPath = "Software\\MyCompany\\MyProgram";
844  
845 docManager = new DocManager(data);
846  
847 docManager.SaveEvent += docManager_SaveEvent;
848 docManager.LoadEvent += docManager_LoadEvent;
849 docManager.OpenEvent += docManager_OpenEvent;
850 docManager.DocChangedEvent += docManager_DocChangedEvent;
851 docManager.ClearEvent += docManager_ClearEvent;
852  
853 docManager.NewDocument();
854  
855 // Optionally - register file type for Windows Shell
856 bool result = docManager.RegisterFileType("mpf", "mpffile", "MyProgram File");
857  
858 5. Call docManager functions when necessary. For example:
859  
860 // File is dropped into the window;
861 // Command line parameter is handled.
862 public void OpenDocument(string file)
863 {
864 docManager.OpenDocument(file);
865 }
866  
867 // User Selected File - Open command.
868 private void CommandOpen()
869 {
870 docManager.OpenDocument("");
871 }
872  
873 // User selected File - Save command
874 private void CommandSave()
875 {
876 docManager.SaveDocument(DocManager.SaveType.Save);
877 }
878  
879 // User selected File - Save As command
880 private void CommandSaveAs()
881 {
882 docManager.SaveDocument(DocManager.SaveType.SaveAs);
883 }
884  
885 // User selected File - New command
886 private void CommandNew()
887 {
888 docManager.NewDocument();
889 }
890  
891  
892 6. Optionally: test for unsaved data in the form Closing event:
893  
894 private void MainForm_Closing(object sender, System.ComponentModel.CancelEventArgs e)
895 {
896 if ( ! docManager.CloseDocument() )
897 e.Cancel = true;
898 }
899  
900 7. Optionally: handle command-line parameters in the main function:
901  
902 [STAThread]
903 static void Main(string[] args)
904 {
905 // Check command line
906 if( args.Length > 1 )
907 {
908 MessageBox.Show("Incorrect number of arguments. Usage: MyProgram.exe [file]", "MyProgram");
909 return;
910 }
911  
912 // Load main form, taking command line into account
913 MainForm form = new MainForm();
914  
915 if ( args.Length == 1 )
916 form.OpenDocument(args[0]); // OpenDocument calls docManager.OpenDocument
917  
918 Application.Run(form);
919 }
920 */
921  
922 #endregion