Browse Source
ResourceCodeGeneratorTool: Set BasePath so that relative file references inside ResX files work. ParserService.GetParseableFileContent can now retrieve the file content from an OpenedFile if that exists. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@3534 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
20 changed files with 1903 additions and 5 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,247 @@
@@ -0,0 +1,247 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Christian Hornung" email="chhornung@googlemail.com"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
namespace ICSharpCode.FormsDesigner.Gui |
||||
{ |
||||
partial class ImageResourceEditorDialog |
||||
{ |
||||
/// <summary>
|
||||
/// Designer variable used to keep track of non-visual components.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null; |
||||
|
||||
/// <summary>
|
||||
/// Disposes resources used by the form.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing) |
||||
{ |
||||
if (disposing) { |
||||
if (components != null) { |
||||
components.Dispose(); |
||||
} |
||||
} |
||||
base.Dispose(disposing); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// This method is required for Windows Forms designer support.
|
||||
/// Do not change the method contents inside the source code editor. The Forms designer might
|
||||
/// not be able to load this method if it was changed manually.
|
||||
/// </summary>
|
||||
private void InitializeComponent() |
||||
{ |
||||
System.Windows.Forms.Button cancelButton; |
||||
System.Windows.Forms.SplitContainer splitContainer; |
||||
System.Windows.Forms.GroupBox resourceSelectionGroup; |
||||
System.Windows.Forms.GroupBox previewGroup; |
||||
this.projectResourcesTreeView = new System.Windows.Forms.TreeView(); |
||||
this.projectResourceRadioButton = new System.Windows.Forms.RadioButton(); |
||||
this.importLocalResourceButton = new System.Windows.Forms.Button(); |
||||
this.noResourceRadioButton = new System.Windows.Forms.RadioButton(); |
||||
this.localResourceRadioButton = new System.Windows.Forms.RadioButton(); |
||||
this.previewPictureBox = new System.Windows.Forms.PictureBox(); |
||||
this.okButton = new System.Windows.Forms.Button(); |
||||
this.projectTreeScanningBackgroundWorker = new System.ComponentModel.BackgroundWorker(); |
||||
cancelButton = new System.Windows.Forms.Button(); |
||||
splitContainer = new System.Windows.Forms.SplitContainer(); |
||||
resourceSelectionGroup = new System.Windows.Forms.GroupBox(); |
||||
previewGroup = new System.Windows.Forms.GroupBox(); |
||||
splitContainer.Panel1.SuspendLayout(); |
||||
splitContainer.Panel2.SuspendLayout(); |
||||
splitContainer.SuspendLayout(); |
||||
resourceSelectionGroup.SuspendLayout(); |
||||
previewGroup.SuspendLayout(); |
||||
((System.ComponentModel.ISupportInitialize)(this.previewPictureBox)).BeginInit(); |
||||
this.SuspendLayout(); |
||||
//
|
||||
// cancelButton
|
||||
//
|
||||
cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); |
||||
cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; |
||||
cancelButton.Location = new System.Drawing.Point(509, 317); |
||||
cancelButton.Name = "cancelButton"; |
||||
cancelButton.Size = new System.Drawing.Size(75, 23); |
||||
cancelButton.TabIndex = 1; |
||||
cancelButton.Text = "${res:Global.CancelButtonText}"; |
||||
cancelButton.UseVisualStyleBackColor = true; |
||||
//
|
||||
// splitContainer
|
||||
//
|
||||
splitContainer.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) |
||||
| System.Windows.Forms.AnchorStyles.Left) |
||||
| System.Windows.Forms.AnchorStyles.Right))); |
||||
splitContainer.Location = new System.Drawing.Point(12, 12); |
||||
splitContainer.Name = "splitContainer"; |
||||
//
|
||||
// splitContainer.Panel1
|
||||
//
|
||||
splitContainer.Panel1.Controls.Add(resourceSelectionGroup); |
||||
//
|
||||
// splitContainer.Panel2
|
||||
//
|
||||
splitContainer.Panel2.Controls.Add(previewGroup); |
||||
splitContainer.Size = new System.Drawing.Size(572, 299); |
||||
splitContainer.SplitterDistance = 280; |
||||
splitContainer.TabIndex = 2; |
||||
//
|
||||
// resourceSelectionGroup
|
||||
//
|
||||
resourceSelectionGroup.Controls.Add(this.projectResourcesTreeView); |
||||
resourceSelectionGroup.Controls.Add(this.projectResourceRadioButton); |
||||
resourceSelectionGroup.Controls.Add(this.importLocalResourceButton); |
||||
resourceSelectionGroup.Controls.Add(this.noResourceRadioButton); |
||||
resourceSelectionGroup.Controls.Add(this.localResourceRadioButton); |
||||
resourceSelectionGroup.Dock = System.Windows.Forms.DockStyle.Fill; |
||||
resourceSelectionGroup.Location = new System.Drawing.Point(0, 0); |
||||
resourceSelectionGroup.Name = "resourceSelectionGroup"; |
||||
resourceSelectionGroup.Size = new System.Drawing.Size(280, 299); |
||||
resourceSelectionGroup.TabIndex = 0; |
||||
resourceSelectionGroup.TabStop = false; |
||||
//
|
||||
// projectResourcesTreeView
|
||||
//
|
||||
this.projectResourcesTreeView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) |
||||
| System.Windows.Forms.AnchorStyles.Left) |
||||
| System.Windows.Forms.AnchorStyles.Right))); |
||||
this.projectResourcesTreeView.HideSelection = false; |
||||
this.projectResourcesTreeView.Location = new System.Drawing.Point(26, 138); |
||||
this.projectResourcesTreeView.Name = "projectResourcesTreeView"; |
||||
this.projectResourcesTreeView.Size = new System.Drawing.Size(248, 155); |
||||
this.projectResourcesTreeView.TabIndex = 4; |
||||
this.projectResourcesTreeView.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.ProjectResourcesTreeViewAfterSelect); |
||||
//
|
||||
// projectResourceRadioButton
|
||||
//
|
||||
this.projectResourceRadioButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) |
||||
| System.Windows.Forms.AnchorStyles.Right))); |
||||
this.projectResourceRadioButton.Location = new System.Drawing.Point(6, 108); |
||||
this.projectResourceRadioButton.Name = "projectResourceRadioButton"; |
||||
this.projectResourceRadioButton.Size = new System.Drawing.Size(268, 24); |
||||
this.projectResourceRadioButton.TabIndex = 3; |
||||
this.projectResourceRadioButton.TabStop = true; |
||||
this.projectResourceRadioButton.Text = "${res:ICSharpCode.SharpDevelop.FormDesigner.Gui.ImageResourceEditor.ProjectResour" + |
||||
"ceButton}"; |
||||
this.projectResourceRadioButton.UseVisualStyleBackColor = true; |
||||
this.projectResourceRadioButton.CheckedChanged += new System.EventHandler(this.ProjectResourceRadioButtonCheckedChanged); |
||||
//
|
||||
// importLocalResourceButton
|
||||
//
|
||||
this.importLocalResourceButton.Location = new System.Drawing.Point(26, 79); |
||||
this.importLocalResourceButton.Name = "importLocalResourceButton"; |
||||
this.importLocalResourceButton.Size = new System.Drawing.Size(126, 23); |
||||
this.importLocalResourceButton.TabIndex = 2; |
||||
this.importLocalResourceButton.Text = "${res:ICSharpCode.SharpDevelop.FormDesigner.Gui.ImageResourceEditor.ImportLocalRe" + |
||||
"sourceButton}"; |
||||
this.importLocalResourceButton.UseVisualStyleBackColor = true; |
||||
this.importLocalResourceButton.Click += new System.EventHandler(this.ImportLocalResourceButtonClick); |
||||
//
|
||||
// noResourceRadioButton
|
||||
//
|
||||
this.noResourceRadioButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) |
||||
| System.Windows.Forms.AnchorStyles.Right))); |
||||
this.noResourceRadioButton.Location = new System.Drawing.Point(6, 19); |
||||
this.noResourceRadioButton.Name = "noResourceRadioButton"; |
||||
this.noResourceRadioButton.Size = new System.Drawing.Size(268, 24); |
||||
this.noResourceRadioButton.TabIndex = 0; |
||||
this.noResourceRadioButton.TabStop = true; |
||||
this.noResourceRadioButton.Text = "${res:ICSharpCode.SharpDevelop.FormDesigner.Gui.ImageResourceEditor.NoResourceBut" + |
||||
"ton}"; |
||||
this.noResourceRadioButton.UseVisualStyleBackColor = true; |
||||
this.noResourceRadioButton.CheckedChanged += new System.EventHandler(this.NoResourceRadioButtonCheckedChanged); |
||||
//
|
||||
// localResourceRadioButton
|
||||
//
|
||||
this.localResourceRadioButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) |
||||
| System.Windows.Forms.AnchorStyles.Right))); |
||||
this.localResourceRadioButton.Location = new System.Drawing.Point(6, 49); |
||||
this.localResourceRadioButton.Name = "localResourceRadioButton"; |
||||
this.localResourceRadioButton.Size = new System.Drawing.Size(268, 24); |
||||
this.localResourceRadioButton.TabIndex = 1; |
||||
this.localResourceRadioButton.TabStop = true; |
||||
this.localResourceRadioButton.Text = "${res:ICSharpCode.SharpDevelop.FormDesigner.Gui.ImageResourceEditor.LocalResource" + |
||||
"Button}"; |
||||
this.localResourceRadioButton.UseVisualStyleBackColor = true; |
||||
this.localResourceRadioButton.CheckedChanged += new System.EventHandler(this.LocalResourceRadioButtonCheckedChanged); |
||||
//
|
||||
// previewGroup
|
||||
//
|
||||
previewGroup.Controls.Add(this.previewPictureBox); |
||||
previewGroup.Dock = System.Windows.Forms.DockStyle.Fill; |
||||
previewGroup.Location = new System.Drawing.Point(0, 0); |
||||
previewGroup.Name = "previewGroup"; |
||||
previewGroup.Size = new System.Drawing.Size(288, 299); |
||||
previewGroup.TabIndex = 0; |
||||
previewGroup.TabStop = false; |
||||
previewGroup.Text = "${res:ICSharpCode.SharpDevelop.FormDesigner.Gui.ImageResourceEditor.Preview}"; |
||||
//
|
||||
// previewPictureBox
|
||||
//
|
||||
this.previewPictureBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) |
||||
| System.Windows.Forms.AnchorStyles.Left) |
||||
| System.Windows.Forms.AnchorStyles.Right))); |
||||
this.previewPictureBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; |
||||
this.previewPictureBox.Location = new System.Drawing.Point(6, 19); |
||||
this.previewPictureBox.Name = "previewPictureBox"; |
||||
this.previewPictureBox.Size = new System.Drawing.Size(276, 274); |
||||
this.previewPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; |
||||
this.previewPictureBox.TabIndex = 0; |
||||
this.previewPictureBox.TabStop = false; |
||||
//
|
||||
// okButton
|
||||
//
|
||||
this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); |
||||
this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK; |
||||
this.okButton.Location = new System.Drawing.Point(428, 317); |
||||
this.okButton.Name = "okButton"; |
||||
this.okButton.Size = new System.Drawing.Size(75, 23); |
||||
this.okButton.TabIndex = 0; |
||||
this.okButton.Text = "${res:Global.OKButtonText}"; |
||||
this.okButton.UseVisualStyleBackColor = true; |
||||
//
|
||||
// projectTreeScanningBackgroundWorker
|
||||
//
|
||||
this.projectTreeScanningBackgroundWorker.WorkerSupportsCancellation = true; |
||||
this.projectTreeScanningBackgroundWorker.DoWork += new System.ComponentModel.DoWorkEventHandler(this.ProjectTreeScanningBackgroundWorkerDoWork); |
||||
this.projectTreeScanningBackgroundWorker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.ProjectTreeScanningBackgroundWorkerRunWorkerCompleted); |
||||
//
|
||||
// ImageResourceEditorDialog
|
||||
//
|
||||
this.AcceptButton = this.okButton; |
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); |
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; |
||||
this.CancelButton = cancelButton; |
||||
this.ClientSize = new System.Drawing.Size(596, 352); |
||||
this.Controls.Add(splitContainer); |
||||
this.Controls.Add(cancelButton); |
||||
this.Controls.Add(this.okButton); |
||||
this.MaximizeBox = false; |
||||
this.MinimizeBox = false; |
||||
this.Name = "ImageResourceEditorDialog"; |
||||
this.ShowIcon = false; |
||||
this.ShowInTaskbar = false; |
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; |
||||
this.Text = "${res:ICSharpCode.SharpDevelop.FormDesigner.Gui.ImageResourceEditor.Title}"; |
||||
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.ImageResourceEditorDialogFormClosed); |
||||
splitContainer.Panel1.ResumeLayout(false); |
||||
splitContainer.Panel2.ResumeLayout(false); |
||||
splitContainer.ResumeLayout(false); |
||||
resourceSelectionGroup.ResumeLayout(false); |
||||
previewGroup.ResumeLayout(false); |
||||
((System.ComponentModel.ISupportInitialize)(this.previewPictureBox)).EndInit(); |
||||
this.ResumeLayout(false); |
||||
} |
||||
private System.ComponentModel.BackgroundWorker projectTreeScanningBackgroundWorker; |
||||
private System.Windows.Forms.RadioButton noResourceRadioButton; |
||||
private System.Windows.Forms.Button importLocalResourceButton; |
||||
private System.Windows.Forms.RadioButton projectResourceRadioButton; |
||||
private System.Windows.Forms.TreeView projectResourcesTreeView; |
||||
private System.Windows.Forms.RadioButton localResourceRadioButton; |
||||
private System.Windows.Forms.PictureBox previewPictureBox; |
||||
private System.Windows.Forms.Button okButton; |
||||
} |
||||
} |
@ -0,0 +1,571 @@
@@ -0,0 +1,571 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Christian Hornung" email="chhornung@googlemail.com"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.ComponentModel; |
||||
using System.Drawing; |
||||
using System.Drawing.Design; |
||||
using System.IO; |
||||
using System.Linq; |
||||
using System.Resources; |
||||
using System.Resources.Tools; |
||||
using System.Windows.Forms; |
||||
|
||||
using ICSharpCode.Core; |
||||
using ICSharpCode.Core.WinForms; |
||||
using ICSharpCode.FormsDesigner.Services; |
||||
using ICSharpCode.SharpDevelop; |
||||
using ICSharpCode.SharpDevelop.Dom; |
||||
using ICSharpCode.SharpDevelop.Project; |
||||
|
||||
namespace ICSharpCode.FormsDesigner.Gui |
||||
{ |
||||
/// <summary>
|
||||
/// Allows the user to select a resource for an image or icon property.
|
||||
/// </summary>
|
||||
public sealed partial class ImageResourceEditorDialog : Form |
||||
{ |
||||
readonly IProject project; |
||||
readonly Type requiredResourceType; |
||||
object originalImage; |
||||
bool selectedImageIsProjectResource; |
||||
object selectedImage; |
||||
|
||||
#region Constructors
|
||||
|
||||
ImageResourceEditorDialog(IProject project, Type requiredResourceType) |
||||
: base() |
||||
{ |
||||
if (requiredResourceType == null) |
||||
throw new ArgumentNullException("requiredResourceType"); |
||||
this.requiredResourceType = requiredResourceType; |
||||
this.project = project; |
||||
|
||||
//
|
||||
// The InitializeComponent() call is required for Windows Forms designer support.
|
||||
//
|
||||
InitializeComponent(); |
||||
Translate(this); |
||||
|
||||
this.projectResourcesTreeView.Nodes.Add(ResourceService.GetString("Global.PleaseWait")); |
||||
|
||||
this.importLocalResourceButton.DataBindings.Add("Enabled", this.localResourceRadioButton, "Checked"); |
||||
this.projectResourcesTreeView.DataBindings.Add("Enabled", this.projectResourceRadioButton, "Checked"); |
||||
} |
||||
|
||||
public ImageResourceEditorDialog(IProject project, Type requiredResourceType, ProjectResourceInfo projectResource) |
||||
: this(project, requiredResourceType) |
||||
{ |
||||
if (projectResource == null) |
||||
throw new ArgumentNullException("projectResource"); |
||||
|
||||
this.projectResourceRadioButton.Checked = true; |
||||
this.originalImage = this.selectedImage = projectResource.OriginalValue; |
||||
|
||||
Image image = this.selectedImage as Image; |
||||
if (image != null) { |
||||
this.selectedImageIsProjectResource = true; |
||||
this.SetPreviewImage(image); |
||||
} else { |
||||
Icon icon = this.selectedImage as Icon; |
||||
if (icon != null) { |
||||
this.selectedImageIsProjectResource = true; |
||||
this.SetPreviewImage(icon.ToBitmap()); |
||||
} |
||||
} |
||||
this.projectTreeScanningBackgroundWorker.RunWorkerAsync(projectResource); |
||||
} |
||||
|
||||
public ImageResourceEditorDialog(IProject project, Image localResource) |
||||
: this(project, typeof(Image)) |
||||
{ |
||||
if (localResource != null) { |
||||
this.localResourceRadioButton.Checked = true; |
||||
this.originalImage = this.selectedImage = localResource; |
||||
this.SetPreviewImage(localResource); |
||||
} else { |
||||
this.noResourceRadioButton.Checked = true; |
||||
} |
||||
this.projectTreeScanningBackgroundWorker.RunWorkerAsync(); |
||||
} |
||||
|
||||
public ImageResourceEditorDialog(IProject project, Icon localResource) |
||||
: this(project, typeof(Icon)) |
||||
{ |
||||
if (localResource != null) { |
||||
this.localResourceRadioButton.Checked = true; |
||||
this.originalImage = this.selectedImage = localResource; |
||||
this.SetPreviewImage(localResource.ToBitmap()); |
||||
} else { |
||||
this.noResourceRadioButton.Checked = true; |
||||
} |
||||
this.projectTreeScanningBackgroundWorker.RunWorkerAsync(); |
||||
} |
||||
|
||||
static void Translate(Control c) |
||||
{ |
||||
c.Text = StringParser.Parse(c.Text); |
||||
foreach (Control child in c.Controls) { |
||||
Translate(child); |
||||
} |
||||
} |
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ProjectResourceInfo"/> for the selected project resource,
|
||||
/// or <c>null</c> if the selected resource is not a project resource.
|
||||
/// </summary>
|
||||
public ProjectResourceInfo SelectedProjectResource { |
||||
get { |
||||
if (this.selectedImageIsProjectResource && this.projectResourceRadioButton.Checked) { |
||||
|
||||
TreeNode node = this.projectResourcesTreeView.SelectedNode; |
||||
if (node == null) return null; |
||||
|
||||
return new ProjectResourceInfo(((FileProjectItem)node.Parent.Tag).FileName, node.Text); |
||||
|
||||
} else { |
||||
return null; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets the selected image.
|
||||
/// This can be an Image or an Icon (matching the type that was passed to the constructor) or null.
|
||||
/// </summary>
|
||||
public object SelectedResourceValue { |
||||
get { |
||||
return this.selectedImage; |
||||
} |
||||
} |
||||
|
||||
#endregion
|
||||
|
||||
void SetPreviewImage(Image image) |
||||
{ |
||||
this.previewPictureBox.Image = image; |
||||
if (image != null) { |
||||
if (image.Width > this.previewPictureBox.ClientSize.Width || |
||||
image.Height > this.previewPictureBox.ClientSize.Height) { |
||||
this.previewPictureBox.SizeMode = PictureBoxSizeMode.Zoom; |
||||
} else { |
||||
this.previewPictureBox.SizeMode = PictureBoxSizeMode.CenterImage; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void DisposeImageIfNotOriginal(object image) |
||||
{ |
||||
if (!Object.ReferenceEquals(image, this.originalImage)) { |
||||
IDisposable d = image as IDisposable; |
||||
if (d != null) { |
||||
d.Dispose(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void SetSelectedImage(object image, bool isProjectResource) |
||||
{ |
||||
if (!Object.ReferenceEquals(this.selectedImage, this.previewPictureBox.Image)) { |
||||
Image temp = this.previewPictureBox.Image; |
||||
this.previewPictureBox.Image = null; |
||||
this.DisposeImageIfNotOriginal(temp); |
||||
} else { |
||||
this.previewPictureBox.Image = null; |
||||
} |
||||
|
||||
if (!this.selectedImageIsProjectResource) { |
||||
this.DisposeImageIfNotOriginal(this.selectedImage); |
||||
} |
||||
|
||||
Image img = image as Image; |
||||
if (img != null) { |
||||
this.selectedImage = img; |
||||
this.selectedImageIsProjectResource = isProjectResource; |
||||
this.SetPreviewImage(img); |
||||
} else { |
||||
Icon icon = image as Icon; |
||||
if (icon != null) { |
||||
this.selectedImage = icon; |
||||
this.selectedImageIsProjectResource = isProjectResource; |
||||
this.SetPreviewImage(icon.ToBitmap()); |
||||
} else { |
||||
this.selectedImageIsProjectResource = false; |
||||
this.selectedImage = null; |
||||
} |
||||
} |
||||
} |
||||
|
||||
#region Project tree filling
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] |
||||
void ProjectTreeScanningBackgroundWorkerDoWork(object sender, DoWorkEventArgs e) |
||||
{ |
||||
if (this.project == null) { |
||||
return; |
||||
} |
||||
|
||||
ProjectResourceInfo selectedProjectResource = e.Argument as ProjectResourceInfo; |
||||
|
||||
IProjectContent projectContent = ParserService.GetProjectContent(this.project); |
||||
|
||||
TreeNode root = new TreeNode(this.project.Name, 0, 0); |
||||
TreeNode preSelection = null; |
||||
TreeNode lastFileNode = null; |
||||
int fileNodesCount = 0; |
||||
|
||||
foreach (FileProjectItem item in this.project.GetItemsOfType(ItemType.EmbeddedResource).OfType<FileProjectItem>().OrderBy(fpi => Path.GetFileName(fpi.VirtualName))) { |
||||
|
||||
if (this.projectTreeScanningBackgroundWorker.CancellationPending) { |
||||
e.Cancel = true; |
||||
break; |
||||
} |
||||
|
||||
// Skip files where the generated class name
|
||||
// would conflict with an existing class.
|
||||
string namespaceName = item.GetEvaluatedMetadata("CustomToolNamespace"); |
||||
if (string.IsNullOrEmpty(namespaceName)) { |
||||
namespaceName = CustomToolsService.GetDefaultNamespace(item.Project, item.FileName); |
||||
} |
||||
IClass existingClass = projectContent.GetClass(namespaceName + "." + StronglyTypedResourceBuilder.VerifyResourceName(Path.GetFileNameWithoutExtension(item.FileName), projectContent.Language.CodeDomProvider), 0); |
||||
if (existingClass != null) { |
||||
if (!ProjectResourceService.IsGeneratedResourceClass(existingClass)) { |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
bool selectedFile = (selectedProjectResource != null) && FileUtility.IsEqualFileName(selectedProjectResource.ResourceFile, item.FileName); |
||||
TreeNode file = null; |
||||
|
||||
try { |
||||
|
||||
foreach (KeyValuePair<string, object> r in this.GetResources(item.FileName).OrderBy(pair => pair.Key)) { |
||||
if (this.projectTreeScanningBackgroundWorker.CancellationPending) { |
||||
e.Cancel = true; |
||||
break; |
||||
} |
||||
|
||||
if (file == null) { |
||||
file = CreateAndAddFileNode(root, item); |
||||
} |
||||
|
||||
TreeNode resNode = new TreeNode(r.Key, 3, 3); |
||||
resNode.Tag = r.Value; |
||||
file.Nodes.Add(resNode); |
||||
|
||||
if (selectedFile) { |
||||
if (String.Equals(r.Key, selectedProjectResource.ResourceKey, StringComparison.Ordinal)) { |
||||
preSelection = resNode; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (file != null) { |
||||
lastFileNode = file; |
||||
++fileNodesCount; |
||||
} |
||||
|
||||
} catch (Exception ex) { |
||||
if (file == null) { |
||||
file = CreateAndAddFileNode(root, item); |
||||
} |
||||
TreeNode error = new TreeNode(ex.Message, 4, 4); |
||||
file.Nodes.Add(error); |
||||
} |
||||
} |
||||
|
||||
if (e.Cancel) { |
||||
DisposeNodeImages(root); |
||||
} else { |
||||
// Preselect the file node if there is only one
|
||||
if (preSelection == null && fileNodesCount == 1) { |
||||
preSelection = lastFileNode; |
||||
} |
||||
e.Result = new TreeScanResult(root, preSelection); |
||||
} |
||||
} |
||||
|
||||
sealed class TreeScanResult { |
||||
readonly TreeNode root; |
||||
readonly TreeNode preSelection; |
||||
|
||||
public TreeNode Root { |
||||
get { return root; } |
||||
} |
||||
|
||||
public TreeNode PreSelection { |
||||
get { return preSelection; } |
||||
} |
||||
|
||||
public TreeScanResult(TreeNode root, TreeNode preSelection) |
||||
{ |
||||
this.root = root; |
||||
this.preSelection = preSelection; |
||||
} |
||||
} |
||||
|
||||
static TreeNode CreateAndAddFileNode(TreeNode root, FileProjectItem item) |
||||
{ |
||||
string directory = Path.GetDirectoryName(item.VirtualName); |
||||
TreeNode dir; |
||||
|
||||
if (String.IsNullOrEmpty(directory)) { |
||||
dir = root; |
||||
} else { |
||||
dir = GetOrCreateDirectoryNode(root, directory); |
||||
} |
||||
|
||||
TreeNode file = new TreeNode(Path.GetFileName(item.VirtualName), 2, 2); |
||||
file.Tag = item; |
||||
dir.Nodes.Add(file); |
||||
return file; |
||||
} |
||||
|
||||
static TreeNode GetOrCreateDirectoryNode(TreeNode root, string directory) |
||||
{ |
||||
int index = directory.IndexOfAny(new [] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}); |
||||
string searchDir; |
||||
|
||||
if (index == -1) { |
||||
searchDir = directory; |
||||
} else { |
||||
searchDir = directory.Substring(0, index); |
||||
} |
||||
|
||||
TreeNode node = null; |
||||
foreach (TreeNode n in root.Nodes) { |
||||
if (n.Text == searchDir) { |
||||
node = n; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (node == null) { |
||||
node = new TreeNode(searchDir, 1, 1); |
||||
int insertIndex; |
||||
for (insertIndex = 0; insertIndex < root.Nodes.Count; insertIndex++) { |
||||
TreeNode n = root.Nodes[insertIndex]; |
||||
if (n.ImageIndex != 1 || StringComparer.CurrentCulture.Compare(searchDir, n.Text) < 0) { |
||||
break; |
||||
} |
||||
} |
||||
root.Nodes.Insert(insertIndex, node); |
||||
} |
||||
|
||||
if (index == -1) { |
||||
return node; |
||||
} else { |
||||
return GetOrCreateDirectoryNode(node, directory.Substring(index + 1)); |
||||
} |
||||
} |
||||
|
||||
Dictionary<string, object> GetResources(string fileName) |
||||
{ |
||||
Stream s; |
||||
OpenedFile file = FileService.GetOpenedFile(fileName); |
||||
if (file != null) { |
||||
s = file.OpenRead(); |
||||
} else { |
||||
s = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); |
||||
} |
||||
using(s) { |
||||
using(IResourceReader reader = ResourceStore.CreateResourceReader(s, ResourceStore.GetResourceType(fileName))) { |
||||
ResXResourceReader resXReader = reader as ResXResourceReader; |
||||
if (resXReader != null) { |
||||
resXReader.BasePath = Path.GetDirectoryName(fileName); |
||||
} |
||||
|
||||
var resources = new Dictionary<string, object>(); |
||||
foreach (System.Collections.DictionaryEntry entry in reader) { |
||||
if (entry.Value == null) continue; |
||||
if (this.requiredResourceType.IsAssignableFrom(entry.Value.GetType())) { |
||||
resources.Add((string)entry.Key, entry.Value); |
||||
} |
||||
} |
||||
return resources; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void ProjectTreeScanningBackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) |
||||
{ |
||||
if (this.IsDisposed || this.projectResourcesTreeView.IsDisposed) { |
||||
// This can happen when the dialog is closed before
|
||||
// the scan has finished
|
||||
if (!e.Cancelled && e.Error == null) { |
||||
TreeScanResult r = e.Result as TreeScanResult; |
||||
if (r != null) { |
||||
DisposeNodeImages(r.Root); |
||||
} |
||||
} |
||||
return; |
||||
} |
||||
|
||||
this.projectResourcesTreeView.Nodes.Clear(); |
||||
|
||||
if (e.Cancelled) { |
||||
return; |
||||
} |
||||
|
||||
if (e.Error != null) { |
||||
MessageService.ShowError(e.Error, "Error in project tree scanning thread"); |
||||
} |
||||
|
||||
TreeScanResult result = e.Result as TreeScanResult; |
||||
if (result == null) { |
||||
return; |
||||
} |
||||
|
||||
this.projectResourcesTreeView.BeginUpdate(); |
||||
|
||||
ImageList imageList = new ImageList(); |
||||
imageList.ColorDepth = ColorDepth.Depth32Bit; |
||||
imageList.Images.Add(IconService.GetBitmap(IconService.GetImageForProjectType(this.project.Language))); |
||||
imageList.Images.Add(WinFormsResourceService.GetBitmap("ProjectBrowser.Folder.Closed")); |
||||
imageList.Images.Add(IconService.GetBitmap(IconService.GetImageForFile("a.resx"))); |
||||
imageList.Images.Add(WinFormsResourceService.GetBitmap("Icons.16x16.Field")); |
||||
imageList.Images.Add(WinFormsResourceService.GetBitmap("Icons.16x16.Error")); |
||||
this.projectResourcesTreeView.ImageList = imageList; |
||||
|
||||
this.projectResourcesTreeView.Nodes.Add(result.Root); |
||||
|
||||
if (result.PreSelection != null) { |
||||
result.PreSelection.EnsureVisible(); |
||||
this.projectResourcesTreeView.SelectedNode = result.PreSelection; |
||||
result.PreSelection.Expand(); |
||||
} else { |
||||
result.Root.Expand(); |
||||
} |
||||
|
||||
this.projectResourcesTreeView.EndUpdate(); |
||||
|
||||
if (result.PreSelection != null) { |
||||
this.projectResourcesTreeView.Focus(); |
||||
} |
||||
} |
||||
|
||||
#endregion
|
||||
|
||||
void NoResourceRadioButtonCheckedChanged(object sender, EventArgs e) |
||||
{ |
||||
if (this.noResourceRadioButton.Checked) { |
||||
this.SetSelectedImage(null, false); |
||||
this.okButton.Enabled = true; |
||||
} |
||||
} |
||||
|
||||
void LocalResourceRadioButtonCheckedChanged(object sender, EventArgs e) |
||||
{ |
||||
if (this.localResourceRadioButton.Checked) { |
||||
this.okButton.Enabled = true; |
||||
} |
||||
} |
||||
|
||||
void ProjectResourceRadioButtonCheckedChanged(object sender, EventArgs e) |
||||
{ |
||||
if (this.projectResourceRadioButton.Checked) { |
||||
this.UpdateOnProjectResourceSelection(); |
||||
this.projectResourcesTreeView.Focus(); |
||||
} |
||||
} |
||||
|
||||
void ProjectResourcesTreeViewAfterSelect(object sender, TreeViewEventArgs e) |
||||
{ |
||||
this.UpdateOnProjectResourceSelection(); |
||||
} |
||||
|
||||
void UpdateOnProjectResourceSelection() |
||||
{ |
||||
TreeNode node = this.projectResourcesTreeView.SelectedNode; |
||||
if (node != null && node.Tag != null && this.requiredResourceType.IsAssignableFrom(node.Tag.GetType())) { |
||||
this.SetSelectedImage(node.Tag, true); |
||||
this.okButton.Enabled = true; |
||||
} else { |
||||
this.SetSelectedImage(null, false); |
||||
this.okButton.Enabled = false; |
||||
} |
||||
} |
||||
|
||||
void ImageResourceEditorDialogFormClosed(object sender, FormClosedEventArgs e) |
||||
{ |
||||
this.projectTreeScanningBackgroundWorker.CancelAsync(); |
||||
if (this.projectResourcesTreeView.Nodes.Count > 0) { |
||||
DisposeNodeImages(this.projectResourcesTreeView.Nodes[0]); |
||||
} |
||||
} |
||||
|
||||
static void DisposeNodeImages(TreeNode root) |
||||
{ |
||||
if (root.Nodes.Count == 0) { |
||||
IDisposable d = root.Tag as IDisposable; |
||||
if (d != null) { |
||||
d.Dispose(); |
||||
} |
||||
root.Tag = null; |
||||
} else { |
||||
foreach (TreeNode node in root.Nodes) { |
||||
DisposeNodeImages(node); |
||||
} |
||||
} |
||||
} |
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] |
||||
void ImportLocalResourceButtonClick(object sender, EventArgs e) |
||||
{ |
||||
bool isIcon = typeof(Icon).IsAssignableFrom(this.requiredResourceType); |
||||
using(OpenFileDialog dialog = new OpenFileDialog()) { |
||||
dialog.Filter = (isIcon ? DummyIconEditor.FileFilterEntry : DummyImageEditor.FileFilterEntry); |
||||
dialog.RestoreDirectory = true; |
||||
dialog.Title = StringParser.Parse("${res:ICSharpCode.SharpDevelop.FormDesigner.Gui.ImageResourceEditor.Title}"); |
||||
if (dialog.ShowDialog(this) == DialogResult.OK && !String.IsNullOrEmpty(dialog.FileName)) { |
||||
try { |
||||
|
||||
if (isIcon) { |
||||
this.SetSelectedImage(new Icon(dialog.FileName), false); |
||||
} else { |
||||
this.SetSelectedImage(Image.FromFile(dialog.FileName), false); |
||||
} |
||||
|
||||
} catch (Exception ex) { |
||||
MessageService.ShowError(ex.Message); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
#region Dummy editors for getting the file filter from the framework
|
||||
|
||||
sealed class DummyImageEditor : ImageEditor |
||||
{ |
||||
DummyImageEditor() |
||||
{ |
||||
} |
||||
|
||||
internal static string FileFilterEntry { |
||||
get { return CreateFilterEntry(new ImageEditor()); } |
||||
} |
||||
} |
||||
|
||||
sealed class DummyIconEditor : IconEditor |
||||
{ |
||||
DummyIconEditor() |
||||
{ |
||||
} |
||||
|
||||
internal static string FileFilterEntry { |
||||
get { return CreateFilterEntry(new IconEditor()); } |
||||
} |
||||
} |
||||
|
||||
#endregion
|
||||
} |
||||
} |
@ -0,0 +1,135 @@
@@ -0,0 +1,135 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<root> |
||||
<!-- |
||||
Microsoft ResX Schema |
||||
|
||||
Version 2.0 |
||||
|
||||
The primary goals of this format is to allow a simple XML format |
||||
that is mostly human readable. The generation and parsing of the |
||||
various data types are done through the TypeConverter classes |
||||
associated with the data types. |
||||
|
||||
Example: |
||||
|
||||
... ado.net/XML headers & schema ... |
||||
<resheader name="resmimetype">text/microsoft-resx</resheader> |
||||
<resheader name="version">2.0</resheader> |
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> |
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> |
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> |
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> |
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> |
||||
<value>[base64 mime encoded serialized .NET Framework object]</value> |
||||
</data> |
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> |
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> |
||||
<comment>This is a comment</comment> |
||||
</data> |
||||
|
||||
There are any number of "resheader" rows that contain simple |
||||
name/value pairs. |
||||
|
||||
Each data row contains a name, and value. The row also contains a |
||||
type or mimetype. Type corresponds to a .NET class that support |
||||
text/value conversion through the TypeConverter architecture. |
||||
Classes that don't support this are serialized and stored with the |
||||
mimetype set. |
||||
|
||||
The mimetype is used for serialized objects, and tells the |
||||
ResXResourceReader how to depersist the object. This is currently not |
||||
extensible. For a given mimetype the value must be set accordingly: |
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format |
||||
that the ResXResourceWriter will generate, however the reader can |
||||
read any of the formats listed below. |
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64 |
||||
value : The object must be serialized with |
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter |
||||
: and then encoded with base64 encoding. |
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64 |
||||
value : The object must be serialized with |
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter |
||||
: and then encoded with base64 encoding. |
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64 |
||||
value : The object must be serialized into a byte array |
||||
: using a System.ComponentModel.TypeConverter |
||||
: and then encoded with base64 encoding. |
||||
--> |
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> |
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> |
||||
<xsd:element name="root" msdata:IsDataSet="true"> |
||||
<xsd:complexType> |
||||
<xsd:choice maxOccurs="unbounded"> |
||||
<xsd:element name="metadata"> |
||||
<xsd:complexType> |
||||
<xsd:sequence> |
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" /> |
||||
</xsd:sequence> |
||||
<xsd:attribute name="name" use="required" type="xsd:string" /> |
||||
<xsd:attribute name="type" type="xsd:string" /> |
||||
<xsd:attribute name="mimetype" type="xsd:string" /> |
||||
<xsd:attribute ref="xml:space" /> |
||||
</xsd:complexType> |
||||
</xsd:element> |
||||
<xsd:element name="assembly"> |
||||
<xsd:complexType> |
||||
<xsd:attribute name="alias" type="xsd:string" /> |
||||
<xsd:attribute name="name" type="xsd:string" /> |
||||
</xsd:complexType> |
||||
</xsd:element> |
||||
<xsd:element name="data"> |
||||
<xsd:complexType> |
||||
<xsd:sequence> |
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> |
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> |
||||
</xsd:sequence> |
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> |
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> |
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> |
||||
<xsd:attribute ref="xml:space" /> |
||||
</xsd:complexType> |
||||
</xsd:element> |
||||
<xsd:element name="resheader"> |
||||
<xsd:complexType> |
||||
<xsd:sequence> |
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> |
||||
</xsd:sequence> |
||||
<xsd:attribute name="name" type="xsd:string" use="required" /> |
||||
</xsd:complexType> |
||||
</xsd:element> |
||||
</xsd:choice> |
||||
</xsd:complexType> |
||||
</xsd:element> |
||||
</xsd:schema> |
||||
<resheader name="resmimetype"> |
||||
<value>text/microsoft-resx</value> |
||||
</resheader> |
||||
<resheader name="version"> |
||||
<value>2.0</value> |
||||
</resheader> |
||||
<resheader name="reader"> |
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> |
||||
</resheader> |
||||
<resheader name="writer"> |
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> |
||||
</resheader> |
||||
<metadata name="cancelButton.GenerateMember" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> |
||||
<value>False</value> |
||||
</metadata> |
||||
<metadata name="splitContainer.GenerateMember" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> |
||||
<value>False</value> |
||||
</metadata> |
||||
<metadata name="resourceSelectionGroup.GenerateMember" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> |
||||
<value>False</value> |
||||
</metadata> |
||||
<metadata name="previewGroup.GenerateMember" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> |
||||
<value>False</value> |
||||
</metadata> |
||||
<metadata name="projectTreeScanningBackgroundWorker.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> |
||||
<value>17, 17</value> |
||||
</metadata> |
||||
</root> |
@ -0,0 +1,157 @@
@@ -0,0 +1,157 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Christian Hornung" email="chhornung@googlemail.com"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.ComponentModel; |
||||
using System.ComponentModel.Design; |
||||
using System.Drawing; |
||||
using System.Drawing.Design; |
||||
using System.Security.Permissions; |
||||
using System.Windows.Forms; |
||||
using System.Windows.Forms.Design; |
||||
|
||||
using ICSharpCode.Core; |
||||
using ICSharpCode.FormsDesigner.Gui; |
||||
using ICSharpCode.SharpDevelop.Project; |
||||
|
||||
namespace ICSharpCode.FormsDesigner.Services |
||||
{ |
||||
/// <summary>
|
||||
/// Edit image and icon properties with the option to use a project resource
|
||||
/// in an <see cref="ImageResourceEditorDialog"/>.
|
||||
/// </summary>
|
||||
public sealed class ImageResourceEditor : UITypeEditor |
||||
{ |
||||
public ImageResourceEditor() |
||||
{ |
||||
} |
||||
|
||||
[PermissionSet(SecurityAction.LinkDemand, Name="FullTrust")] |
||||
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) |
||||
{ |
||||
if (context == null || context.PropertyDescriptor == null) |
||||
return UITypeEditorEditStyle.None; |
||||
|
||||
if (typeof(Image).IsAssignableFrom(context.PropertyDescriptor.PropertyType) || |
||||
typeof(Icon).IsAssignableFrom(context.PropertyDescriptor.PropertyType)) { |
||||
|
||||
if (context.GetService(typeof(ProjectResourceService)) is ProjectResourceService) { |
||||
return UITypeEditorEditStyle.Modal; |
||||
} |
||||
|
||||
} |
||||
|
||||
return UITypeEditorEditStyle.Modal; |
||||
} |
||||
|
||||
[PermissionSet(SecurityAction.LinkDemand, Name="FullTrust")] |
||||
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) |
||||
{ |
||||
if (context == null || context.PropertyDescriptor == null || context.Instance == null || provider == null) { |
||||
return value; |
||||
} |
||||
|
||||
IComponent component = context.Instance as IComponent; |
||||
if (component == null || component.Site == null) { |
||||
LoggingService.Info("Editing of image properties on objects not implementing IComponent and components without Site is not supported by the ImageResourceEditor."); |
||||
if (typeof(Icon).IsAssignableFrom(context.PropertyDescriptor.PropertyType)) { |
||||
return new IconEditor().EditValue(context, provider, value); |
||||
} else { |
||||
return new ImageEditor().EditValue(context, provider, value); |
||||
} |
||||
} |
||||
|
||||
var prs = provider.GetService(typeof(ProjectResourceService)) as ProjectResourceService; |
||||
if (prs == null) { |
||||
return value; |
||||
} |
||||
|
||||
var edsvc = provider.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService; |
||||
if (edsvc == null) { |
||||
throw new InvalidOperationException("The required IWindowsFormsEditorService is not available."); |
||||
} |
||||
|
||||
var dictService = component.Site.GetService(typeof(IDictionaryService)) as IDictionaryService; |
||||
if (dictService == null) { |
||||
throw new InvalidOperationException("The required IDictionaryService is not available."); |
||||
} |
||||
|
||||
var projectResource = dictService.GetValue(ProjectResourceService.ProjectResourceKey + context.PropertyDescriptor.Name) as ProjectResourceInfo; |
||||
|
||||
IProject project = prs.ProjectContent.Project as IProject; |
||||
ImageResourceEditorDialog dialog; |
||||
|
||||
if (projectResource != null && Object.ReferenceEquals(projectResource.OriginalValue, value)) { |
||||
dialog = new ImageResourceEditorDialog(project, context.PropertyDescriptor.PropertyType, projectResource); |
||||
} else { |
||||
if (context.PropertyDescriptor.PropertyType == typeof(Image)) { |
||||
dialog = new ImageResourceEditorDialog(project, value as Image); |
||||
} else if (context.PropertyDescriptor.PropertyType == typeof(Icon)) { |
||||
dialog = new ImageResourceEditorDialog(project, value as Icon); |
||||
} else { |
||||
throw new InvalidOperationException("ImageResourceEditor called on unsupported property type: " + context.PropertyDescriptor.PropertyType.ToString()); |
||||
} |
||||
} |
||||
|
||||
using(dialog) { |
||||
if (edsvc.ShowDialog(dialog) == DialogResult.OK) { |
||||
projectResource = dialog.SelectedProjectResource; |
||||
if (projectResource != null) { |
||||
dictService.SetValue(ProjectResourceService.ProjectResourceKey + context.PropertyDescriptor.Name, projectResource); |
||||
|
||||
// Ensure the resource generator is turned on for the selected resource file.
|
||||
if (project != null) { |
||||
FileProjectItem fpi = project.FindFile(projectResource.ResourceFile); |
||||
if (fpi == null) { |
||||
throw new InvalidOperationException("The selected resource file '" + projectResource.ResourceFile + "' was not found in the project."); |
||||
} |
||||
const string resourceGeneratorToolName = "ResXFileCodeGenerator"; |
||||
if (!String.Equals(resourceGeneratorToolName, fpi.CustomTool, StringComparison.Ordinal)) { |
||||
fpi.CustomTool = resourceGeneratorToolName; |
||||
} |
||||
CustomToolsService.RunCustomTool(fpi, true); |
||||
} |
||||
|
||||
return projectResource.OriginalValue; |
||||
} else { |
||||
dictService.SetValue(ProjectResourceService.ProjectResourceKey + context.PropertyDescriptor.Name, null); |
||||
return dialog.SelectedResourceValue; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return value; |
||||
} |
||||
|
||||
[PermissionSet(SecurityAction.LinkDemand, Name="FullTrust")] |
||||
public override bool GetPaintValueSupported(ITypeDescriptorContext context) |
||||
{ |
||||
if (context != null && context.PropertyDescriptor != null && |
||||
(context.PropertyDescriptor.PropertyType == typeof(Image) || |
||||
context.PropertyDescriptor.PropertyType == typeof(Icon))) { |
||||
return true; |
||||
} |
||||
return base.GetPaintValueSupported(context); |
||||
} |
||||
|
||||
[PermissionSet(SecurityAction.LinkDemand, Name="FullTrust")] |
||||
public override void PaintValue(PaintValueEventArgs e) |
||||
{ |
||||
Image img = e.Value as Image; |
||||
if (img != null) { |
||||
e.Graphics.DrawImage(img, e.Bounds); |
||||
} else { |
||||
Icon icon = e.Value as Icon; |
||||
if (icon != null) { |
||||
e.Graphics.DrawIcon(icon, e.Bounds); |
||||
} else { |
||||
base.PaintValue(e); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,94 @@
@@ -0,0 +1,94 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Christian Hornung" email="chhornung@googlemail.com"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Collections; |
||||
using System.IO; |
||||
using System.Resources; |
||||
|
||||
using ICSharpCode.SharpDevelop; |
||||
|
||||
namespace ICSharpCode.FormsDesigner.Services |
||||
{ |
||||
/// <summary>
|
||||
/// Describes a project resource reference.
|
||||
/// </summary>
|
||||
public sealed class ProjectResourceInfo |
||||
{ |
||||
readonly string resourceFile; |
||||
readonly string resourceKey; |
||||
readonly object originalValue; |
||||
|
||||
/// <summary>
|
||||
/// Gets the full file name of the resource file that contains the resource.
|
||||
/// </summary>
|
||||
public string ResourceFile { |
||||
get { return resourceFile; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets the resource key.
|
||||
/// </summary>
|
||||
public string ResourceKey { |
||||
get { return resourceKey; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the resource at creation time of this instance.
|
||||
/// Can be <c>null</c> if the resource or the file was not found.
|
||||
/// </summary>
|
||||
public object OriginalValue { |
||||
get { return originalValue; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProjectResourceInfo"/> class
|
||||
/// and stores the resource value in the <see cref="OriginalValue"/> property
|
||||
/// if the resource file is found and it contains the specified key.
|
||||
/// </summary>
|
||||
/// <param name="resourceFile">The full name of the resource file that contains the resource.</param>
|
||||
/// <param name="resourceKey">The resource key.</param>
|
||||
public ProjectResourceInfo(string resourceFile, string resourceKey) |
||||
{ |
||||
if (resourceFile == null) |
||||
throw new ArgumentNullException("resourceFile"); |
||||
if (resourceKey == null) |
||||
throw new ArgumentNullException("resourceKey"); |
||||
this.resourceFile = resourceFile; |
||||
this.resourceKey = resourceKey; |
||||
|
||||
if (File.Exists(resourceFile)) { |
||||
|
||||
OpenedFile openedFile = FileService.GetOpenedFile(resourceFile); |
||||
Stream s; |
||||
if (openedFile != null) { |
||||
s = openedFile.OpenRead(); |
||||
} else { |
||||
s = new FileStream(resourceFile, FileMode.Open, FileAccess.Read, FileShare.Read); |
||||
} |
||||
|
||||
using(s) { |
||||
using(IResourceReader reader = ResourceStore.CreateResourceReader(s, ResourceStore.GetResourceType(resourceFile))) { |
||||
|
||||
ResXResourceReader resXReader = reader as ResXResourceReader; |
||||
if (resXReader != null) { |
||||
resXReader.BasePath = Path.GetDirectoryName(resourceFile); |
||||
} |
||||
|
||||
foreach (DictionaryEntry entry in reader) { |
||||
if (String.Equals(resourceKey, entry.Key as string, StringComparison.Ordinal)) { |
||||
this.originalValue = entry.Value; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,177 @@
@@ -0,0 +1,177 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Christian Hornung" email="chhornung@googlemail.com"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.CodeDom; |
||||
using System.IO; |
||||
using System.Linq; |
||||
|
||||
using ICSharpCode.Core; |
||||
using ICSharpCode.SharpDevelop; |
||||
using ICSharpCode.SharpDevelop.Dom; |
||||
using ICSharpCode.TextEditor; |
||||
using ICSharpCode.TextEditor.Document; |
||||
|
||||
namespace ICSharpCode.FormsDesigner.Services |
||||
{ |
||||
/// <summary>
|
||||
/// Supports project-level resources in the Windows.Forms designer.
|
||||
/// </summary>
|
||||
public sealed class ProjectResourceService |
||||
{ |
||||
public const string ProjectResourceKey = "SDProjectResource_"; |
||||
|
||||
IProjectContent projectContent; |
||||
string stringLiteralDelimiter; |
||||
|
||||
public ProjectResourceService(IProjectContent projectContent) |
||||
{ |
||||
if (projectContent == null) |
||||
throw new ArgumentNullException("projectContent"); |
||||
this.projectContent = projectContent; |
||||
} |
||||
|
||||
public IProjectContent ProjectContent { |
||||
get { return projectContent; } |
||||
set { |
||||
if (value == null) |
||||
throw new ArgumentNullException("value"); |
||||
if (this.projectContent != value) { |
||||
this.projectContent = value; |
||||
this.stringLiteralDelimiter = null; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets the string literal delimiter for the current language
|
||||
/// by generating code for a known literal.
|
||||
/// </summary>
|
||||
string StringLiteralDelimiter { |
||||
get { |
||||
if (stringLiteralDelimiter == null) { |
||||
const string TestString = "A"; |
||||
string testCode = this.projectContent.Language.CodeGenerator.GenerateCode(new NRefactory.Ast.PrimitiveExpression(TestString, TestString), String.Empty); |
||||
stringLiteralDelimiter = testCode.Substring(0, testCode.IndexOf(TestString, StringComparison.Ordinal)); |
||||
} |
||||
return stringLiteralDelimiter; |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets the project resource from the specified expression.
|
||||
/// </summary>
|
||||
public ProjectResourceInfo GetProjectResource(CodePropertyReferenceExpression propRef) |
||||
{ |
||||
CodeTypeReferenceExpression typeRef = propRef.TargetObject as CodeTypeReferenceExpression; |
||||
if (typeRef == null) { |
||||
LoggingService.Info("Target of possible project resources property reference is not a type reference, but " + propRef.TargetObject.ToString() + "."); |
||||
return null; |
||||
} |
||||
|
||||
// Get the (generated) class where the resource is defined.
|
||||
IClass resourceClass = this.projectContent.GetClass(typeRef.Type.BaseType, 0); |
||||
if (resourceClass == null) { |
||||
throw new InvalidOperationException("Could not find class for project resources: '" + typeRef.Type.BaseType + "'."); |
||||
} |
||||
|
||||
if (resourceClass.CompilationUnit == null || resourceClass.CompilationUnit.FileName == null) { |
||||
return null; |
||||
} |
||||
|
||||
// Make sure the class we have found is a generated resource class.
|
||||
if (!IsGeneratedResourceClass(resourceClass)) { |
||||
return null; |
||||
} |
||||
|
||||
// Get the name of the resource file based on the file that contains the generated class.
|
||||
string resourceFileName = Path.GetFileNameWithoutExtension(resourceClass.CompilationUnit.FileName); |
||||
if (resourceFileName.EndsWith("Designer", StringComparison.OrdinalIgnoreCase)) { |
||||
resourceFileName = Path.GetFileNameWithoutExtension(resourceFileName); |
||||
} |
||||
resourceFileName = Path.Combine(Path.GetDirectoryName(resourceClass.CompilationUnit.FileName), resourceFileName); |
||||
if (File.Exists(resourceFileName + ".resources")) { |
||||
resourceFileName = resourceFileName + ".resources"; |
||||
} else if (File.Exists(resourceFileName + ".resx")) { |
||||
resourceFileName = resourceFileName + ".resx"; |
||||
} else { |
||||
throw new FileNotFoundException("Could not find the resource file for type '" + resourceClass.FullyQualifiedName + "'. Tried these file names: '" + resourceFileName + ".(resources|resx)'."); |
||||
} |
||||
|
||||
// Get the property for the resource.
|
||||
IProperty prop = resourceClass.Properties.SingleOrDefault(p => p.Name == propRef.PropertyName); |
||||
if (prop == null) { |
||||
throw new InvalidOperationException("Property '" + propRef.PropertyName + "' not found in type '" + resourceClass.FullyQualifiedName + "'."); |
||||
} |
||||
|
||||
if (!prop.CanGet) { |
||||
throw new InvalidOperationException("Property '" + propRef.PropertyName + "' in type '" + resourceClass.FullyQualifiedName + "' does not have a getter."); |
||||
} |
||||
|
||||
// Get the code of the resource class and
|
||||
// extract the resource key from the property.
|
||||
// This is necessary because the key may differ from the property name
|
||||
// if special characters are used.
|
||||
// It would be better if we could use a real code parser for this, but
|
||||
// that is not possible without getting dependent on the programming language.
|
||||
|
||||
IDocument doc = new DocumentFactory().CreateDocument(); |
||||
doc.TextContent = ParserService.GetParseableFileContent(resourceClass.CompilationUnit.FileName); |
||||
|
||||
int startOffset = doc.PositionToOffset(new TextLocation(prop.GetterRegion.BeginColumn - 1, prop.GetterRegion.BeginLine - 1)); |
||||
int endOffset = doc.PositionToOffset(new TextLocation(prop.GetterRegion.EndColumn - 1, prop.GetterRegion.EndLine - 1)); |
||||
|
||||
string code = doc.GetText(startOffset, endOffset - startOffset + 1); |
||||
|
||||
int index = code.IndexOf("ResourceManager", StringComparison.Ordinal); |
||||
if (index == -1) { |
||||
throw new InvalidOperationException("No reference to ResourceManager found in property getter of '" + prop.FullyQualifiedName + "'. Code: '" + code + "'"); |
||||
} |
||||
|
||||
index = code.IndexOf("Get", index, StringComparison.Ordinal); |
||||
if (index == -1) { |
||||
throw new InvalidOperationException("No call to Get... found in property getter of '" + prop.FullyQualifiedName + "'. Code: '" + code + "'"); |
||||
} |
||||
|
||||
index = code.IndexOf(this.StringLiteralDelimiter, index + 1, StringComparison.Ordinal); |
||||
if (index == -1) { |
||||
throw new InvalidOperationException("No string delimiter ('" + this.StringLiteralDelimiter + "') found in property getter of '" + prop.FullyQualifiedName + "'. Code: '" + code + "'"); |
||||
} |
||||
index += this.StringLiteralDelimiter.Length; |
||||
|
||||
int endIndex = code.LastIndexOf(this.StringLiteralDelimiter, StringComparison.Ordinal); |
||||
if (endIndex == -1) { |
||||
throw new InvalidOperationException("No string terminator ('" + this.StringLiteralDelimiter + "') found in property getter of '" + prop.FullyQualifiedName + "'. Code: '" + code + "'"); |
||||
} |
||||
|
||||
string resourceKey = code.Substring(index, endIndex - index); |
||||
LoggingService.Debug("-> Decoded resource: In: " + resourceFileName + ". Key: " + resourceKey); |
||||
|
||||
return new ProjectResourceInfo(resourceFileName, resourceKey); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified class is a generated resource
|
||||
/// class, based on the attached attributes.
|
||||
/// </summary>
|
||||
public static bool IsGeneratedResourceClass(IClass @class) |
||||
{ |
||||
IClass generatedCodeAttributeClass = @class.ProjectContent.GetClass("System.CodeDom.Compiler.GeneratedCodeAttribute", 0); |
||||
if (generatedCodeAttributeClass == null) { |
||||
LoggingService.Info("Could not find the class for 'System.CodeDom.Compiler.GeneratedCodeAttribute'."); |
||||
return false; |
||||
} |
||||
IReturnType generatedCodeAttribute = generatedCodeAttributeClass.DefaultReturnType; |
||||
return @class.Attributes.Any( |
||||
att => |
||||
att.AttributeType.Equals(generatedCodeAttribute) && |
||||
att.PositionalArguments.Count == 2 && |
||||
String.Equals("System.Resources.Tools.StronglyTypedResourceBuilder", att.PositionalArguments[0] as string, StringComparison.Ordinal) |
||||
); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,258 @@
@@ -0,0 +1,258 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Christian Hornung" email="chhornung@googlemail.com"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.CodeDom; |
||||
using System.ComponentModel; |
||||
using System.ComponentModel.Design; |
||||
using System.ComponentModel.Design.Serialization; |
||||
using System.IO; |
||||
using System.Reflection; |
||||
|
||||
using ICSharpCode.Core; |
||||
using ICSharpCode.NRefactory.Visitors; |
||||
|
||||
namespace ICSharpCode.FormsDesigner.Services |
||||
{ |
||||
/// <summary>
|
||||
/// Can deserialize project resources used in a component definition.
|
||||
/// </summary>
|
||||
internal sealed class ProjectResourcesComponentCodeDomSerializer : CodeDomSerializer |
||||
{ |
||||
readonly CodeDomSerializer baseSerializer; |
||||
|
||||
internal ProjectResourcesComponentCodeDomSerializer(CodeDomSerializer baseSerializer) |
||||
{ |
||||
if (baseSerializer == null) |
||||
throw new ArgumentNullException("baseSerializer"); |
||||
this.baseSerializer = baseSerializer; |
||||
} |
||||
|
||||
public override object Deserialize(IDesignerSerializationManager manager, object codeObject) |
||||
{ |
||||
if (manager == null) |
||||
throw new ArgumentNullException("manager"); |
||||
if (codeObject == null) |
||||
throw new ArgumentNullException("codeObject"); |
||||
|
||||
object instance = null; |
||||
|
||||
CodeStatementCollection statements = codeObject as CodeStatementCollection; |
||||
if (statements != null) { |
||||
foreach (CodeStatement statement in statements) { |
||||
|
||||
if (!this.DeserializeProjectResourceStatement(manager, statement)) { |
||||
object result = this.baseSerializer.Deserialize(manager, new CodeStatementCollection(new [] {statement})); |
||||
if (instance == null) { |
||||
instance = result; |
||||
} |
||||
} |
||||
|
||||
} |
||||
return instance; |
||||
} |
||||
|
||||
return this.baseSerializer.Deserialize(manager, codeObject); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Attempts to deserialize the specified statement as
|
||||
/// a statement which accesses a project resource.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if the statement was deserialized successfully, otherwise <c>false</c>.</returns>
|
||||
bool DeserializeProjectResourceStatement(IDesignerSerializationManager manager, CodeStatement statement) |
||||
{ |
||||
var assignStatement = statement as CodeAssignStatement; |
||||
if (assignStatement != null) { |
||||
return this.DeserializeProjectResourceAssignStatement(manager, assignStatement); |
||||
} |
||||
|
||||
var exprStatement = statement as CodeExpressionStatement; |
||||
if (exprStatement != null) { |
||||
var invokeExpr = exprStatement.Expression as CodeMethodInvokeExpression; |
||||
if (invokeExpr != null) { |
||||
return this.DeserializeProjectResourceMethodInvokeExpression(manager, invokeExpr); |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Deserializes an assignment.
|
||||
/// This is used for standard properties, e.g.
|
||||
/// <code>myPictureBox.Image = value</code>
|
||||
/// </summary>
|
||||
bool DeserializeProjectResourceAssignStatement(IDesignerSerializationManager manager, CodeAssignStatement assignStatement) |
||||
{ |
||||
var propRefTarget = assignStatement.Left as CodePropertyReferenceExpression; |
||||
if (propRefTarget == null) { |
||||
return false; |
||||
} |
||||
|
||||
var propRefSource = assignStatement.Right as CodePropertyReferenceExpression; |
||||
if (propRefSource == null) { |
||||
return false; |
||||
} |
||||
|
||||
LoggingService.Debug("Forms designer: deserializing a property assignment:"); |
||||
LoggingService.Debug("-> " + CodeStatementToString(assignStatement)); |
||||
|
||||
IComponent component = this.baseSerializer.Deserialize(manager, propRefTarget.TargetObject) as IComponent; |
||||
if (component == null) { |
||||
LoggingService.Info("Forms designer: ProjectResourcesComponentCodeDomSerializer could not deserialze the target object to IComponent"); |
||||
return false; |
||||
} |
||||
if (component.Site == null) { |
||||
LoggingService.Info("Forms designer: ProjectResourcesComponentCodeDomSerializer: The deserialized component '" + component.ToString() + "' does not have a Site."); |
||||
return false; |
||||
} |
||||
|
||||
PropertyDescriptor propDescTarget = TypeDescriptor.GetProperties(component).Find(propRefTarget.PropertyName, false); |
||||
if (propDescTarget == null) { |
||||
throw new InvalidOperationException("Could not find the property descriptor for property '" + propRefTarget.PropertyName + "' on object '" + component.ToString() + "'."); |
||||
} |
||||
|
||||
ProjectResourceInfo resourceInfo = GetProjectResourceFromPropertyReference(manager, propRefSource); |
||||
if (resourceInfo == null) { |
||||
return false; |
||||
} |
||||
|
||||
// Set the property value of the target component to the value from the resource
|
||||
propDescTarget.SetValue(component, resourceInfo.OriginalValue); |
||||
|
||||
// Store our resource info in the dictionary service.
|
||||
// This is needed for the serializer so that it can
|
||||
// serialize this value as a project resource reference again.
|
||||
StoreResourceInfo(component, propDescTarget.Name, resourceInfo); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Deserializes a method invocation expression.
|
||||
/// This is used for extender providers, e.g.
|
||||
/// <code>myProvider.SetSomeProperty(targetComponent, value)</code>
|
||||
/// </summary>
|
||||
bool DeserializeProjectResourceMethodInvokeExpression(IDesignerSerializationManager manager, CodeMethodInvokeExpression invokeExpression) |
||||
{ |
||||
if (!invokeExpression.Method.MethodName.StartsWith("Set", StringComparison.OrdinalIgnoreCase) || |
||||
invokeExpression.Parameters.Count != 2) { |
||||
return false; |
||||
} |
||||
|
||||
var propRefSource = invokeExpression.Parameters[1] as CodePropertyReferenceExpression; |
||||
if (propRefSource == null) { |
||||
return false; |
||||
} |
||||
|
||||
LoggingService.Debug("Forms designer: deserializing a method invocation:"); |
||||
LoggingService.Debug("-> " + CodeStatementToString(new CodeExpressionStatement(invokeExpression))); |
||||
|
||||
object extenderProvider = this.baseSerializer.Deserialize(manager, invokeExpression.Method.TargetObject); |
||||
if (extenderProvider == null) { |
||||
return false; |
||||
} |
||||
|
||||
IComponent targetComponent = this.baseSerializer.Deserialize(manager, invokeExpression.Parameters[0]) as IComponent; |
||||
if (targetComponent == null) { |
||||
LoggingService.Info("Forms designer: ProjectResourcesComponentCodeDomSerializer could not deserialze the target object to IComponent"); |
||||
return false; |
||||
} |
||||
if (targetComponent.Site == null) { |
||||
LoggingService.Info("Forms designer: ProjectResourcesComponentCodeDomSerializer: The deserialized component '" + targetComponent.ToString() + "' does not have a Site."); |
||||
return false; |
||||
} |
||||
|
||||
ProjectResourceInfo resourceInfo = GetProjectResourceFromPropertyReference(manager, propRefSource); |
||||
if (resourceInfo == null) { |
||||
return false; |
||||
} |
||||
|
||||
// Set the property value of the target component to the value from the resource
|
||||
extenderProvider.GetType() |
||||
.InvokeMember(invokeExpression.Method.MethodName, |
||||
BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public, |
||||
null, |
||||
extenderProvider, |
||||
new [] {targetComponent, resourceInfo.OriginalValue}, |
||||
System.Globalization.CultureInfo.InvariantCulture); |
||||
|
||||
// Store our resource info in the dictionary service.
|
||||
// This is needed for the serializer so that it can
|
||||
// serialize this value as a project resource reference again.
|
||||
StoreResourceInfo(targetComponent, invokeExpression.Method.MethodName.Substring(3), resourceInfo); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
static ProjectResourceInfo GetProjectResourceFromPropertyReference(IDesignerSerializationManager manager, CodePropertyReferenceExpression propRefSource) |
||||
{ |
||||
ProjectResourceService prs = manager.GetService(typeof(ProjectResourceService)) as ProjectResourceService; |
||||
if (prs == null) { |
||||
throw new InvalidOperationException("The required ProjectResourceService is not available."); |
||||
} |
||||
|
||||
return prs.GetProjectResource(propRefSource); |
||||
} |
||||
|
||||
static void StoreResourceInfo(IComponent component, string propertyName, ProjectResourceInfo resourceInfo) |
||||
{ |
||||
var dictService = component.Site.GetService(typeof(IDictionaryService)) as IDictionaryService; |
||||
if (dictService == null) { |
||||
throw new InvalidOperationException("The required IDictionaryService is not available on component '" + component.ToString() + "'."); |
||||
} |
||||
dictService.SetValue(ProjectResourceService.ProjectResourceKey + propertyName, resourceInfo); |
||||
} |
||||
|
||||
#region Default overrides redirecting to baseSerializer
|
||||
|
||||
protected override object DeserializeInstance(IDesignerSerializationManager manager, Type type, object[] parameters, string name, bool addToContainer) |
||||
{ |
||||
// Because this method is protected, we cannot call into the baseSerializer.
|
||||
// However, as we do not use any serialization of this serializer,
|
||||
// this is should never be called.
|
||||
throw new NotImplementedException(); |
||||
} |
||||
|
||||
public override string GetTargetComponentName(CodeStatement statement, CodeExpression expression, Type targetType) |
||||
{ |
||||
return this.baseSerializer.GetTargetComponentName(statement, expression, targetType); |
||||
} |
||||
|
||||
public override object Serialize(IDesignerSerializationManager manager, object value) |
||||
{ |
||||
return this.baseSerializer.Serialize(manager, value); |
||||
} |
||||
|
||||
public override object SerializeAbsolute(IDesignerSerializationManager manager, object value) |
||||
{ |
||||
return this.baseSerializer.SerializeAbsolute(manager, value); |
||||
} |
||||
|
||||
public override CodeStatementCollection SerializeMember(IDesignerSerializationManager manager, object owningObject, MemberDescriptor member) |
||||
{ |
||||
return this.baseSerializer.SerializeMember(manager, owningObject, member); |
||||
} |
||||
|
||||
public override CodeStatementCollection SerializeMemberAbsolute(IDesignerSerializationManager manager, object owningObject, MemberDescriptor member) |
||||
{ |
||||
return this.baseSerializer.SerializeMemberAbsolute(manager, owningObject, member); |
||||
} |
||||
|
||||
#endregion
|
||||
|
||||
static string CodeStatementToString(CodeStatement statement) |
||||
{ |
||||
CodeDomVerboseOutputGenerator outputGenerator = new CodeDomVerboseOutputGenerator(); |
||||
using(StringWriter sw = new StringWriter(System.Globalization.CultureInfo.InvariantCulture)) { |
||||
outputGenerator.PublicGenerateCodeFromStatement(statement, sw, null); |
||||
return sw.ToString().TrimEnd(); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,172 @@
@@ -0,0 +1,172 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Christian Hornung" email="chhornung@googlemail.com"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.CodeDom; |
||||
using System.ComponentModel; |
||||
using System.ComponentModel.Design; |
||||
using System.ComponentModel.Design.Serialization; |
||||
using System.IO; |
||||
using System.Linq; |
||||
using System.Resources.Tools; |
||||
|
||||
using ICSharpCode.Core; |
||||
using ICSharpCode.EasyCodeDom; |
||||
using ICSharpCode.SharpDevelop; |
||||
using ICSharpCode.SharpDevelop.Dom; |
||||
using ICSharpCode.SharpDevelop.Project; |
||||
|
||||
namespace ICSharpCode.FormsDesigner.Services |
||||
{ |
||||
/// <summary>
|
||||
/// Can serialize assignments to component properties using project resource references.
|
||||
/// </summary>
|
||||
internal sealed class ProjectResourcesMemberCodeDomSerializer : MemberCodeDomSerializer |
||||
{ |
||||
readonly MemberCodeDomSerializer baseSerializer; |
||||
|
||||
public ProjectResourcesMemberCodeDomSerializer(MemberCodeDomSerializer baseSerializer) |
||||
{ |
||||
if (baseSerializer == null) |
||||
throw new ArgumentNullException("baseSerializer"); |
||||
this.baseSerializer = baseSerializer; |
||||
} |
||||
|
||||
public override void Serialize(IDesignerSerializationManager manager, object value, MemberDescriptor descriptor, CodeStatementCollection statements) |
||||
{ |
||||
if (!this.SerializeProjectResource(manager, value, descriptor, statements)) { |
||||
this.baseSerializer.Serialize(manager, value, descriptor, statements); |
||||
} |
||||
} |
||||
|
||||
bool SerializeProjectResource(IDesignerSerializationManager manager, object value, MemberDescriptor descriptor, CodeStatementCollection statements) |
||||
{ |
||||
var propDesc = descriptor as PropertyDescriptor; |
||||
if (propDesc == null) return false; |
||||
|
||||
var component = value as IComponent; |
||||
if (component == null || component.Site == null) return false; |
||||
|
||||
if (!propDesc.ShouldSerializeValue(component)) { |
||||
return false; |
||||
} |
||||
|
||||
var dictService = component.Site.GetService(typeof(IDictionaryService)) as IDictionaryService; |
||||
if (dictService == null) return false; |
||||
|
||||
var resourceInfo = dictService.GetValue(ProjectResourceService.ProjectResourceKey + propDesc.Name) as ProjectResourceInfo; |
||||
if (resourceInfo == null) return false; |
||||
|
||||
if (!Object.ReferenceEquals(resourceInfo.OriginalValue, propDesc.GetValue(value))) { |
||||
LoggingService.Info("Value of property '" + propDesc.Name + "' on component '" + value.ToString() + "' is not equal to stored project resource value. Ignoring this resource."); |
||||
return false; |
||||
} |
||||
|
||||
|
||||
// Find the generated file with the resource accessing class.
|
||||
|
||||
var prs = manager.GetService(typeof(ProjectResourceService)) as ProjectResourceService; |
||||
if (prs == null) { |
||||
LoggingService.Warn("ProjectResourceService not found"); |
||||
return false; |
||||
} |
||||
|
||||
IProject project = prs.ProjectContent.Project as IProject; |
||||
if (project == null) { |
||||
LoggingService.Warn("Serializer cannot proceed because project is not an IProject"); |
||||
return false; |
||||
} |
||||
|
||||
string resourceFileDirectory = Path.GetDirectoryName(resourceInfo.ResourceFile); |
||||
string resourceFileName = Path.GetFileName(resourceInfo.ResourceFile); |
||||
var items = project.Items |
||||
.OfType<FileProjectItem>() |
||||
.Where( |
||||
fpi => |
||||
FileUtility.IsEqualFileName(Path.GetDirectoryName(fpi.FileName), resourceFileDirectory) && |
||||
FileUtility.IsEqualFileName(fpi.DependentUpon, resourceFileName) && |
||||
fpi.ItemType == ItemType.Compile && |
||||
fpi.VirtualName.ToUpperInvariant().Contains("DESIGNER") |
||||
); |
||||
|
||||
if (items.Count() != 1) { |
||||
LoggingService.Info("Did not find exactly one possible file that contains the generated class for the resource file '" + resourceInfo.ResourceFile + "'. Ignoring this resource."); |
||||
return false; |
||||
} |
||||
|
||||
string resourceCodeFile = items.Single().FileName; |
||||
|
||||
// We expect a single class to be in this file.
|
||||
IClass resourceClass = ParserService.GetParseInformation(resourceCodeFile).MostRecentCompilationUnit.Classes.Single(); |
||||
// Here we assume that VerifyResourceName is the same name transform that
|
||||
// was used when generating the resource code file.
|
||||
// This should be true as long as the code is generated using the
|
||||
// custom tool in SharpDevelop or Visual Studio.
|
||||
string resourcePropertyName = StronglyTypedResourceBuilder.VerifyResourceName(resourceInfo.ResourceKey, prs.ProjectContent.Language.CodeDomProvider ?? LanguageProperties.CSharp.CodeDomProvider); |
||||
if (resourcePropertyName == null) { |
||||
throw new InvalidOperationException("The resource name '" + resourceInfo.ResourceKey + "' could not be transformed to a name that is valid in the current programming language."); |
||||
} |
||||
|
||||
|
||||
// Now do the actual serialization.
|
||||
|
||||
LoggingService.Debug("Serializing project resource: Component '" + component.ToString() + "', Property: '" + propDesc.Name + "', Resource class: '" + resourceClass.FullyQualifiedName + "', Resource property: '" + resourcePropertyName + "'"); |
||||
|
||||
var targetObjectExpr = base.SerializeToExpression(manager, value); |
||||
if (targetObjectExpr == null) { |
||||
LoggingService.Info("Target object could not be serialized: " + value.ToString()); |
||||
return false; |
||||
} |
||||
|
||||
if (propDesc.SerializationVisibility == DesignerSerializationVisibility.Content) { |
||||
LoggingService.Debug("-> is a content property, ignoring this."); |
||||
return false; |
||||
} |
||||
|
||||
var propRefSource = |
||||
Easy.Type( |
||||
new CodeTypeReference(resourceClass.FullyQualifiedName, CodeTypeReferenceOptions.GlobalReference) |
||||
).Property(resourcePropertyName); |
||||
|
||||
var extAttr = propDesc.Attributes[typeof(ExtenderProvidedPropertyAttribute)] as ExtenderProvidedPropertyAttribute; |
||||
if (extAttr != null && extAttr.Provider != null) { |
||||
|
||||
// This is an extender property.
|
||||
var extProvider = base.SerializeToExpression(manager, extAttr.Provider); |
||||
if (extProvider == null) { |
||||
throw new InvalidOperationException("Could not serialize the extender provider '" + extAttr.Provider.ToString() + "'."); |
||||
} |
||||
|
||||
statements.Add( |
||||
new EasyExpression(extProvider) |
||||
.InvokeMethod( |
||||
"Set" + propDesc.Name, |
||||
targetObjectExpr, |
||||
propRefSource |
||||
) |
||||
); |
||||
|
||||
} else { |
||||
|
||||
// This is a standard property.
|
||||
statements.Add( |
||||
new CodeAssignStatement( |
||||
new CodePropertyReferenceExpression(targetObjectExpr, propDesc.Name), |
||||
propRefSource) |
||||
); |
||||
|
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
public override bool ShouldSerialize(IDesignerSerializationManager manager, object value, MemberDescriptor descriptor) |
||||
{ |
||||
return this.baseSerializer.ShouldSerialize(manager, value, descriptor); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,48 @@
@@ -0,0 +1,48 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Christian Hornung" email="chhornung@googlemail.com"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.ComponentModel; |
||||
using System.ComponentModel.Design.Serialization; |
||||
|
||||
namespace ICSharpCode.FormsDesigner.Services |
||||
{ |
||||
/// <summary>
|
||||
/// Provides a custom serialization service for the designer.
|
||||
/// </summary>
|
||||
internal sealed class SharpDevelopSerializationProvider : IDesignerSerializationProvider |
||||
{ |
||||
internal SharpDevelopSerializationProvider() |
||||
{ |
||||
} |
||||
|
||||
object IDesignerSerializationProvider.GetSerializer(IDesignerSerializationManager manager, object currentSerializer, Type objectType, Type serializerType) |
||||
{ |
||||
if (currentSerializer == null) { |
||||
// We need a base serializer to proceed.
|
||||
return null; |
||||
} |
||||
|
||||
|
||||
if (serializerType == typeof(MemberCodeDomSerializer)) { |
||||
|
||||
if (typeof(PropertyDescriptor).IsAssignableFrom(objectType) && !(currentSerializer is ProjectResourcesMemberCodeDomSerializer)) { |
||||
return new ProjectResourcesMemberCodeDomSerializer((MemberCodeDomSerializer)currentSerializer); |
||||
} |
||||
|
||||
} else if (serializerType == typeof(CodeDomSerializer)) { |
||||
|
||||
if (typeof(IComponent).IsAssignableFrom(objectType) && !(currentSerializer is ProjectResourcesComponentCodeDomSerializer)) { |
||||
return new ProjectResourcesComponentCodeDomSerializer((CodeDomSerializer)currentSerializer); |
||||
} |
||||
|
||||
} |
||||
|
||||
return null; |
||||
} |
||||
} |
||||
} |
Binary file not shown.
Loading…
Reference in new issue