home *** CD-ROM | disk | FTP | other *** search
- // Pavel Zolnikov[http://www.codeproject.com/script/profile/whos_who.asp?id=35980], 2002
-
- using System;
- using System.Text;
- using System.Xml;
- using System.IO;
- using System.Drawing;
- using System.Resources;
- using System.Reflection;
- using System.Windows.Forms;
- using System.Drawing.Drawing2D;
- using System.Xml.Serialization;
- using System.Runtime.InteropServices;
-
- using ZCommon;
-
- namespace CommandBar
- {
- /// <summary>
- /// Provides drop down menu for the 'Script' toolbar button based on the xml macro file.
- /// Traks changes to the file so menu always stays updated.
- /// </summary>
- [ComVisible(false)]
- public class MacroMenuBuilder
- {
- /// <summary>
- /// Watches for changes in a macro file so if there is one menu is being rebuilt.
- /// </summary>
- FileSystemWatcher fsw;
- readonly String macroFilePath;
- readonly ContextMenu menu2Build;
-
- /// <summary>
- ///
- /// </summary>
- /// <param name="path">path to the xml file with macro</param>
- /// <param name="menu">reference to menu that will be populated</param>
- public MacroMenuBuilder(String path, ContextMenu menu)
- {
- macroFilePath = path;
- menu2Build = menu;
- reBuildMacroMenu();
-
- menu2Build.Popup += new EventHandler( handlePopup );
-
- if( macroFilePath != "" )
- {
- String dir = Path.GetDirectoryName(macroFilePath);
- if( Directory.Exists(dir) )
- {
- fsw = new FileSystemWatcher();
- fsw.Path = dir;
- fsw.Filter = Path.GetFileName(macroFilePath);
- fsw.NotifyFilter = NotifyFilters.LastWrite;
- fsw.Changed += new FileSystemEventHandler( handleMacroFileChanged );
- fsw.EnableRaisingEvents = true;
- }
- }
- }
-
- /// <summary>
- /// If there was an error parsing xml macro file then contains description of it. Otherwise null.
- /// </summary>
- public string MacroFileError
- {
- get
- {
- return macroFileError;
- }
- }string macroFileError;
-
- /// <summary>
- /// Raised when menu item was selected.
- /// </summary>
- public event EventHandler MenuItemClick;
- /// <summary>
- /// Raised when menu was changed.
- /// </summary>
- public event EventHandler MenuChanged;
-
- bool bMacroFileChanged;
- void handleMacroFileChanged(object sender, FileSystemEventArgs fsa)
- {
- bMacroFileChanged = true;
- }
-
- void handleMenuItemClick(object sender, System.EventArgs e)
- {
- if( MenuItemClick != null )
- MenuItemClick(sender, EventArgs.Empty );
- }
- /// <summary>
- /// MenuItems of macro menu are ownerdrawn. Implementtion uses MeasureString for the current system MenuFont and text.
- /// </summary>
- void handleMeasureItem(object sender, MeasureItemEventArgs e )
- {
- TagMenuItem mi = (TagMenuItem)sender;
- item script = (item)mi.Tag;
-
- Size bounds = e.Graphics.MeasureString( script.text, SystemInformation.MenuFont ).ToSize();
-
- e.ItemHeight = bounds.Height;
- e.ItemWidth = bounds.Width + SystemInformation.MenuCheckSize.Width;
- }
- /// <summary>
- /// MenuItems of macro menu are ownerdrawn. Draws text and 'enter' symbol to the left of it if command autoexecutes.
- /// </summary>
- void handleDrawMenuItem(object sender, DrawItemEventArgs e )
- {
- TagMenuItem mi = (TagMenuItem)sender;
- item script = (item)mi.Tag;
-
- Rectangle textPosition = e.Bounds;
- textPosition.Offset( SystemInformation.MenuCheckSize.Width, 0 );
- e.DrawBackground();
- e.Graphics.DrawString( script.text, e.Font, new SolidBrush(e.ForeColor), textPosition );
-
- if( script is macro && ((macro)script).execute )
- {
- Font f = new Font("Symbol", e.Font.SizeInPoints, FontStyle.Regular, GraphicsUnit.Point );
-
- StringFormat sf = new StringFormat();
- sf.Alignment = StringAlignment.Far;
-
- e.Graphics.DrawString( "\xBF", f, new SolidBrush(e.ForeColor), e.Bounds, sf );
- }
- }
-
- /// <summary>
- /// Desrializes xml in macro file into graph of item-derived objects. Builds context menu from this graph.
- /// </summary>
- void reBuildMacroMenu()
- {
- group scripts = null;
- macroFileError = null;
- menu2Build.MenuItems.Clear();
-
- Stream sr = null;
- try
- {
- if( File.Exists(macroFilePath) )
- {
- sr = File.OpenRead( macroFilePath );
- scripts = (group)new XmlSerializer(typeof(group)).Deserialize( sr );
- }
- else
- {
- ResourceManager rm = new ResourceManager("CommandBar.macro",GetType().Assembly);
- XmlTextReader xtr = new XmlTextReader(rm.GetString("macro"), XmlNodeType.Document, null);
- scripts = (group)new XmlSerializer(typeof(group)).Deserialize( xtr );
- }
- }
- catch(Exception e)
- {
- macroFileError = e.Message;
- }
- finally
- {
- if( sr != null ) sr.Close();
- }
-
- if( scripts != null && macroFileError == null )
- {
- scripts.BuildContextMenu( menu2Build, new EventHandler(instrumentMenuItem) );
- bMacroFileChanged = false;
- }
-
- if( MenuChanged!= null )
- MenuChanged( this, EventArgs.Empty );
- }
-
- /// <summary>
- /// Called by item,macro and group during the process of building menu. Allows for tweaking all created MenuItem objects.
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="ea"></param>
- void instrumentMenuItem(Object sender, EventArgs ea)
- {
- MenuItem mi =(MenuItem)sender;
- mi.Click += new EventHandler(handleMenuItemClick);
- mi.OwnerDraw = true;
- mi.DrawItem += new DrawItemEventHandler( handleDrawMenuItem );
- mi.MeasureItem += new MeasureItemEventHandler( handleMeasureItem );
- }
-
- void handlePopup(Object sender, EventArgs ea)
- {
- if( bMacroFileChanged )
- reBuildMacroMenu();
- }
-
-
- /// <summary>
- /// Base class for (de)serializing macro menu in xml format.
- /// </summary>
- [ComVisible(false)]
- public class item
- {
- public item(){}
- public item(String t) { text = t; }
-
- [XmlAttribute]
- public String text;
-
- public virtual TagMenuItem BuildMenu(Menu menu, EventHandler instrumentMenuItem)
- {
- TagMenuItem mi = new TagMenuItem(text,this);
- menu.MenuItems.Add( mi );
-
- instrumentMenuItem(mi, EventArgs.Empty);
- return mi;
- }
- }
-
- /// <summary>
- /// Represents group tag in xml macro file.
- /// </summary>
- [ComVisible(false)]
- public class group : item
- {
- public group() {}
- public group(String t) : base(t) {}
-
- /// <summary>
- /// group contains list of chile items. As this list may consist of <code>macro</code> and
- /// <code>group</code> elements we must specify both these types in <code>XmlElement</code> attribute
- /// </summary>
- [XmlElement(typeof(group))]
- [XmlElement(typeof(macro))]
- public item[] items;
-
- public void BuildContextMenu(ContextMenu menu, EventHandler instrumentMenuItem)
- {
- if( items != null )
- foreach(item m in items)
- m.BuildMenu( menu, instrumentMenuItem );
- }
-
- public override TagMenuItem BuildMenu(Menu menu, EventHandler instrumentMenuItem)
- {
- TagMenuItem mi = base.BuildMenu( menu, instrumentMenuItem );
-
- if( items != null )
- foreach(item m in items)
- m.BuildMenu( mi, instrumentMenuItem );
-
- return mi;
- }
- }
-
- /// <summary>
- /// Represents macro tag in xml macro file.
- /// </summary>
- [ComVisible(false)]
- public class macro : item
- {
- [XmlAttribute]
- public bool execute = true;
-
- [XmlAttribute]
- public String command;
-
- public macro(){}
- public macro(String t) : base(t) {}
- public macro(String t, bool b) : base(t) { execute = b; }
- public macro(String t, String c, bool b) : base(t) { command = c; execute = b; }
- }
- }
- }