* Added interface to add custom controls to toolbox

* Fixes to document saving. Moz still swallows directive placeholders...
* Changed the way editor commands are hooked up and exposed more
* Minor fix to string types used in c++ glue

svn path=/trunk/aspeditor/; revision=49229
This commit is contained in:
Michael Hutchinson 2005-08-31 23:15:00 +00:00
Родитель 6949554db7
Коммит ce74746f33
12 изменённых файлов: 526 добавлений и 152 удалений

Просмотреть файл

@ -46,7 +46,8 @@ namespace AspNetEdit.SampleHost
class SampleHost class SampleHost
{ {
static DesignerHost host; static DesignerHost host;
static Frame geckoFrame; static Frame geckoFrame;
static AspNetEdit.Editor.ComponentModel.ToolboxService toolboxService;
static void Main () static void Main ()
{ {
@ -79,7 +80,9 @@ namespace AspNetEdit.SampleHost
#endregion #endregion
#region Toolbar #region Toolbar
// * Save/Open
Toolbar buttons = new Toolbar (); Toolbar buttons = new Toolbar ();
outerBox.PackStart (buttons, false, false, 0); outerBox.PackStart (buttons, false, false, 0);
@ -89,7 +92,11 @@ namespace AspNetEdit.SampleHost
ToolButton openButton = new ToolButton(Stock.Open); ToolButton openButton = new ToolButton(Stock.Open);
buttons.Add(openButton); buttons.Add(openButton);
openButton.Clicked += new EventHandler(openButton_Clicked); openButton.Clicked += new EventHandler(openButton_Clicked);
buttons.Add (new SeparatorToolItem());
// * Clipboard
ToolButton undoButton = new ToolButton (Stock.Undo); ToolButton undoButton = new ToolButton (Stock.Undo);
buttons.Add (undoButton); buttons.Add (undoButton);
@ -109,7 +116,39 @@ namespace AspNetEdit.SampleHost
ToolButton pasteButton = new ToolButton (Stock.Paste); ToolButton pasteButton = new ToolButton (Stock.Paste);
buttons.Add (pasteButton); buttons.Add (pasteButton);
pasteButton.Clicked += new EventHandler (pasteButton_Clicked); pasteButton.Clicked += new EventHandler (pasteButton_Clicked);
buttons.Add (new SeparatorToolItem());
// * Text style
ToolButton boldButton = new ToolButton (Stock.Bold);
buttons.Add (boldButton);
boldButton.Clicked += new EventHandler (boldButton_Clicked);
ToolButton italicButton = new ToolButton (Stock.Italic);
buttons.Add (italicButton);
italicButton.Clicked += new EventHandler (italicButton_Clicked);
ToolButton underlineButton = new ToolButton (Stock.Underline);
buttons.Add (underlineButton);
underlineButton.Clicked += new EventHandler (underlineButton_Clicked);
ToolButton indentButton = new ToolButton (Stock.Indent);
buttons.Add (indentButton);
indentButton.Clicked += new EventHandler (indentButton_Clicked);
ToolButton unindentButton = new ToolButton (Stock.Unindent);
buttons.Add (unindentButton);
unindentButton.Clicked += new EventHandler (unindentButton_Clicked);
buttons.Add (new SeparatorToolItem());
// * Toolbox
ToolButton toolboxAddButton = new ToolButton (Stock.Add);
buttons.Add (toolboxAddButton);
toolboxAddButton.Clicked += new EventHandler (toolboxAddButton_Clicked);
#endregion #endregion
@ -117,15 +156,15 @@ namespace AspNetEdit.SampleHost
//set up the services //set up the services
ServiceContainer services = new ServiceContainer (); ServiceContainer services = new ServiceContainer ();
services.AddService (typeof (INameCreationService), new AspNetEdit.Editor.ComponentModel.NameCreationService ()); services.AddService (typeof (INameCreationService), new NameCreationService ());
services.AddService (typeof (ISelectionService), new AspNetEdit.Editor.ComponentModel.SelectionService ()); services.AddService (typeof (ISelectionService), new SelectionService ());
services.AddService (typeof (IEventBindingService), new AspNetEdit.Editor.ComponentModel.EventBindingService (window)); services.AddService (typeof (IEventBindingService), new EventBindingService (window));
services.AddService (typeof (ITypeResolutionService), new AspNetEdit.Editor.ComponentModel.TypeResolutionService ()); services.AddService (typeof (ITypeResolutionService), new TypeResolutionService ());
ExtenderListService extListServ = new AspNetEdit.Editor.ComponentModel.ExtenderListService (); ExtenderListService extListServ = new AspNetEdit.Editor.ComponentModel.ExtenderListService ();
services.AddService (typeof (IExtenderListService), extListServ); services.AddService (typeof (IExtenderListService), extListServ);
services.AddService (typeof (IExtenderProviderService), extListServ); services.AddService (typeof (IExtenderProviderService), extListServ);
services.AddService (typeof (ITypeDescriptorFilterService), new TypeDescriptorFilterService ()); services.AddService (typeof (ITypeDescriptorFilterService), new TypeDescriptorFilterService ());
AspNetEdit.Editor.ComponentModel.ToolboxService toolboxService = new AspNetEdit.Editor.ComponentModel.ToolboxService (); toolboxService = new ToolboxService ();
services.AddService (typeof (IToolboxService), toolboxService); services.AddService (typeof (IToolboxService), toolboxService);
//create our host //create our host
@ -147,7 +186,8 @@ namespace AspNetEdit.SampleHost
Toolbox toolbox = new Toolbox (services); Toolbox toolbox = new Toolbox (services);
leftBox.Pack1 (toolbox, false, false); leftBox.Pack1 (toolbox, false, false);
toolboxService.PopulateFromAssembly (System.Reflection.Assembly.GetAssembly (typeof (System.Web.UI.Control))); toolboxService.PopulateFromAssembly (System.Reflection.Assembly.GetAssembly (typeof (System.Web.UI.Control)));
toolboxService.AddToolboxItem (new TextToolboxItem ("<table><tr><td></td><td></td></tr><tr><td></td><td></td></tr></table>", "Table"), "Html");
toolbox.UpdateCategories (); toolbox.UpdateCategories ();
#endregion #endregion
@ -193,7 +233,6 @@ namespace AspNetEdit.SampleHost
fcd.Filter = new FileFilter(); fcd.Filter = new FileFilter();
fcd.Filter.AddPattern ("*.aspx"); fcd.Filter.AddPattern ("*.aspx");
fcd.SelectMultiple = false; fcd.SelectMultiple = false;
fcd.SetFilename (((System.Web.UI.Control)host.RootComponent).ID + ".aspx");
ResponseType response = (ResponseType) fcd.Run( ); ResponseType response = (ResponseType) fcd.Run( );
fcd.Hide (); fcd.Hide ();
@ -214,27 +253,77 @@ namespace AspNetEdit.SampleHost
static void redoButton_Clicked (object sender, EventArgs e) static void redoButton_Clicked (object sender, EventArgs e)
{ {
throw new NotImplementedException (); host.RootDocument.DoCommand (EditorCommand.Redo);
} }
static void undoButton_Clicked (object sender, EventArgs e) static void undoButton_Clicked (object sender, EventArgs e)
{ {
throw new NotImplementedException (); host.RootDocument.DoCommand (EditorCommand.Undo);
} }
static void cutButton_Clicked (object sender, EventArgs e) static void cutButton_Clicked (object sender, EventArgs e)
{ {
throw new NotImplementedException (); host.RootDocument.DoCommand (EditorCommand.Cut);
} }
static void copyButton_Clicked (object sender, EventArgs e) static void copyButton_Clicked (object sender, EventArgs e)
{ {
throw new NotImplementedException (); host.RootDocument.DoCommand (EditorCommand.Copy);
} }
static void pasteButton_Clicked (object sender, EventArgs e) static void pasteButton_Clicked (object sender, EventArgs e)
{ {
throw new NotImplementedException (); host.RootDocument.DoCommand (EditorCommand.Paste);
}
static void italicButton_Clicked (object sender, EventArgs e)
{
host.RootDocument.DoCommand (EditorCommand.Italic);
}
static void boldButton_Clicked (object sender, EventArgs e)
{
host.RootDocument.DoCommand (EditorCommand.Bold);
}
static void underlineButton_Clicked (object sender, EventArgs e)
{
host.RootDocument.DoCommand (EditorCommand.Underline);
}
static void indentButton_Clicked (object sender, EventArgs e)
{
host.RootDocument.DoCommand (EditorCommand.Indent);
}
static void unindentButton_Clicked (object sender, EventArgs e)
{
host.RootDocument.DoCommand (EditorCommand.Outdent);
}
static void toolboxAddButton_Clicked (object sender, EventArgs e)
{
FileChooserDialog fcd = new FileChooserDialog ("Add custom controls...", (Window)((Widget)sender).Toplevel, FileChooserAction.Open);
fcd.AddButton(Stock.Cancel, ResponseType.Cancel);
fcd.AddButton(Stock.Open, ResponseType.Ok);
fcd.DefaultResponse = ResponseType.Ok;
fcd.Filter = new FileFilter();
fcd.Filter.AddPattern ("*.dll");
fcd.SelectMultiple = false;
ResponseType response = (ResponseType) fcd.Run( );
fcd.Hide ();
if (response == ResponseType.Ok && fcd.Filename != null)
try{
System.Reflection.Assembly a = System.Reflection.Assembly.LoadFrom (fcd.Filename);
toolboxService.PopulateFromAssembly (a);
}
catch (Exception ex) {
//TODO: handle this better!
System.Diagnostics.Trace.WriteLine ("Could not load assembly \"" + fcd.Filename + "\".");
}
fcd.Destroy();
} }
#endregion #endregion

Просмотреть файл

@ -80,7 +80,7 @@ namespace AspNetEdit.Editor.ComponentModel
//check arguments //check arguments
if (componentClass == null) if (componentClass == null)
throw new ArgumentNullException ("componentClass"); throw new ArgumentNullException ("componentClass");
if (!componentClass.IsSubclassOf (typeof (System.Web.UI.Control)) && componentClass.GetType() != typeof (System.Web.UI.Control)) if (!componentClass.IsSubclassOf (typeof (System.Web.UI.Control)) && componentClass != typeof (System.Web.UI.Control))
throw new ArgumentException ("componentClass must be a subclass of System.Web.UI.Control", "componentClass"); throw new ArgumentException ("componentClass must be a subclass of System.Web.UI.Control", "componentClass");
if (componentClass.IsSubclassOf (typeof (System.Web.UI.Page))) if (componentClass.IsSubclassOf (typeof (System.Web.UI.Page)))

Просмотреть файл

@ -47,7 +47,7 @@ namespace AspNetEdit.Editor.ComponentModel
{ {
public static readonly string newDocument = "<html>\n<head>\n\t<title>{0}</title>\n</head>\n<body>\n<form runat=\"server\">\n\n</form></body>\n</html>"; public static readonly string newDocument = "<html>\n<head>\n\t<title>{0}</title>\n</head>\n<body>\n<form runat=\"server\">\n\n</form></body>\n</html>";
public static readonly string ControlSubstituteStructure = "<aspcontrol id=\"{0}\" width=\"{1}\" height=\"{2}\" -md-can-drop=\"{3}\" -md-can-resize=\"{4}\">{5}</aspcontrol>"; public static readonly string ControlSubstituteStructure = "<aspcontrol id=\"{0}\" width=\"{1}\" height=\"{2}\" -md-can-drop=\"{3}\" -md-can-resize=\"{4}\">{5}</aspcontrol>";
public static readonly string DirectivePlaceholderStructure = "<directiveplaceholder id =\"{0}\" />"; public static readonly string DirectivePlaceholderStructure = "<!--<directiveplaceholder id =\"{0}\" />-->";
string document; string document;
Hashtable directives; Hashtable directives;
@ -55,13 +55,14 @@ namespace AspNetEdit.Editor.ComponentModel
private Control parent; private Control parent;
private DesignerHost host; private DesignerHost host;
private RootDesignerView view; private RootDesignerView view;
private DesignTimeParser aspParser;
///<summary>Creates a new document</summary> ///<summary>Creates a new document</summary>
public Document (Control parent, DesignerHost host, string documentName) public Document (Control parent, DesignerHost host, string documentName)
{ {
initDocument (parent, host); initDocument (parent, host);
document = String.Format (newDocument, documentName); this.document = String.Format (newDocument, documentName);
GetView (); GetView ();
} }
@ -70,20 +71,15 @@ namespace AspNetEdit.Editor.ComponentModel
{ {
initDocument (parent, host); initDocument (parent, host);
DesignTimeParser ps = new DesignTimeParser (host, this);
TextReader reader = new StreamReader (fileStream); TextReader reader = new StreamReader (fileStream);
try { try {
Control[] controls; this.document = DeserializeAndAdd (reader.ReadToEnd ());
ps.ParseDocument (reader.ReadToEnd (), out controls, out document);
foreach (Control c in controls)
host.Container.Add (c);
} }
catch (ParseException ex) { catch (ParseException ex) {
document = string.Format ("<html><head></head><body><h1>{0}</h1><p>{1}</p></body></html>", ex.Title, ex.Message); this.document = string.Format ("<html><head></head><body><h1>{0}</h1><p>{1}</p></body></html>", ex.Title, ex.Message);
} }
catch (Exception ex) { catch (Exception ex) {
document = string.Format ("<html><head></head><body><h1>{0}</h1><p>{1}</p><p>{2}</p></body></html>", "Error loading document", ex.Message, ex.StackTrace); this.document = string.Format ("<html><head></head><body><h1>{0}</h1><p>{1}</p><p>{2}</p></body></html>", "Error loading document", ex.Message, ex.StackTrace);
} }
GetView (); GetView ();
@ -102,7 +98,9 @@ namespace AspNetEdit.Editor.ComponentModel
CaseInsensitiveHashCodeProvider provider = new CaseInsensitiveHashCodeProvider(CultureInfo.InvariantCulture); CaseInsensitiveHashCodeProvider provider = new CaseInsensitiveHashCodeProvider(CultureInfo.InvariantCulture);
CaseInsensitiveComparer comparer = new CaseInsensitiveComparer(CultureInfo.InvariantCulture); CaseInsensitiveComparer comparer = new CaseInsensitiveComparer(CultureInfo.InvariantCulture);
directives = new Hashtable (provider, comparer); directives = new Hashtable (provider, comparer);
this.aspParser = new DesignTimeParser (host, this);
} }
private void GetView () private void GetView ()
@ -114,8 +112,7 @@ namespace AspNetEdit.Editor.ComponentModel
System.Diagnostics.Trace.WriteLine ("Document created."); System.Diagnostics.Trace.WriteLine ("Document created.");
} }
#region viewing #region Some Gecko communication stuff
//we don't want to have the document lying around forever, but we //we don't want to have the document lying around forever, but we
//want the RootDesignerview to be able to get it when Gecko XUL loads //want the RootDesignerview to be able to get it when Gecko XUL loads
@ -128,48 +125,154 @@ namespace AspNetEdit.Editor.ComponentModel
document = null; document = null;
return doc; return doc;
} }
#endregion
public string PersistDocument ()
{
//TODO: Parse document instead of StringBuilder.Replace
string stringDocument = view.GetDocument ();
StringBuilder builder = new StringBuilder (stringDocument);
if (host == null)
throw new Exception("The WebFormsPage cannot be persisted without a host");
//substitute all components
foreach (IComponent comp in host.Container.Components)
{
if (comp is Page)
continue;
if (!(comp is Control) || comp.Site == null)
throw new Exception("The component is not a sited System.Web.UI.Control");
string substituteText = RenderDesignerControl ((Control)comp);
string persistedText = ControlPersister.PersistControl ((Control)comp, host);
builder.Replace(substituteText, persistedText);
}
//substitute all directive placeholders
for (int i = 0; i <= directivePlaceholderKey; i++)
{
string persistedText = RemoveDirective(i);
string substituteText = String.Format (DirectivePlaceholderStructure, i.ToString());
if (stringDocument.IndexOf(substituteText) > -1)
builder.Replace (substituteText, persistedText);
else
builder.Insert (0, persistedText);
}
return builder.ToString();
}
#region add/remove/update controls
///<summary>Serialises the entire document to ASP.NET code</summary>
public string PersistDocument ()
{
StringBuilder builder = new StringBuilder(this.Serialize (view.GetDocument ()));
//insert all remaining directives
for (int i = 0; i <= directivePlaceholderKey; i++)
{
builder.Insert (0, RemoveDirective(i));
}
return builder.ToString ();
}
public void DoCommand (string editorCommand)
{
view.DoCommand (editorCommand);
}
#endregion
#region Serialisation stuff
///<summary>Converts a designer document fragment to ASP.NET code</summary>
public string Serialize (string designerDocumentFragment)
{
if (host == null)
throw new Exception("The document cannot be persisted without a host");
string serializedDoc = string.Empty;
StringWriter writer = new StringWriter ();
//keep method argument meaningfully named, but keep code readable!
string frag = designerDocumentFragment;
int length = frag.Length;
int pos = 0;
SMode mode = SMode.Free;
while (pos < length)
{
char c = frag [pos];
switch (mode)
{
//it's freely copying to output, but watching for a directive or control placeholder
case SMode.Free:
if (c == '<')
{
if ((pos + 10 < length) && frag.Substring (pos + 1, 10) == "aspcontrol") {
mode = SMode.ControlId;
pos += 10;
break;
}
else if ((pos + 24 < length) && frag.Substring (pos + 1, 24) == "!--<directiveplaceholder") {
mode = SMode.DirectiveId;
pos += 24;
break;
}
}
writer.Write (c);
break;
//it's found a directive placeholder and is scanning for the ID
case SMode.DirectiveId:
if (c == 'i' && (pos + 4 < length) && frag.Substring (pos, 4) == "id=\"") {
int idEnd = frag.IndexOf ('"', pos + 4 + 1);
if (idEnd == -1) throw new Exception ("Identifier was unterminated");
int id = System.Convert.ToInt32 (frag.Substring (pos + 4 + 1, (idEnd - pos - 4)));
//TODO: more intelligent removal/copying of directives in case of fragments
//works fine with whole document.
string directive = RemoveDirective (id);
writer.Write (directive);
mode = SMode.DirectiveEnd;
pos = idEnd;
}
break;
//it's found a control placeholder and is scanning for the ID
case SMode.ControlId:
if (c == 'i' && (pos + 4 < length) && frag.Substring (pos, 4) == "id=\"") {
int idEnd = frag.IndexOf("\"", pos + 4);
if (idEnd == -1) throw new Exception ("Identifier was unterminated");
string id = frag.Substring (pos + 4, (idEnd - pos - 4));
System.Diagnostics.Trace.WriteLine ("Persisting control with id: " + id);
DesignContainer dc = (DesignContainer) host.Container;
Control control = dc.GetComponent (id) as Control;
if (control == null) throw new Exception ("Could not retrieve control "+id);
ControlPersister.PersistControl (writer, control);
mode = SMode.ControlEnd;
pos = idEnd;
}
break;
//it's found the control's ID and is looking for the end
case SMode.ControlEnd:
if (c == '<' && (pos + 13 < length) && frag.Substring (pos, 13) == "</aspcontrol>") {
pos += 12;
mode = SMode.Free;
}
break;
//it's found the placeholder's ID and is looking for the end
case SMode.DirectiveEnd:
mode = SMode.Free;
break;
}
pos++;
}
serializedDoc = writer.ToString ();
writer.Close ();
return serializedDoc;
}
///<summary>Converts a ASP.NET fragment to a a designer document fragment,
/// and adds the controls and directives etc to the host.</summary>
public string DeserializeAndAdd (string aspFragment)
{
string document;
Control[] controls;
aspParser.ParseDocument (aspFragment, out controls, out document);
foreach (Control c in controls)
host.Container.Add (c);
return document;
}
//modes for the Serializing parser
private enum SMode {
Free,
ControlId,
DirectiveId,
ControlEnd,
DirectiveEnd
}
///<summary>Renders the designer html for an ASP.NET Control</summary>
public static string RenderDesignerControl (Control control) public static string RenderDesignerControl (Control control)
{ {
string height = "auto"; string height = "auto";
@ -181,7 +284,7 @@ namespace AspNetEdit.Editor.ComponentModel
WebControl wc = control as WebControl; WebControl wc = control as WebControl;
if (wc != null) { if (wc != null) {
height = wc.Height.ToString (); height = wc.Height.ToString ();
width = wc.Height.ToString (); width = wc.Width.ToString ();
} }
else else
{ {
@ -203,22 +306,30 @@ namespace AspNetEdit.Editor.ComponentModel
return string.Format (ControlSubstituteStructure, id, width, height, canDrop, canResize, content); return string.Format (ControlSubstituteStructure, id, width, height, canDrop, canResize, content);
} }
#endregion
#region add/remove/update controls
public void AddControl(Control control) public void AddControl (Control control)
{ {
view.AddControl (control); view.AddControl (control);
} }
public void RemoveControl(Control control) public void RemoveControl (Control control)
{ {
view.RemoveControl (control); view.RemoveControl (control);
} }
public void RenameControl(string oldName, string newName) public void RenameControl (string oldName, string newName)
{ {
view.RenameControl (oldName, newName); view.RenameControl (oldName, newName);
} }
public void InsertFragment (string fragment)
{
view.InsertFragment (fragment);
}
#endregion #endregion

Просмотреть файл

@ -44,7 +44,14 @@ namespace AspNetEdit.Editor.ComponentModel
{ {
Hashtable categories = new Hashtable (); Hashtable categories = new Hashtable ();
private string selectedCategory; private string selectedCategory;
private ToolboxItem selectedItem = null; private ToolboxItem selectedItem = null;
public event EventHandler ToolboxChanged;
protected void OnToolboxChanged ()
{
ToolboxChanged (this, new EventArgs ());
}
#region IToolboxService Members #region IToolboxService Members
@ -76,8 +83,9 @@ namespace AspNetEdit.Editor.ComponentModel
public void AddToolboxItem (ToolboxItem toolboxItem, string category) public void AddToolboxItem (ToolboxItem toolboxItem, string category)
{ {
if (!categories.ContainsKey (category)) if (!categories.ContainsKey (category))
categories[category] = new ArrayList (); categories[category] = new ArrayList ();
System.Diagnostics.Trace.WriteLine ("Adding ToolboxItem: " + toolboxItem.DisplayName + ", " + category);
((ArrayList) categories[category]).Add (toolboxItem); ((ArrayList) categories[category]).Add (toolboxItem);
} }
@ -290,6 +298,8 @@ namespace AspNetEdit.Editor.ComponentModel
foreach (Type t in types) foreach (Type t in types)
{ {
if (t.IsAbstract || t.IsNotPublic) continue; if (t.IsAbstract || t.IsNotPublic) continue;
if (t.GetConstructor (new Type[] {}) == null) continue;
AttributeCollection atts = TypeDescriptor.GetAttributes (t); AttributeCollection atts = TypeDescriptor.GetAttributes (t);
@ -314,9 +324,10 @@ namespace AspNetEdit.Editor.ComponentModel
category = "Data Controls"; category = "Data Controls";
else if (t.IsSubclassOf (typeof (System.Web.UI.WebControls.WebControl))) else if (t.IsSubclassOf (typeof (System.Web.UI.WebControls.WebControl)))
category = "Web Controls"; category = "Web Controls";
AddToolboxItem ((ToolboxItem) Activator.CreateInstance (toolboxItemType, new object[] {t}), category); AddToolboxItem ((ToolboxItem) Activator.CreateInstance (toolboxItemType, new object[] {t}), category);
} }
OnToolboxChanged ();
} }
#endregion #endregion

Просмотреть файл

@ -43,10 +43,21 @@ using AspNetEdit.Editor.Persistence;
namespace AspNetEdit.Editor.ComponentModel namespace AspNetEdit.Editor.ComponentModel
{ {
internal class WebFormPage : System.Web.UI.Page internal class WebFormPage : System.Web.UI.Page
{ {
private HttpRequest httpRequest;
public WebFormPage () public WebFormPage ()
{ {
pdc = TypeDescriptor.GetProperties (this); pdc = TypeDescriptor.GetProperties (this);
//fake the request for some controls which need it
/*
HttpRequest request = new HttpRequest (string.Empty, "file:///", string.Empty);
System.IO.StringWriter strw = new System.IO.StringWriter ();
HttpResponse response = new HttpResponse (strw);
HttpContext context = new HttpContext (request, response);
this.ProcessRequest (context);
*/
} }
//FIXME: enforce this... //FIXME: enforce this...

Просмотреть файл

@ -263,7 +263,9 @@ namespace AspNetEdit.Editor.Persistence
PersistenceModeAttribute modeAttrib = prop.Attributes[typeof(PersistenceModeAttribute)] as PersistenceModeAttribute; PersistenceModeAttribute modeAttrib = prop.Attributes[typeof(PersistenceModeAttribute)] as PersistenceModeAttribute;
if (modeAttrib == null || modeAttrib.Mode == PersistenceMode.Attribute) if (modeAttrib == null || modeAttrib.Mode == PersistenceMode.Attribute)
continue; continue;
Console.WriteLine ("Prop: "+prop.Name+"PersistenceMode:"+modeAttrib.Mode.ToString());
//handle the different modes //handle the different modes
switch (modeAttrib.Mode) switch (modeAttrib.Mode)
@ -279,7 +281,7 @@ namespace AspNetEdit.Editor.Persistence
case PersistenceMode.InnerDefaultProperty: case PersistenceMode.InnerDefaultProperty:
if (contentStarted) if (contentStarted)
throw new Exception("The Control has inner properties in addition to a default inner property"); throw new Exception("The Control has inner properties in addition to a default inner property");
PersistInnerProperty(prop,prop.GetValue (component), writer, host, true); PersistInnerProperty(prop, prop.GetValue (component), writer, host, true);
return; return;
case PersistenceMode.InnerProperty: case PersistenceMode.InnerProperty:
PersistInnerProperty (prop, prop.GetValue (component), writer, host, false); PersistInnerProperty (prop, prop.GetValue (component), writer, host, false);
@ -293,33 +295,26 @@ namespace AspNetEdit.Editor.Persistence
//once we've determined we need to persist a property, this does the actual work //once we've determined we need to persist a property, this does the actual work
private static void PersistInnerProperty (PropertyDescriptor prop, object value, HtmlTextWriter writer, IDesignerHost host, bool isDefault) private static void PersistInnerProperty (PropertyDescriptor prop, object value, HtmlTextWriter writer, IDesignerHost host, bool isDefault)
{ {
//look up tag prefix from host
IWebFormReferenceManager refMan = host.GetService (typeof (IWebFormReferenceManager)) as IWebFormReferenceManager;
if (refMan == null)
throw new Exception("Could not obtain IWebFormReferenceManager service"); ;
string prefix = refMan.GetTagPrefix (prop.PropertyType);
//newline and indent //newline and indent
writer.WriteLine(); writer.WriteLine();
//trivial case //trivial case
if (value == null) { if (value == null) {
if (!isDefault) { if (!isDefault) {
writer.WriteBeginTag (prefix + ":" + prop.Name); writer.WriteBeginTag (prop.Name);
writer.Write (HtmlTextWriter.SelfClosingTagEnd); writer.Write (HtmlTextWriter.SelfClosingTagEnd);
} }
return; return;
} }
//Persist collections as tag with property name //A collection? Persist individual objects.
//containing tags of object name, with object properties as attribs
if (value is ICollection) { if (value is ICollection) {
if (((ICollection) value).Count > 0) { if (((ICollection) value).Count > 0) {
//if default property needs no surrounding tags
if(!isDefault) { if(!isDefault) {
writer.WriteFullBeginTag(prefix + ":" + prop.Name); writer.WriteFullBeginTag (prop.Name);
writer.Indent++; writer.Indent++;
} }
@ -328,15 +323,21 @@ namespace AspNetEdit.Editor.Persistence
if(!isDefault) { if(!isDefault) {
writer.Indent--; writer.Indent--;
writer.WriteEndTag (prefix + ":" + prop.Name); writer.WriteEndTag (prop.Name);
} }
} }
} }
//not a collection? Simple: a tag of object name, with object properties as attribs //default but not collection: just write content
else else if (isDefault) {
{ if (prop.Converter.CanConvertTo (typeof (string))){
writer.Write (prop.Converter.ConvertToString (value));
return;
}
}
//else: a tag of property name, with sub-properties as attribs
else {
//only want to render tag if it has any attributes //only want to render tag if it has any attributes
writer.WriteBeginTag (prefix + ":" + prop.Name); writer.WriteBeginTag (prop.Name);
foreach (PropertyDescriptor p in TypeDescriptor.GetProperties(value)) foreach (PropertyDescriptor p in TypeDescriptor.GetProperties(value))
ProcessAttribute (p, value, writer, string.Empty); ProcessAttribute (p, value, writer, string.Empty);

Просмотреть файл

@ -98,18 +98,15 @@ namespace AspNetEdit.Editor.UI
//Register incoming calls from JavaScript //Register incoming calls from JavaScript
comm.RegisterJSHandler ("Click", new ClrCall (JSClick)); comm.RegisterJSHandler ("Click", new ClrCall (JSClick));
comm.RegisterJSHandler ("SavePage", new ClrCall (JSSave));
comm.RegisterJSHandler ("Activate", new ClrCall (JSActivate)); comm.RegisterJSHandler ("Activate", new ClrCall (JSActivate));
comm.RegisterJSHandler ("ThrowException", new ClrCall (JSException)); comm.RegisterJSHandler ("ThrowException", new ClrCall (JSException));
comm.RegisterJSHandler ("DebugStatement", new ClrCall (JSDebugStatement)); comm.RegisterJSHandler ("DebugStatement", new ClrCall (JSDebugStatement));
comm.RegisterJSHandler ("ResizeControl", new ClrCall (JSResize)); comm.RegisterJSHandler ("ResizeControl", new ClrCall (JSResize));
comm.RegisterJSHandler ("DocumentReturn", new ClrCall (JSDocumentReturn)); comm.RegisterJSHandler ("DocumentReturn", new ClrCall (JSDocumentReturn));
System.Diagnostics.Trace.WriteLine ("RootDesignerView created"); comm.RegisterJSHandler ("RemoveControl", new ClrCall (JSRemoveControl));
//TODO: Gecko seems to be taking over DND comm.RegisterJSHandler ("DeserializeAndAdd", new ClrCall (JSDeserializeAndAdd));
//register for drag+drop comm.RegisterJSHandler ("Serialize", new ClrCall (JSSerialize));
//TargetEntry te = new TargetEntry(Toolbox.DragDropIdentifier, TargetFlags.App, 0); System.Diagnostics.Trace.WriteLine ("RootDesignerView created");
//Drag.DestSet (this, DestDefaults.All, new TargetEntry[] { te }, Gdk.DragAction.Copy);
//this.DragDataReceived += new DragDataReceivedHandler(view_DragDataReceived);
} }
internal void BeginLoad () internal void BeginLoad ()
@ -163,6 +160,12 @@ namespace AspNetEdit.Editor.UI
#region document modification accessors for AspNetEdit.Editor.ComponentModel.Document #region document modification accessors for AspNetEdit.Editor.ComponentModel.Document
internal void InsertFragment (string fragment)
{
System.Diagnostics.Trace.WriteLine ("Inserting document fragment: " + fragment);
comm.JSCall (GeckoFunctions.InsertFragment, null, fragment);
}
internal void AddControl(Control control) internal void AddControl(Control control)
{ {
if (!active) return; if (!active) return;
@ -204,6 +207,24 @@ namespace AspNetEdit.Editor.UI
return d; return d;
} }
internal void DoCommand (string editorCommand)
{
System.Diagnostics.Trace.WriteLine ( "Executing command \"" + editorCommand +"\"");
comm.JSCall (GeckoFunctions.DoCommand, null, editorCommand);
}
#endregion
#region Inbound Gecko functions
///<summary>
/// Name: DocumentReturn
/// Callback function for when host initiates document save
/// Arguments:
/// string document: the document text, with placeholder'd controls
/// Returns: none
///</summary>
private string JSDocumentReturn (string[] args) private string JSDocumentReturn (string[] args)
{ {
if (args.Length != 1) if (args.Length != 1)
@ -212,10 +233,6 @@ namespace AspNetEdit.Editor.UI
return string.Empty; return string.Empty;
} }
#endregion
#region Inbound Gecko functions
//this is because of the Gecko# not wanting to give up its DomDocument until it's been shown. //this is because of the Gecko# not wanting to give up its DomDocument until it's been shown.
///<summary> ///<summary>
/// Name: Activate /// Name: Activate
@ -280,23 +297,6 @@ namespace AspNetEdit.Editor.UI
return string.Empty; return string.Empty;
} }
///<summary>
/// Name: SavePage
/// Callback function for when host initiates document save
/// Arguments:
/// string document: the document text, with placeholder'd controls
/// Returns: none
///</summary>
private string JSSave (string[] args)
{
if (args.Length != 1)
throw new InvalidJSArgumentException ("SavePage", -1);
throw new NotImplementedException (args[0]);
return string.Empty;
}
///<summary> ///<summary>
/// Name: ThrowException /// Name: ThrowException
/// Throws managed exceptions on behalf of Javascript /// Throws managed exceptions on behalf of Javascript
@ -358,13 +358,68 @@ namespace AspNetEdit.Editor.UI
pdc_h.SetValue (wc, pdc_h.Converter.ConvertFromInvariantString(args[2])); pdc_h.SetValue (wc, pdc_h.Converter.ConvertFromInvariantString(args[2]));
return string.Empty; return string.Empty;
}
///<summary>
/// Name: RemoveControl
/// Removes a control from the host when its Gecko representation is removed
/// Arguments:
/// string id: the control's ID
/// Returns: none
///</summary>
private string JSRemoveControl (string[] args)
{
if (args.Length != 1)
throw new InvalidJSArgumentException ("ResizeControl", -1);
//look up our component
DesignContainer container = (DesignContainer) host.Container;
IComponent component = container.GetComponent (args[0]);
if (component == null)
throw new InvalidJSArgumentException ("ResizeControl", 0);
//and remove it
container.Remove (component);
return string.Empty;
}
///<summary>
/// Name: Serialize
/// Serialises a fragment of a Gecko document into ASP.NET code
/// Arguments:
/// string designerDocumentFragment: the Gecko document fragment
/// Returns: the serialised document
///</summary>
private string JSSerialize (string[] args)
{
if (args.Length != 1)
throw new InvalidJSArgumentException ("Serialize", -1);
return host.RootDocument.Serialize (args [0]);
}
///<summary>
/// Name: DeserializeAndAdd
/// Deserialises a fragment of ASP.NET code into a Gecko designer document fragment
/// and adds the controls, directives etc to the host.
/// Arguments:
/// string designerDocumentFragment: the ASP.NET document fragment
/// Returns: the deserialised document
///</summary>
private string JSDeserializeAndAdd (string[] args)
{
if (args.Length != 1)
throw new InvalidJSArgumentException ("DeserializeAndAdd", -1);
return host.RootDocument.DeserializeAndAdd (args [0]);
} }
#endregion #endregion
#region Outbound Gecko functions #region Outbound Gecko functions
public class GeckoFunctions private class GeckoFunctions
{ {
///<summary> ///<summary>
/// Add a control to the document /// Add a control to the document
@ -414,8 +469,72 @@ namespace AspNetEdit.Editor.UI
/// Returns: none /// Returns: none
///</summary> ///</summary>
public static readonly string GetPage = "GetPage"; public static readonly string GetPage = "GetPage";
///<summary>
/// Passes a simple command to Gecko
/// Args:
/// string command: Use the enum EditorCommand
/// Returns: none
///</summary>
public static readonly string DoCommand = "DoCommand";
///<summary>
/// Inserts a document fragment. May contain HTML or ASP.NET; document should call host to deserialise it.
/// Args:
/// string fragment: The document fragment
/// Returns: none
///</summary>
public static readonly string InsertFragment = "InsertFragment";
} }
#endregion #endregion
}
//TODO: GetCommandState to check whether we can perform these commands
//commands for DoCommand
//simply triggers functionality in Mozilla editor
public class EditorCommand
{
//clipboard
public static readonly string Cut = "cmd_cut";
public static readonly string Copy = "cmd_copy";
public static readonly string Paste = "cmd_paste";
public static readonly string Delete = "cmd_delete";
//transactions
public static readonly string Undo = "cmd_undo";
public static readonly string Redo = "cmd_redo";
//styles
public static readonly string Bold = "cmd_bold";
public static readonly string Italic = "cmd_italic";
public static readonly string Underline = "cmd_underline";
public static readonly string TeleType = "cmd_tt";
public static readonly string Strikethrough = "cmd_strikethru";
public static readonly string Superscript = "cmd_superscript";
public static readonly string Subscript = "cmd_subscript";
public static readonly string Indent = "cmd_indent";
public static readonly string Outdent = "cmd_outdent";
public static readonly string IncreaseFont = "cmd_increaseFont";
public static readonly string DecreaseFont = "cmd_decreaseFont";
//semantic
public static readonly string Emphasis = "cmd_em";
public static readonly string Strong = "cmd_strong";
public static readonly string Citation = "cmd_cite";
public static readonly string Abbreviation = "cmd_abbr";
public static readonly string Acronym = "cmd_acronym";
public static readonly string Code = "cmd_code";
//lists
public static readonly string OrderedList = "cmd_ol";
public static readonly string UnorderedList = "cmd_ul";
//public static readonly string NoBreak = "cmd_nobreak";
//public static readonly string Underline = "cmd_dt";
//public static readonly string Underline = "cmd_dd";
} }
} }

Просмотреть файл

@ -33,7 +33,8 @@ using Gtk;
using System.Collections; using System.Collections;
using System.Drawing.Design; using System.Drawing.Design;
using System.ComponentModel.Design; using System.ComponentModel.Design;
using System.ComponentModel; using System.ComponentModel;
using AspNetEdit.Editor.ComponentModel;
namespace AspNetEdit.Editor.UI namespace AspNetEdit.Editor.UI
{ {
@ -42,7 +43,7 @@ namespace AspNetEdit.Editor.UI
private ServiceContainer parentServices; private ServiceContainer parentServices;
Hashtable expanders = new Hashtable (); Hashtable expanders = new Hashtable ();
private VBox vbox; private VBox vbox;
IToolboxService toolboxService; ToolboxService toolboxService;
public Toolbox(ServiceContainer parentServices) public Toolbox(ServiceContainer parentServices)
@ -50,11 +51,13 @@ namespace AspNetEdit.Editor.UI
this.parentServices = parentServices; this.parentServices = parentServices;
//we need this service, so create it if not present //we need this service, so create it if not present
toolboxService = parentServices.GetService (typeof (IToolboxService)) as IToolboxService; toolboxService = parentServices.GetService (typeof (IToolboxService)) as ToolboxService;
if (toolboxService == null) { if (toolboxService == null) {
toolboxService = new AspNetEdit.Editor.ComponentModel.ToolboxService (); toolboxService = new ToolboxService ();
parentServices.AddService (typeof (IToolboxService), toolboxService); parentServices.AddService (typeof (IToolboxService), toolboxService);
} }
toolboxService.ToolboxChanged += new EventHandler (tbsChanged);
base.VscrollbarPolicy = PolicyType.Automatic; base.VscrollbarPolicy = PolicyType.Automatic;
base.HscrollbarPolicy = PolicyType.Automatic; base.HscrollbarPolicy = PolicyType.Automatic;
@ -63,6 +66,11 @@ namespace AspNetEdit.Editor.UI
vbox = new VBox (); vbox = new VBox ();
base.AddWithViewport (vbox); base.AddWithViewport (vbox);
} }
public void tbsChanged (object sender, EventArgs e)
{
UpdateCategories ();
}
#region GUI population #region GUI population
@ -109,7 +117,8 @@ namespace AspNetEdit.Editor.UI
EventBox bottomWidget = new EventBox (); EventBox bottomWidget = new EventBox ();
bottomWidget.CanFocus = true; bottomWidget.CanFocus = true;
vbox.PackEnd (bottomWidget, true, true, 0); vbox.PackEnd (bottomWidget, true, true, 0);
} }
public void ResetCategory (string category) public void ResetCategory (string category)
{ {
if (!expanders.ContainsKey(category)) if (!expanders.ContainsKey(category))
@ -120,7 +129,13 @@ namespace AspNetEdit.Editor.UI
if (host == null) { if (host == null) {
expanders.Clear (); expanders.Clear ();
return; return;
} }
//kill existing items
VBox vb = new VBox ();
((Expander) (expanders[category])).Child.Destroy ();
((Expander) (expanders[category])).Child = vb;
//get the items and add them all //get the items and add them all
ToolboxItemCollection tools = toolboxService.GetToolboxItems (category, host); ToolboxItemCollection tools = toolboxService.GetToolboxItems (category, host);
@ -134,8 +149,10 @@ namespace AspNetEdit.Editor.UI
itemBox.ButtonReleaseEvent += new ButtonReleaseEventHandler (itemBox_ButtonReleaseEvent); itemBox.ButtonReleaseEvent += new ButtonReleaseEventHandler (itemBox_ButtonReleaseEvent);
itemBox.ButtonPressEvent += new ButtonPressEventHandler (itemBox_ButtonPressEvent); itemBox.ButtonPressEvent += new ButtonPressEventHandler (itemBox_ButtonPressEvent);
itemBox.MotionNotifyEvent += new MotionNotifyEventHandler (itemBox_MotionNotifyEvent); itemBox.MotionNotifyEvent += new MotionNotifyEventHandler (itemBox_MotionNotifyEvent);
((VBox) ((Expander) (expanders[category])).Child).PackEnd (itemBox, false, false, 0); vb.PackEnd (itemBox, false, false, 0);
} }
vb.ShowAll ();
} }
private class SortByName : IComparer private class SortByName : IComparer
@ -208,8 +225,13 @@ namespace AspNetEdit.Editor.UI
void selectedBox_DragDataGet (object o, DragDataGetArgs args) void selectedBox_DragDataGet (object o, DragDataGetArgs args)
{ {
ToolboxItemBox itemBox = (ToolboxItemBox) o; ToolboxItemBox itemBox = (ToolboxItemBox) o;
args.SelectionData.Text = (string) toolboxService.SerializeToolboxItem (itemBox.ToolboxItem); TextToolboxItem textItem = itemBox.ToolboxItem as TextToolboxItem;
if (textItem != null)
args.SelectionData.Text = textItem.Text;
else
args.SelectionData.Text = (string) toolboxService.SerializeToolboxItem (itemBox.ToolboxItem);
} }
void itemBox_ButtonReleaseEvent (object sender, ButtonReleaseEventArgs args) void itemBox_ButtonReleaseEvent (object sender, ButtonReleaseEventArgs args)
@ -226,7 +248,14 @@ namespace AspNetEdit.Editor.UI
ToolboxItemBox itemBox = (ToolboxItemBox) o; ToolboxItemBox itemBox = (ToolboxItemBox) o;
TargetEntry te = new TargetEntry (DragDropIdentifier, TargetFlags.App, 0); TargetEntry te;
if (itemBox.ToolboxItem is TextToolboxItem)
te = new TargetEntry ("text/plain", TargetFlags.App, 0);
else
te = new TargetEntry (DragDropIdentifier, TargetFlags.App, 0);
TargetList tl = new TargetList (new TargetEntry[] { te } ); TargetList tl = new TargetList (new TargetEntry[] { te } );
Gdk.DragContext context = Drag.Begin (itemBox, tl, Gdk.DragAction.Copy, 1, args.Event); Gdk.DragContext context = Drag.Begin (itemBox, tl, Gdk.DragAction.Copy, 1, args.Event);

Просмотреть файл

@ -53,7 +53,8 @@ EDITOR_CSFILES = \
$(srcdir)/AspNetEdit.Editor.Persistence/TagAttributes.cs \ $(srcdir)/AspNetEdit.Editor.Persistence/TagAttributes.cs \
$(srcdir)/AspNetEdit.Editor.Persistence/TagType.cs \ $(srcdir)/AspNetEdit.Editor.Persistence/TagType.cs \
$(srcdir)/AspNetEdit.Editor.ComponentModel/Document.cs \ $(srcdir)/AspNetEdit.Editor.ComponentModel/Document.cs \
$(srcdir)/AspNetEdit.Editor.ComponentModel/DocumentDirective.cs $(srcdir)/AspNetEdit.Editor.ComponentModel/DocumentDirective.cs \
$(srcdir)/AspNetEdit.Editor.ComponentModel/TextToolboxItem.cs
$(ASSEMBLY): $(EDITOR_CSFILES) $(ASSEMBLY): $(EDITOR_CSFILES)
$(MCS) $(MCS_OPTIONS) $(EDITOR_REFERENCES) -debug -target:library -out:$@ $(EDITOR_CSFILES) $(MCS) $(MCS_OPTIONS) $(EDITOR_REFERENCES) -debug -target:library -out:$@ $(EDITOR_CSFILES)

Просмотреть файл

@ -56,6 +56,7 @@
<File name="./AspNetEdit.Editor.Persistence/StrUtils.cs" subtype="Code" buildaction="Compile" /> <File name="./AspNetEdit.Editor.Persistence/StrUtils.cs" subtype="Code" buildaction="Compile" />
<File name="./AspNetEdit.Editor.Persistence/TagAttributes.cs" subtype="Code" buildaction="Compile" /> <File name="./AspNetEdit.Editor.Persistence/TagAttributes.cs" subtype="Code" buildaction="Compile" />
<File name="./AspNetEdit.Editor.Persistence/TagType.cs" subtype="Code" buildaction="Compile" /> <File name="./AspNetEdit.Editor.Persistence/TagType.cs" subtype="Code" buildaction="Compile" />
<File name="./AspNetEdit.Editor.ComponentModel/TextToolboxItem.cs" subtype="Code" buildaction="Compile" />
</Contents> </Contents>
<References> <References>
<ProjectReference type="Project" localcopy="True" refto="jscall" /> <ProjectReference type="Project" localcopy="True" refto="jscall" />

Просмотреть файл

@ -101,7 +101,8 @@ namespace AspNetEdit.JSCall
argsOut += "|" + args[i]; argsOut += "|" + args[i];
} }
} }
if (returnTo == null) returnTo = string.Empty;
int result = PlaceFunctionCall (webControl.Handle, function, returnTo, argsOut); int result = PlaceFunctionCall (webControl.Handle, function, returnTo, argsOut);
string err; string err;

Просмотреть файл

@ -97,9 +97,9 @@ int PlaceFunctionCall(GtkMozEmbed *embed, const PRUnichar *call, const PRUnichar
if(NS_FAILED(result) || !infunction) return 6; if(NS_FAILED(result) || !infunction) return 6;
//add the properties //add the properties
result = infunction->SetAttribute(NS_ConvertUTF8toUTF16("call"), nsString(call)); result = infunction->SetAttribute(NS_ConvertUTF8toUTF16("call"), nsDependentString(call));
result = infunction->SetAttribute(NS_ConvertUTF8toUTF16("returnto"), nsString(returnto)); result = infunction->SetAttribute(NS_ConvertUTF8toUTF16("returnto"), nsDependentString(returnto));
result = infunction->SetAttribute(NS_ConvertUTF8toUTF16("args"), nsString(args)); result = infunction->SetAttribute(NS_ConvertUTF8toUTF16("args"), nsDependentString(args));
if(NS_FAILED(result)) return 7; if(NS_FAILED(result)) return 7;
//append it to the jscall node //append it to the jscall node