/src/DocumentWorkspace.cs
C# | 2944 lines | 2357 code | 451 blank | 136 comment | 287 complexity | 5edb570d764eb19ca36f67c71e1b848a MD5 | raw file
Possible License(s): Unlicense
- /////////////////////////////////////////////////////////////////////////////////
- // Paint.NET //
- // Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. //
- // Portions Copyright (C) Microsoft Corporation. All Rights Reserved. //
- // See src/Resources/Files/License.txt for full licensing and attribution //
- // details. //
- // . //
- /////////////////////////////////////////////////////////////////////////////////
-
- using PaintDotNet.Data;
- using PaintDotNet.Effects;
- using PaintDotNet.HistoryFunctions;
- using PaintDotNet.HistoryMementos;
- using PaintDotNet.SystemLayer;
- using PaintDotNet.Tools;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Drawing;
- using System.Drawing.Imaging;
- using System.Globalization;
- using System.IO;
- using System.Reflection;
- using System.Runtime.Serialization;
- using System.Security;
- using System.Text;
- using System.Threading;
- using System.Windows.Forms;
-
- namespace PaintDotNet
- {
- /// <summary>
- /// Builds on DocumentView by adding application-specific elements.
- /// </summary>
- internal class DocumentWorkspace
- : DocumentView,
- IHistoryWorkspace,
- IThumbnailProvider
- {
- public static readonly DateTime NeverSavedDateTime = DateTime.MinValue;
-
- private static Type[] tools; // TODO: move to Tool class?
- private static ToolInfo[] toolInfos;
-
- private ZoomBasis zoomBasis;
- private AppWorkspace appWorkspace;
- private string filePath = null;
- private FileType fileType = null;
- private SaveConfigToken saveConfigToken = null;
- private Selection selection = new Selection();
- private Surface scratchSurface = null;
- private SelectionRenderer selectionRenderer;
- private Hashtable staticToolData = Hashtable.Synchronized(new Hashtable());
- private Tool activeTool;
- private Type previousActiveToolType;
- private Type preNullTool = null;
- private int nullToolCount = 0;
- private int zoomChangesCount = 0;
- private HistoryStack history;
- private Layer activeLayer;
- private System.Windows.Forms.Timer toolPulseTimer;
- private DateTime lastSaveTime = NeverSavedDateTime;
- private int suspendToolCursorChanges = 0;
- private ImageResource statusIcon = null;
- private string statusText = null;
-
- private readonly string contextStatusBarWithAngleFormat = PdnResources.GetString("StatusBar.Context.SelectedArea.Text.WithAngle.Format");
- private readonly string contextStatusBarFormat = PdnResources.GetString("StatusBar.Context.SelectedArea.Text.Format");
-
- public void SuspendToolCursorChanges()
- {
- ++this.suspendToolCursorChanges;
- }
-
- public void ResumeToolCursorChanges()
- {
- --this.suspendToolCursorChanges;
-
- if (this.suspendToolCursorChanges <= 0 && this.activeTool != null)
- {
- Cursor = this.activeTool.Cursor;
- }
- }
-
- public ImageResource StatusIcon
- {
- get
- {
- return this.statusIcon;
- }
- }
-
- public string StatusText
- {
- get
- {
- return this.statusText;
- }
- }
-
- public void SetStatus(string newStatusText, ImageResource newStatusIcon)
- {
- this.statusText = newStatusText;
- this.statusIcon = newStatusIcon;
- OnStatusChanged();
- }
-
- public event EventHandler StatusChanged;
- protected virtual void OnStatusChanged()
- {
- if (StatusChanged != null)
- {
- StatusChanged(this, EventArgs.Empty);
- }
- }
-
- static DocumentWorkspace()
- {
- InitializeTools();
- InitializeToolInfos();
- }
-
- public DateTime LastSaveTime
- {
- get
- {
- return this.lastSaveTime;
- }
- }
-
- public bool IsZoomChanging
- {
- get
- {
- return (this.zoomChangesCount > 0);
- }
- }
-
- private void BeginZoomChanges()
- {
- ++this.zoomChangesCount;
- }
-
- private void EndZoomChanges()
- {
- --this.zoomChangesCount;
- }
-
- protected override void OnSizeChanged(EventArgs e)
- {
- PerformLayout();
- base.OnSizeChanged(e);
- }
-
- protected override void OnLayout(LayoutEventArgs e)
- {
- if (this.zoomBasis == ZoomBasis.FitToWindow)
- {
- ZoomToWindow();
-
- // This bizarre ordering of setting PanelAutoScroll prevents some very weird layout/scroll-without-scrollbars stuff.
- PanelAutoScroll = true;
- PanelAutoScroll = false;
- }
-
- base.OnLayout(e);
- }
-
- protected override void OnResize(EventArgs e)
- {
- if (this.zoomBasis == ZoomBasis.FitToWindow)
- {
- PerformLayout();
- }
-
- base.OnResize(e);
- }
-
- public DocumentWorkspace()
- {
- this.activeLayer = null;
- this.history = new HistoryStack(this);
-
- InitializeComponent();
-
- // hook the DocumentWorkspace with its selectedPath ...
- this.selectionRenderer = new SelectionRenderer(this.RendererList, this.Selection, this);
- this.RendererList.Add(this.selectionRenderer, true);
- this.selectionRenderer.EnableOutlineAnimation = true;
- this.selectionRenderer.EnableSelectionTinting = false;
- this.selectionRenderer.EnableSelectionOutline = true;
-
- this.selection.Changed += new EventHandler(Selection_Changed);
-
- this.zoomBasis = ZoomBasis.FitToWindow;
- }
-
- protected override void OnUnitsChanged()
- {
- if (!Selection.IsEmpty)
- {
- UpdateSelectionInfoInStatusBar();
- }
-
- base.OnUnitsChanged();
- }
-
- public void UpdateStatusBarToToolHelpText(Tool tool)
- {
- if (tool == null)
- {
- SetStatus(string.Empty, null);
- }
- else
- {
- string toolName = tool.Name;
- string helpText = tool.HelpText;
-
- string contextFormat = PdnResources.GetString("StatusBar.Context.Help.Text.Format");
- string contextText = string.Format(contextFormat, toolName, helpText);
-
- SetStatus(contextText, PdnResources.GetImageResource("Icons.MenuHelpHelpTopicsIcon.png"));
- }
- }
-
- public void UpdateStatusBarToToolHelpText()
- {
- UpdateStatusBarToToolHelpText(this.activeTool);
- }
-
- private void UpdateSelectionInfoInStatusBar()
- {
- if (Selection.IsEmpty)
- {
- UpdateStatusBarToToolHelpText();
- }
- else
- {
- string newStatusText;
-
- int area = 0;
- Rectangle bounds;
-
- using (PdnRegion tempSelection = Selection.CreateRegionRaw())
- {
- tempSelection.Intersect(Document.Bounds);
- bounds = Utility.GetRegionBounds(tempSelection);
- area = tempSelection.GetArea();
- }
-
- string unitsAbbreviationXY;
- string xString;
- string yString;
- string unitsAbbreviationWH;
- string widthString;
- string heightString;
-
- Document.CoordinatesToStrings(Units, bounds.X, bounds.Y, out xString, out yString, out unitsAbbreviationXY);
- Document.CoordinatesToStrings(Units, bounds.Width, bounds.Height, out widthString, out heightString, out unitsAbbreviationWH);
-
- NumberFormatInfo nfi = (NumberFormatInfo)CultureInfo.CurrentCulture.NumberFormat.Clone();
-
- string areaString;
- if (this.Units == MeasurementUnit.Pixel)
- {
- nfi.NumberDecimalDigits = 0;
- areaString = area.ToString("N", nfi);
- }
- else
- {
- nfi.NumberDecimalDigits = 2;
- double areaD = Document.PixelAreaToPhysicalArea(area, this.Units);
- areaString = areaD.ToString("N", nfi);
- }
-
- string pluralUnits = PdnResources.GetString("MeasurementUnit." + this.Units.ToString() + ".Plural");
- MoveToolBase moveTool = Tool as MoveToolBase;
-
- if (moveTool != null && moveTool.HostShouldShowAngle)
- {
- NumberFormatInfo nfi2 = (NumberFormatInfo)nfi.Clone();
- nfi2.NumberDecimalDigits = 2;
- float angle = moveTool.HostAngle;
-
- while (angle > 180.0f)
- {
- angle -= 360.0f;
- }
-
- while (angle < -180.0f)
- {
- angle += 360.0f;
- }
-
- newStatusText = string.Format(
- contextStatusBarWithAngleFormat,
- xString,
- unitsAbbreviationXY,
- yString,
- unitsAbbreviationXY,
- widthString,
- unitsAbbreviationWH,
- heightString,
- unitsAbbreviationWH,
- areaString,
- pluralUnits.ToLower(),
- moveTool.HostAngle.ToString("N", nfi2));
- }
- else
- {
- newStatusText = string.Format(
- contextStatusBarFormat,
- xString,
- unitsAbbreviationXY,
- yString,
- unitsAbbreviationXY,
- widthString,
- unitsAbbreviationWH,
- heightString,
- unitsAbbreviationWH,
- areaString,
- pluralUnits.ToLower());
- }
-
- SetStatus(newStatusText, PdnResources.GetImageResource("Icons.SelectionIcon.png"));
- }
- }
-
- private void Selection_Changed(object sender, EventArgs e)
- {
- UpdateRulerSelectionTinting();
- UpdateSelectionInfoInStatusBar();
- }
-
- private void InitializeComponent()
- {
- this.toolPulseTimer = new System.Windows.Forms.Timer();
- this.toolPulseTimer.Interval = 16;
- this.toolPulseTimer.Tick += new EventHandler(this.ToolPulseTimer_Tick);
- }
-
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- if (this.activeTool != null)
- {
- this.activeTool.Dispose();
- this.activeTool = null;
- }
- }
-
- base.Dispose(disposing);
- }
-
- public void PerformActionAsync(DocumentWorkspaceAction action)
- {
- BeginInvoke(new Procedure<DocumentWorkspaceAction>(PerformAction), new object[] { action });
- }
-
- public void PerformAction(DocumentWorkspaceAction action)
- {
- bool nullTool = false;
-
- if ((action.ActionFlags & ActionFlags.KeepToolActive) != ActionFlags.KeepToolActive)
- {
- PushNullTool();
- Update();
- nullTool = true;
- }
-
- try
- {
- using (new WaitCursorChanger(this))
- {
- HistoryMemento ha = action.PerformAction(this);
-
- if (ha != null)
- {
- History.PushNewMemento(ha);
- }
- }
- }
-
- finally
- {
- if (nullTool)
- {
- PopNullTool();
- }
- }
- }
-
- /// <summary>
- /// Executes a HistoryFunction in the context of this DocumentWorkspace.
- /// </summary>
- /// <param name="function">The HistoryFunction to execute.</param>
- /// <remarks>
- /// Depending on the HistoryFunction, the currently active tool may be refreshed.
- /// </remarks>
- public HistoryFunctionResult ExecuteFunction(HistoryFunction function)
- {
- HistoryFunctionResult result;
-
- bool nullTool = false;
-
- if ((function.ActionFlags & ActionFlags.KeepToolActive) != ActionFlags.KeepToolActive)
- {
- PushNullTool();
- Update();
- nullTool = true;
- }
-
- try
- {
- using (new WaitCursorChanger(this))
- {
- HistoryMemento hm = null;
- string errorText;
-
- try
- {
- bool cancelled = false;
-
- if ((function.ActionFlags & ActionFlags.ReportsProgress) != ActionFlags.ReportsProgress)
- {
- hm = function.Execute(this);
- }
- else
- {
- ProgressDialog pd = new ProgressDialog();
- bool pdLoaded = false;
- bool closeAtLoad = false;
-
- EventHandler loadCallback =
- delegate(object sender, EventArgs e)
- {
- pdLoaded = true;
-
- if (closeAtLoad)
- {
- pd.Close();
- }
- };
-
- ProgressEventHandler progressCallback =
- delegate(object sender, ProgressEventArgs e)
- {
- if (pdLoaded)
- {
- double newValue = Utility.Clamp(e.Percent, 0.0, 100.0);
- pd.Value = newValue;
- }
- };
-
- EventHandler<EventArgs<HistoryMemento>> finishedCallback =
- delegate(object sender, EventArgs<HistoryMemento> e)
- {
- hm = e.Data;
-
- if (pdLoaded)
- {
- // TODO: fix ProgressDialog's very weird interface
- pd.ExternalFinish();
- pd.Close();
- }
- else
- {
- closeAtLoad = true;
- }
- };
-
- EventHandler cancelClickCallback =
- delegate(object sender, EventArgs e)
- {
- cancelled = true;
- function.RequestCancel();
- //pd.Cancellable = false;
- };
-
- pd.Text = PdnInfo.GetBareProductName();
- pd.Description = PdnResources.GetString("ExecuteFunction.ProgressDialog.Description.Text");
- pd.Load += loadCallback;
- pd.Cancellable = false; //function.Cancellable;
- pd.CancelClick += cancelClickCallback;
- function.Progress += progressCallback;
- function.BeginExecute(this, this, finishedCallback);
- pd.ShowDialog(this);
- pd.Dispose();
- }
-
- if (hm == null && !cancelled)
- {
- result = HistoryFunctionResult.SuccessNoOp;
- }
- else if (hm == null && cancelled)
- {
- result = HistoryFunctionResult.Cancelled;
- }
- else
- {
- result = HistoryFunctionResult.Success;
- }
-
- errorText = null;
- }
-
- catch (HistoryFunctionNonFatalException hfnfex)
- {
- if (hfnfex.InnerException is OutOfMemoryException)
- {
- result = HistoryFunctionResult.OutOfMemory;
- }
- else
- {
- result = HistoryFunctionResult.NonFatalError;
- }
-
- if (hfnfex.LocalizedErrorText != null)
- {
- errorText = hfnfex.LocalizedErrorText;
- }
- else
- {
- if (hfnfex.InnerException is OutOfMemoryException)
- {
- errorText = PdnResources.GetString("ExecuteFunction.GenericOutOfMemory");
- }
- else
- {
- errorText = PdnResources.GetString("ExecuteFunction.GenericError");
- }
- }
- }
-
- if (errorText != null)
- {
- Utility.ErrorBox(this, errorText);
- }
-
- if (hm != null)
- {
- History.PushNewMemento(hm);
- }
- }
- }
-
- finally
- {
- if (nullTool)
- {
- PopNullTool();
- }
- }
-
- return result;
- }
-
- public override void ZoomIn()
- {
- this.ZoomBasis = ZoomBasis.ScaleFactor;
- base.ZoomIn();
- }
-
- public override void ZoomIn(double factor)
- {
- this.ZoomBasis = ZoomBasis.ScaleFactor;
- base.ZoomIn(factor);
- }
-
- public override void ZoomOut()
- {
- this.ZoomBasis = ZoomBasis.ScaleFactor;
- base.ZoomOut();
- }
-
- public override void ZoomOut(double factor)
- {
- this.ZoomBasis = ZoomBasis.ScaleFactor;
- base.ZoomOut(factor);
- }
-
- // TODO:
- /// <summary>
- /// Same as PerformAction(Type) except it lets you rename the HistoryMemento's name.
- /// </summary>
- /// <param name="actionType"></param>
- /// <param name="newName"></param>
- public void PerformAction(Type actionType, string newName, ImageResource icon)
- {
- using (new WaitCursorChanger(this))
- {
- ConstructorInfo ci = actionType.GetConstructor(new Type[] { typeof(DocumentWorkspace) });
- object actionAsObject = ci.Invoke(new object[] { this });
- DocumentWorkspaceAction action = actionAsObject as DocumentWorkspaceAction;
-
- if (action != null)
- {
- bool nullTool = false;
-
- if ((action.ActionFlags & ActionFlags.KeepToolActive) != ActionFlags.KeepToolActive)
- {
- PushNullTool();
- Update();
- nullTool = true;
- }
-
- try
- {
- HistoryMemento ha = action.PerformAction(this);
-
- if (ha != null)
- {
- ha.Name = newName;
- ha.Image = icon;
- History.PushNewMemento(ha);
- }
- }
-
- finally
- {
- if (nullTool)
- {
- PopNullTool();
- }
- }
- }
- }
- }
-
- public event EventHandler ZoomBasisChanging;
- protected virtual void OnZoomBasisChanging()
- {
- if (ZoomBasisChanging != null)
- {
- ZoomBasisChanging(this, EventArgs.Empty);
- }
- }
-
- public event EventHandler ZoomBasisChanged;
- protected virtual void OnZoomBasisChanged()
- {
- if (ZoomBasisChanged != null)
- {
- ZoomBasisChanged(this, EventArgs.Empty);
- }
- }
-
- public ZoomBasis ZoomBasis
- {
- get
- {
- return this.zoomBasis;
- }
-
- set
- {
- if (this.zoomBasis != value)
- {
- OnZoomBasisChanging();
- this.zoomBasis = value;
-
- switch (this.zoomBasis)
- {
- case ZoomBasis.FitToWindow:
- ZoomToWindow();
-
- // Enable PanelAutoScroll only long enough to recenter the view
- PanelAutoScroll = true;
- PanelAutoScroll = false;
-
- // this would be unset by the scalefactor changes in ZoomToWindow
- this.zoomBasis = ZoomBasis.FitToWindow;
- break;
-
- case ZoomBasis.ScaleFactor:
- PanelAutoScroll = true;
- break;
-
- default:
- throw new InvalidEnumArgumentException();
- }
-
- OnZoomBasisChanged();
- }
- }
- }
-
- public void ZoomToSelection()
- {
- if (Selection.IsEmpty)
- {
- ZoomToWindow();
- }
- else
- {
- using (PdnRegion region = Selection.CreateRegion())
- {
- ZoomToRectangle(region.GetBoundsInt());
- }
- }
- }
-
- public void ZoomToRectangle(Rectangle selectionBounds)
- {
- PointF selectionCenter = new PointF((selectionBounds.Left + selectionBounds.Right + 1) / 2,
- (selectionBounds.Top + selectionBounds.Bottom + 1) / 2);
-
- PointF cornerPosition;
-
- ScaleFactor zoom = ScaleFactor.Min(ClientRectangleMin.Width, selectionBounds.Width + 2,
- ClientRectangleMin.Height, selectionBounds.Height + 2,
- ScaleFactor.MinValue);
-
- // Zoom out to fit the image
- ZoomBasis = ZoomBasis.ScaleFactor;
- ScaleFactor = zoom;
-
- cornerPosition = new PointF(selectionCenter.X - (VisibleDocumentRectangleF.Width / 2),
- selectionCenter.Y - (VisibleDocumentRectangleF.Height / 2));
-
- DocumentScrollPositionF = cornerPosition;
- }
-
- protected override void HandleMouseWheel(Control sender, MouseEventArgs e)
- {
- if (Control.ModifierKeys == Keys.Control)
- {
- double mouseDelta = (double)e.Delta / 120.0f;
- Rectangle visibleDocBoundsStart = this.VisibleDocumentBounds;
- Point mouseDocPt = this.MouseToDocument(sender, new Point(e.X, e.Y));
- RectangleF visibleDocDocRect1 = this.VisibleDocumentRectangleF;
-
- PointF mouseNPt = new PointF(
- (mouseDocPt.X - visibleDocDocRect1.X) / visibleDocDocRect1.Width,
- (mouseDocPt.Y - visibleDocDocRect1.Y) / visibleDocDocRect1.Height);
-
- const double factor = 1.12;
- double mouseFactor = Math.Pow(factor, Math.Abs(mouseDelta));
-
- if (e.Delta > 0)
- {
- this.ZoomIn(mouseFactor);
- }
- else if (e.Delta < 0)
- {
- this.ZoomOut(mouseFactor);
- }
-
- RectangleF visibleDocDocRect2 = this.VisibleDocumentRectangleF;
-
- PointF scrollPt2 = new PointF(
- mouseDocPt.X - visibleDocDocRect2.Width * mouseNPt.X,
- mouseDocPt.Y - visibleDocDocRect2.Height * mouseNPt.Y);
-
- this.DocumentScrollPositionF = scrollPt2;
-
- Rectangle visibleDocBoundsEnd = this.VisibleDocumentBounds;
-
- if (visibleDocBoundsEnd != visibleDocBoundsStart)
- {
- // Make sure the screen updates, otherwise it can get a little funky looking
- this.Update();
- }
- }
-
- base.HandleMouseWheel(sender, e);
- }
-
- public void SelectClosestVisibleLayer(Layer layer)
- {
- int oldLayerIndex = this.Document.Layers.IndexOf(layer);
- int newLayerIndex = oldLayerIndex;
-
- // find the closest layer that is still visible
- for (int i = 0; i < this.Document.Layers.Count; ++i)
- {
- int lower = oldLayerIndex - i;
- int upper = oldLayerIndex + i;
-
- if (lower >= 0 && lower < this.Document.Layers.Count && ((Layer)this.Document.Layers[lower]).Visible)
- {
- newLayerIndex = lower;
- break;
- }
-
- if (upper >= 0 && upper < this.Document.Layers.Count && ((Layer)this.Document.Layers[upper]).Visible)
- {
- newLayerIndex = upper;
- break;
- }
- }
-
- if (newLayerIndex != oldLayerIndex)
- {
- this.ActiveLayer = (Layer)Document.Layers[newLayerIndex];
- }
- }
-
- public void UpdateRulerSelectionTinting()
- {
- if (this.RulersEnabled)
- {
- Rectangle bounds = this.Selection.GetBounds();
- this.SetHighlightRectangle(bounds);
- }
- }
-
- private void LayerRemovingHandler(object sender, IndexEventArgs e)
- {
- Layer layer = (Layer)this.Document.Layers[e.Index];
- layer.PropertyChanging -= LayerPropertyChangingHandler;
- layer.PropertyChanged -= LayerPropertyChangedHandler;
-
- // pick a new valid layer!
- int newLayerIndex;
-
- if (e.Index == this.Document.Layers.Count - 1)
- {
- newLayerIndex = e.Index - 1;
- }
- else
- {
- newLayerIndex = e.Index + 1;
- }
-
- if (newLayerIndex >= 0 && newLayerIndex < this.Document.Layers.Count)
- {
- this.ActiveLayer = (Layer)this.Document.Layers[newLayerIndex];
- }
- else
- {
- if (this.Document.Layers.Count == 0)
- {
- this.ActiveLayer = null;
- }
- else
- {
- this.ActiveLayer = (Layer)this.Document.Layers[0];
- }
- }
- }
-
- private void LayerRemovedHandler(object sender, IndexEventArgs e)
- {
- }
-
- private void LayerInsertedHandler(object sender, IndexEventArgs e)
- {
- Layer layer = (Layer)this.Document.Layers[e.Index];
- this.ActiveLayer = layer;
- layer.PropertyChanging += LayerPropertyChangingHandler;
- layer.PropertyChanged += LayerPropertyChangedHandler;
- }
-
- private void LayerPropertyChangingHandler(object sender, PropertyEventArgs e)
- {
- string nameFormat = PdnResources.GetString("LayerPropertyChanging.HistoryMementoNameFormat");
- string haName = string.Format(nameFormat, e.PropertyName);
-
- LayerPropertyHistoryMemento lpha = new LayerPropertyHistoryMemento(
- haName,
- PdnResources.GetImageResource("Icons.MenuLayersLayerPropertiesIcon.png"),
- this,
- this.Document.Layers.IndexOf(sender));
-
- this.History.PushNewMemento(lpha);
- }
-
- private void LayerPropertyChangedHandler(object sender, PropertyEventArgs e)
- {
- Layer layer = (Layer)sender;
-
- if (!layer.Visible &&
- layer == this.ActiveLayer &&
- this.Document.Layers.Count > 1 &&
- !History.IsExecutingMemento)
- {
- SelectClosestVisibleLayer(layer);
- }
- }
-
- private void ToolPulseTimer_Tick(object sender, EventArgs e)
- {
- if (FindForm() == null || FindForm().WindowState == FormWindowState.Minimized)
- {
- return;
- }
-
- if (this.Tool != null && this.Tool.Active)
- {
- this.Tool.PerformPulse();
- }
- }
-
- protected override void OnLoad(EventArgs e)
- {
- if (this.appWorkspace == null)
- {
- throw new InvalidOperationException("Must set the Workspace property");
- }
-
- base.OnLoad(e);
- }
-
- public event EventHandler ActiveLayerChanging;
- protected void OnLayerChanging()
- {
- if (ActiveLayerChanging != null)
- {
- ActiveLayerChanging(this, EventArgs.Empty);
- }
- }
-
- public event EventHandler ActiveLayerChanged;
- protected void OnLayerChanged()
- {
- this.Focus();
-
- if (ActiveLayerChanged != null)
- {
- ActiveLayerChanged(this, EventArgs.Empty);
- }
- }
-
- public Layer ActiveLayer
- {
- get
- {
- return this.activeLayer;
- }
-
- set
- {
- OnLayerChanging();
-
- bool deactivateTool;
-
- if (this.Tool != null)
- {
- deactivateTool = this.Tool.DeactivateOnLayerChange;
- }
- else
- {
- deactivateTool = false;
- }
-
- if (deactivateTool)
- {
- PushNullTool();
- this.EnableToolPulse = false;
- }
-
- try
- {
- // Verify that the layer is in the document (sanity checking)
- if (this.Document != null)
- {
- if (value != null && !this.Document.Layers.Contains(value))
- {
- throw new InvalidOperationException("ActiveLayer was changed to a layer that is not contained within the Document");
- }
- }
- else
- {
- // Document == null
- if (value != null)
- {
- throw new InvalidOperationException("ActiveLayer was set to non-null while Document was null");
- }
- }
-
- // Finally, set the field.
- this.activeLayer = value;
- }
-
- finally
- {
- if (deactivateTool)
- {
- PopNullTool();
- this.EnableToolPulse = true;
- }
- }
-
- OnLayerChanged();
- }
- }
-
- public int ActiveLayerIndex
- {
- get
- {
- return Document.Layers.IndexOf(ActiveLayer);
- }
-
- set
- {
- this.ActiveLayer = (Layer)Document.Layers[value];
- }
- }
-
- public bool EnableToolPulse
- {
- get
- {
- return this.toolPulseTimer.Enabled;
- }
-
- set
- {
- this.toolPulseTimer.Enabled = value;
- }
- }
-
- public HistoryStack History
- {
- get
- {
- return this.history;
- }
- }
-
- public Tool Tool
- {
- get
- {
- return this.activeTool;
- }
- }
-
- public Type GetToolType()
- {
- if (Tool != null)
- {
- return Tool.GetType();
- }
- else
- {
- return null;
- }
- }
-
- public void SetToolFromType(Type toolType)
- {
- if (toolType == GetToolType())
- {
- return;
- }
- else if (toolType == null)
- {
- SetTool(null);
- }
- else
- {
- Tool newTool = CreateTool(toolType);
- SetTool(newTool);
- }
- }
-
- public void PushNullTool()
- {
- if (this.nullToolCount == 0)
- {
- this.preNullTool = GetToolType();
- this.SetTool(null);
- this.nullToolCount = 1;
- }
- else
- {
- ++this.nullToolCount;
- }
- }
-
- public void PopNullTool()
- {
- --this.nullToolCount;
-
- if (this.nullToolCount == 0)
- {
- this.SetToolFromType(this.preNullTool);
- this.preNullTool = null;
- }
- else if (this.nullToolCount < 0)
- {
- throw new InvalidOperationException("PopNullTool() call was not matched with PushNullTool()");
- }
- }
-
- public Type PreviousActiveToolType
- {
- get
- {
- return this.previousActiveToolType;
- }
- }
-
- public void SetTool(Tool copyMe)
- {
- OnToolChanging();
-
- if (this.activeTool != null)
- {
- this.previousActiveToolType = this.activeTool.GetType();
- this.activeTool.CursorChanged -= ToolCursorChangedHandler;
- this.activeTool.PerformDeactivate();
- this.activeTool.Dispose();
- this.activeTool = null;
- }
-
- if (copyMe == null)
- {
- EnableToolPulse = false;
- }
- else
- {
- Tracing.LogFeature("SetTool(" + copyMe.GetType().FullName + ")");
- this.activeTool = CreateTool(copyMe.GetType());
- this.activeTool.PerformActivate();
- this.activeTool.CursorChanged += ToolCursorChangedHandler;
-
- if (this.suspendToolCursorChanges <= 0)
- {
- Cursor = this.activeTool.Cursor;
- }
-
- EnableToolPulse = true;
- }
-
- OnToolChanged();
- }
-
- public Tool CreateTool(Type toolType)
- {
- return DocumentWorkspace.CreateTool(toolType, this);
- }
-
- private static Tool CreateTool(Type toolType, DocumentWorkspace dc)
- {
- ConstructorInfo ci = toolType.GetConstructor(new Type[] { typeof(DocumentWorkspace) });
- Tool tool = (Tool)ci.Invoke(new object[] { dc });
- return tool;
- }
-
- private static void InitializeTools()
- {
- // add all the tools
- tools = new Type[]
- {
- typeof(RectangleSelectTool),
- typeof(MoveTool),
- typeof(LassoSelectTool),
- typeof(MoveSelectionTool),
-
- typeof(EllipseSelectTool),
- typeof(ZoomTool),
-
- typeof(MagicWandTool),
- typeof(PanTool),
-
- typeof(PaintBucketTool),
- typeof(GradientTool),
-
- typeof(PaintBrushTool),
- typeof(EraserTool),
- typeof(PencilTool),
- typeof(ColorPickerTool),
- typeof(CloneStampTool),
- typeof(RecolorTool),
- typeof(TextTool),
-
- typeof(LineTool),
- typeof(RectangleTool),
- typeof(RoundedRectangleTool),
- typeof(EllipseTool),
- typeof(FreeformShapeTool),
- };
- }
-
- private static void InitializeToolInfos()
- {
- int i = 0;
- toolInfos = new ToolInfo[tools.Length];
-
- foreach (Type toolType in tools)
- {
- using (Tool tool = DocumentWorkspace.CreateTool(toolType, null))
- {
- toolInfos[i] = tool.Info;
- ++i;
- }
- }
- }
-
- public static Type[] Tools
- {
- get
- {
- return (Type[])tools.Clone();
- }
- }
-
- public static ToolInfo[] ToolInfos
- {
- get
- {
- return (ToolInfo[])toolInfos.Clone();
- }
- }
-
- public event EventHandler ToolChanging;
- protected void OnToolChanging()
- {
- if (ToolChanging != null)
- {
- ToolChanging(this, EventArgs.Empty);
- }
- }
-
- public event EventHandler ToolChanged;
- protected void OnToolChanged()
- {
- if (ToolChanged != null)
- {
- ToolChanged(this, EventArgs.Empty);
- }
- }
-
- private void ToolCursorChangedHandler(object sender, EventArgs e)
- {
- if (this.suspendToolCursorChanges <= 0)
- {
- Cursor = this.activeTool.Cursor;
- }
- }
-
- // Note: static tool data is removed whenever the Document changes
- // TODO: shouldn't this be moved to the Tool class somehow?
- public object GetStaticToolData(Type toolType)
- {
- return staticToolData[toolType];
- }
-
- public void SetStaticToolData(Type toolType, object data)
- {
- staticToolData[toolType] = data;
- }
-
- public AppWorkspace AppWorkspace
- {
- get
- {
- return this.appWorkspace;
- }
-
- set
- {
- this.appWorkspace = value;
- }
- }
-
- public Selection Selection
- {
- get
- {
- return this.selection;
- }
- }
-
- public bool EnableOutlineAnimation
- {
- get
- {
- return this.selectionRenderer.EnableOutlineAnimation;
- }
-
- set
- {
- this.selectionRenderer.EnableOutlineAnimation = value;
- }
- }
-
- public bool EnableSelectionOutline
- {
- get
- {
- return this.selectionRenderer.EnableSelectionOutline;
- }
-
- set
- {
- this.selectionRenderer.EnableSelectionOutline = value;
- }
- }
-
- public bool EnableSelectionTinting
- {
- get
- {
- return this.selectionRenderer.EnableSelectionTinting;
- }
-
- set
- {
- this.selectionRenderer.EnableSelectionTinting = value;
- }
- }
-
- public void ResetOutlineWhiteOpacity()
- {
- this.selectionRenderer.ResetOutlineWhiteOpacity();
- }
-
- public event EventHandler FilePathChanged;
- protected virtual void OnFilePathChanged()
- {
- if (FilePathChanged != null)
- {
- FilePathChanged(this, EventArgs.Empty);
- }
- }
-
- public string FilePath
- {
- get
- {
- return this.filePath;
- }
- }
-
- public string GetFriendlyName()
- {
- string friendlyName;
-
- if (this.filePath != null)
- {
- friendlyName = Path.GetFileName(this.filePath);
- }
- else
- {
- friendlyName = PdnResources.GetString("Untitled.FriendlyName");
- }
-
- return friendlyName;
- }
-
- public FileType FileType
- {
- get
- {
- return this.fileType;
- }
- }
-
- public SaveConfigToken SaveConfigToken
- {
- get
- {
- if (this.saveConfigToken == null)
- {
- return null;
- }
- else
- {
- return (SaveConfigToken)this.saveConfigToken.Clone();
- }
- }
- }
-
- public event EventHandler SaveOptionsChanged;
- protected virtual void OnSaveOptionsChanged()
- {
- if (SaveOptionsChanged != null)
- {
- SaveOptionsChanged(this, EventArgs.Empty);
- }
- }
-
- /// <summary>
- /// Sets the FileType and SaveConfigToken parameters that are used if the
- /// user chooses "Save" from the File menu. These are not used by the
- /// DocumentControl class and should be used by whoever actually goes
- /// to save the Document instance.
- /// </summary>
- /// <param name="fileType"></param>
- /// <param name="saveParameters"></param>
- public void SetDocumentSaveOptions(string newFilePath, FileType newFileType, SaveConfigToken newSaveConfigToken)
- {
- this.filePath = newFilePath;
- OnFilePathChanged();
-
- this.fileType = newFileType;
-
- if (newSaveConfigToken == null)
- {
- this.saveConfigToken = null;
- }
- else
- {
- this.saveConfigToken = (SaveConfigToken)newSaveConfigToken.Clone();
- }
-
- OnSaveOptionsChanged();
- }
-
- public void GetDocumentSaveOptions(out string filePathResult, out FileType fileTypeResult, out SaveConfigToken saveConfigTokenResult)
- {
- filePathResult = this.filePath;
- fileTypeResult = this.fileType;
-
- if (this.saveConfigToken == null)
- {
- saveConfigTokenResult = null;
- }
- else
- {
- saveConfigTokenResult = (SaveConfigToken)this.saveConfigToken.Clone();
- }
- }
-
- private bool isScratchSurfaceBorrowed = false;
- private string borrowScratchSurfaceReason = string.Empty;
-
- /// The scratch, stencil, accumulation, whatever buffer. This is used by many parts
- /// of Paint.NET as a temporary area for which to store data.
- /// This surface is 'owned' by any Tool that is active. If you want to use this you
- /// must first deactivate the Tool using PushNullTool() and then reactivate it when
- /// you are finished by calling PopNullTool().
- /// Tools should use Tool.ScratchSurface instead of these API's.
-
- public Surface BorrowScratchSurface(string reason)
- {
- if (this.isScratchSurfaceBorrowed)
- {
- throw new InvalidOperationException(
- "ScratchSurface already borrowed: '" +
- this.borrowScratchSurfaceReason +
- "' (trying to borrow for: '" + reason + "')");
- }
-
- Tracing.Ping("Borrowing scratchSurface: " + reason);
- this.isScratchSurfaceBorrowed = true;
- this.borrowScratchSurfaceReason = reason;
- return this.scratchSurface;
- }
-
- public void ReturnScratchSurface(Surface borrowedScratchSurface)
- {
- if (!this.isScratchSurfaceBorrowed)
- {
- throw new InvalidOperationException("ScratchSurface wasn't borrowed");
- }
-
- if (this.scratchSurface != borrowedScratchSurface)
- {
- throw new InvalidOperationException("returned ScratchSurface doesn't match the real one");
- }
-
- Tracing.Ping("Returning scratchSurface: " + this.borrowScratchSurfaceReason);
- this.isScratchSurfaceBorrowed = false;
- this.borrowScratchSurfaceReason = string.Empty;
- }
-
- /// <summary>
- /// Updates any pertinent EXIF tags, such as "Creation Software", to be
- /// relevant or up-to-date.
- /// </summary>
- /// <param name="document"></param>
- private void UpdateExifTags(Document document)
- {
- // We want it to say "Creation Software: Paint.NET vX.Y"
- // I have verified that other image editing software overwrites this tag,
- // and does not just add it when it does not exist.
- PropertyItem pi = Exif.CreateAscii(ExifTagID.Software, PdnInfo.GetProductName(false));
- document.Metadata.ReplaceExifValues(ExifTagID.Software, new PropertyItem[1] { pi });
- }
-
- private ZoomBasis savedZb;
- private ScaleFactor savedSf;
- private int savedAli;
- protected override void OnDocumentChanging(Document newDocument)
- {
- base.OnDocumentChanging(newDocument);
-
- this.savedZb = this.ZoomBasis;
- this.savedSf = ScaleFactor;
-
- if (this.ActiveLayer != null)
- {
- this.savedAli = ActiveLayerIndex;
- }
- else
- {
- this.savedAli = -1;
- }
-
- if (newDocument != null)
- {
- UpdateExifTags(newDocument);
- }
-
- if (this.Document != null)
- {
- foreach (Layer layer in this.Document.Layers)
- {
- layer.PropertyChanging -= LayerPropertyChangingHandler;
- layer.PropertyChanged -= LayerPropertyChangedHandler;
- }
-
- this.Document.Layers.RemovingAt -= LayerRemovingHandler;
- this.Document.Layers.RemovedAt -= LayerRemovedHandler;
- this.Document.Layers.Inserted -= LayerInsertedHandler;
- }
-
- this.staticToolData.Clear();
-
- PushNullTool(); // matching Pop is in OnDocumetChanged()
- ActiveLayer = null;
-
- if (this.scratchSurface != null)
- {
- if (this.isScratchSurfaceBorrowed)
- {
- throw new InvalidOperationException("scratchSurface is currently borrowed: " + this.borrowScratchSurfaceReason);
- }
-
- if (newDocument == null || newDocument.Size != this.scratchSurface.Size)
- {
- this.scratchSurface.Dispose();
- this.scratchSurface = null;
- }
- }
-
- if (!Selection.IsEmpty)
- {
- Selection.Reset();
- }
- }
-
- protected override void OnDocumentChanged()
- {
- // if the ActiveLayer is not in this new document, then
- // we try to set ActiveLayer to the first layer in this
- // new document. But if the document contains no layers,
- // or is null, we just null the ActiveLayer.
- if (this.Document == null)
- {
- this.ActiveLayer = null;
- }
- else
- {
- if (this.activeTool != null)
- {
- throw new InvalidOperationException("Tool was not deactivated while Document was being changed");
- }
-
- if (this.scratchSurface != null)
- {
- if (this.isScratchSurfaceBorrowed)
- {
- throw new InvalidOperationException("scratchSurface is currently borrowed: " + this.borrowScratchSurfaceReason);
- }
-
- if (Document == null || this.scratchSurface.Size != Document.Size)
- {
- this.scratchSurface.Dispose();
- this.scratchSurface = null;
- }
- }
-
- this.scratchSurface = new Surface(this.Document.Size);
-
- this.Selection.ClipRectangle = this.Document.Bounds;
-
- foreach (Layer layer in this.Document.Layers)
- {
- layer.PropertyChanging += LayerPropertyChangingHandler;
- layer.PropertyChanged += LayerPropertyChangedHandler;
- }
-
- this.Document.Layers.RemovingAt += LayerRemovingHandler;
- this.Document.Layers.RemovedAt += LayerRemovedHandler;
- this.Document.Layers.Inserted += LayerInsertedHandler;
-
- if (!this.Document.Layers.Contains(this.ActiveLayer))
- {
- if (this.Document.Layers.Count > 0)
- {
- if (savedAli >= 0 && savedAli < this.Document.Layers.Count)
- {
- this.ActiveLayer = (Layer)this.Document.Layers[savedAli];
- }
- else
- {
- this.ActiveLayer = (Layer)this.Document.Layers[0];
- }
- }
- else
- {
- this.ActiveLayer = null;
- }
- }
-
- // we invalidate each layer so that the layer previews refresh themselves
- foreach (Layer layer in this.Document.Layers)
- {
- layer.Invalidate();
- }
-
- bool oldDirty = this.Document.Dirty;
- this.Document.Invalidate();
- this.Document.Dirty = oldDirty;
-
- this.ZoomBasis = this.savedZb;
- if (this.savedZb == ZoomBasis.ScaleFactor)
- {
- ScaleFactor = this.savedSf;
- }
- }
-
- PopNullTool();
- AutoScrollPosition = new Point(0, 0);
-
- base.OnDocumentChanged();
- }
-
- /// <summary>
- /// Takes the current Document from this DocumentWorkspace instance and adds it to the MRU list.
- /// </summary>
- /// <param name="fileName"></param>
- public void AddToMruList()
- {
- using (new PushNullToolMode(this))
- {
- string fullFileName = Path.GetFullPath(this.FilePath);
- int edgeLength = AppWorkspace.MostRecentFiles.IconSize;
- Surface thumb1 = RenderThumbnail(edgeLength, true, true);
-
- // Put it inside a square bitmap
- Surface thumb = new Surface(4 + edgeLength, 4 + edgeLength);
-
- thumb.Clear(ColorBgra.Transparent);
-
- Rectangle dstRect = new Rectangle((thumb.Width - thumb1.Width) / 2,
- (thumb.Height - thumb1.Height) / 2, thumb1.Width, thumb1.Height);
-
- thumb.CopySurface(thumb1, dstRect.Location);
-
- using (RenderArgs ra = new RenderArgs(thumb))
- {
- // Draw black border
- Rectangle borderRect = new Rectangle(dstRect.Left - 1, dstRect.Top - 1, dstRect.Width + 2, dstRect.Height + 2);
- --borderRect.Width;
- --borderRect.Height;
- ra.Graphics.DrawRectangle(Pens.Black, borderRect);
-
- Rectangle shadowRect = Rectangle.Inflate(borderRect, 1, 1);
- ++shadowRect.Width;
- ++shadowRect.Height;
- Utility.DrawDropShadow1px(ra.Graphics, shadowRect);
-
- thumb1.Dispose();
- thumb1 = null;
-
- MostRecentFile mrf = new MostRecentFile(fullFileName, Utility.FullCloneBitmap(ra.Bitmap));
-
- if (AppWorkspace.MostRecentFiles.Contains(fullFileName))
- {
- AppWorkspace.MostRecentFiles.Remove(fullFileName);
- }
-
- AppWorkspace.MostRecentFiles.Add(mrf);
- AppWorkspace.MostRecentFiles.SaveMruList();
- }
- }
- }
-
- /// <summary>
- /// Shows an OpenFileDialog or SaveFileDialog and populates the InitialDirectory from the global
- /// settings repository if possible.
- /// </summary>
- /// <param name="fd">The FileDialog to show.</param>
- /// <remarks>
- /// The FileDialog should already have its InitialDirectory populated as a suggestion of where to start.
- /// </remarks>
- public static DialogResult ShowFileDialog(Control owner, IFileDialog fd)
- {
- string initialDirectory = Settings.CurrentUser.GetString(SettingNames.LastFileDialogDirectory, fd.InitialDirectory);
-
- // TODO: spawn this in a background thread, if it doesn't respond within ~500ms?, assume the dir doesn't exist
- bool dirExists = false;
-
- try
- {
- DirectoryInfo dirInfo = new DirectoryInfo(initialDirectory);
-
- using (new WaitCursorChanger(owner))
- {
- dirExists = dirInfo.Exists;
-
- if (!dirInfo.Exists)
- {
- initialDirectory = fd.InitialDirectory;
- }
- }
- }
-
- catch (Exception)
- {
- initialDirectory = fd.InitialDirectory;
- }
-
- fd.InitialDirectory = initialDirectory;
-
- OurFileDialogUICallbacks ouc = new OurFileDialogUICallbacks();
- DialogResult result = fd.ShowDialog(owner, ouc);
-
- if (result == DialogResult.OK)
- {
- string fileName;
-
- if (fd is IFileOpenDialog)
- {
- string[] fileNames = ((IFileOpenDialog)fd).FileNames;
-
- if (fileNames.Length > 0)
- {
- fileName = fileNames[0];
- }
- else
- {
- fileName = null;
- }
- }
- else if (fd is IFileSaveDialog)
- {
- fileName = ((IFileSaveDialog)fd).FileName;
- }
- else
- {
- throw new InvalidOperationException();
- }
-
- if (fileName != null)
- {
- string newDir = Path.GetDirectoryName(fileName);
- Settings.CurrentUser.SetString(SettingNames.LastFileDialogDirectory, newDir);
- }
- else
- {
- throw new FileNotFoundException();
- }
- }
-
- return result;
- }
-
- private sealed class OurFileDialogUICallbacks
- : IFileDialogUICallbacks
- {
- public FileOverwriteAction ShowOverwritePrompt(IWin32Window owner, string pathName)
- {
- FileOverwriteAction returnVal;
-
- string title = PdnResources.GetString("SaveAs.OverwriteConfirmation.Title");
- string textFormat = PdnResources.GetString("SaveAs.OverwriteConfirmation.Text.Format");
- string fileName;
-
- try
- {
- fileName = Path.GetFileName(pathName);
- }
-
- catch (Exception)
- {
- fileName = pathName;
- }
-
- string text = string.Format(textFormat, fileName);
-
- DialogResult result = MessageBox.Show(owner, text, title, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2);
-
- switch (result)
- {
- case DialogResult.Yes:
- returnVal = FileOverwriteAction.Overwrite;
- break;
-
- case DialogResult.No:
- returnVal = FileOverwriteAction.Cancel;
- break;
-
- default:
- throw new InvalidEnumArgumentException();
- }
-
- return returnVal;
- }
-
- public bool ShowError(IWin32Window owner, string filePath, Exception ex)
- {
- if (ex is PathTooLongException)
- {
- string title = PdnInfo.GetBareProductName();
- string message = PdnResources.GetString("FileDialog.PathTooLongException.Message");
-
- MessageBox.Show(owner, message, title, MessageBoxButtons.OK, MessageBoxIcon.Error);
-
- return true;
- }
- else
- {
- return false;
- }
- }
-
- public IFileTransferProgressEvents CreateFileTransferProgressEvents()
- {
- return new OurProgressEvents();
- }
- }
-
- private sealed class OurProgressEvents
- : IFileTransferProgressEvents
- {
- private TransferProgressDialog progressDialog;
- private ICancelable cancelSink;
- private int itemCount = 0;
- private int itemOrdinal = 0;
- private string itemName = string.Empty;
- private long totalWork;
- private long totalProgress;
- private const int maxPBValue = 200; // granularity of progress bar. 100 means 1%, 200 means 0.5%, etc.
- private bool cancelRequested = false;
-
- private ManualResetEvent operationEnded = new ManualResetEvent(false);
-
- public OurProgressEvents()
- {
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "cancelSink")]
- public void BeginOperation(IWin32Window owner, EventHandler callWhenUIShown, ICancelable cancelSink)
- {
- if (this.progressDialog != null)
- {
- throw new InvalidOperationException("Operation already in progress");
- }
-
- this.progressDialog = new TransferProgressDialog();
- this.progressDialog.Text = PdnResources.GetString("DocumentWorkspace.ShowFileDialog.TransferProgress.Title");
- this.progressDialog.Icon = Utility.ImageToIcon(PdnResources.GetImageResource("Icons.MenuFileOpenIcon.png").Reference);
- this.progressDialog.ItemText = PdnResources.GetString("DocumentWorkspace.ShowFileDialog.ItemText.Initializing");
- this.progressDialog.ProgressBar.Style = ProgressBarStyle.Marquee;
- this.progressDialog.ProgressBar.Maximum = maxPBValue;
-
- this.progressDialog.CancelClicked +=
- delegate(object sender, EventArgs e)
- {
- this.cancelRequested = true;
- this.cancelSink.RequestCancel();
- UpdateUI();
- };
-
- EventHandler progressDialog_Shown =
- delegate(object sender, EventArgs e)
- {
- callWhenUIShown(this, EventArgs.Empty);
- };
-
- this.cancelSink = cancelSink;
- this.itemOrdinal = 0;
- this.cancelRequested = false;
- this.itemName = string.Empty;
- this.itemCount = 0;
- this.itemOrdinal = 0;
- this.totalProgress = 0;
- this.totalWork = 0;
-
- this.progressDialog.Shown += progressDialog_Shown;
- this.progressDialog.ShowDialog(owner);
- this.progressDialog.Shown -= progressDialog_Shown;
-
- this.progressDialog.Dispose();
- this.progressDialog = null;
- this.cancelSink = null;
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "itemCount")]
- public void SetItemCount(int itemCount)
- {
- if (this.progressDialog.InvokeRequired)
- {
- this.progressDialog.BeginInvoke(new Procedure<int>(SetItemCount), new object[] { itemCount });
- }
- else
- {
- this.itemCount = itemCount;
- UpdateUI();
- }
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "itemOrdinal")]
- public void SetItemOrdinal(int itemOrdinal)
- {
- if (this.progressDialog.InvokeRequired)
- {
- this.progressDialog.BeginInvoke(new Procedure<int>(SetItemOrdinal), new object[] { itemOrdinal });
- }
- else
- {
- this.itemOrdinal = itemOrdinal;
- this.totalWork = 0;
- this.totalProgress = 0;
- UpdateUI();
- }
- }
-
- public void SetItemInfo(string itemInfo)
- {
- if (this.progressDialog.InvokeRequired)
- {
- this.progressDialog.BeginInvoke(new Procedure<string>(SetItemInfo), new object[] { itemInfo });
- }
- else
- {
- this.itemName = itemInfo;
- UpdateUI();
- }
- }
-
- public void BeginItem()
- {
- if (this.progressDialog.InvokeRequired)
- {
- this.progressDialog.BeginInvoke(new Procedure(BeginItem), null);
- }
- else
- {
- this.progressDialog.ProgressBar.Style = ProgressBarStyle.Continuous;
- }
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "totalWork")]
- public void SetItemWorkTotal(long totalWork)
- {
- if (this.progressDialog.InvokeRequired)
- {
- this.progressDialog.BeginInvoke(new Procedure<long>(SetItemWorkTotal), new object[] { totalWork });
- }
- else
- {
- this.totalWork = totalWork;
- UpdateUI();
- }
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "totalProgress")]
- public void SetItemWorkProgress(long totalProgress)
- {
- if (this.progressDialog.InvokeRequired)
- {
- this.progressDialog.BeginInvoke(new Procedure<long>(SetItemWorkProgress), new object[] { totalProgress });
- }
- else
- {
- this.totalProgress = totalProgress;
- UpdateUI();
- }
- }
-
- public void EndItem(WorkItemResult result)
- {
- if (this.progressDialog.InvokeRequired)
- {
- this.progressDialog.BeginInvoke(new Procedure<WorkItemResult>(EndItem), new object[] { result });
- }
- else
- {
- }
- }
-
- public void EndOperation(OperationResult result)
- {
- if (this.progressDialog.InvokeRequired)
- {
- this.progressDialog.BeginInvoke(new Procedure<OperationResult>(EndOperation), new object[] { result });
- }
- else
- {
- this.progressDialog.Close();
- }
- }
-
- public WorkItemFailureAction ReportItemFailure(Exception ex)
- {
- if (this.progressDialog.InvokeRequired)
- {
- object result = this.progressDialog.Invoke(
- new Function<WorkItemFailureAction, Exception>(ReportItemFailure),
- new object[] { ex });
-
- return (WorkItemFailureAction)result;
- }
- else
- {
- WorkItemFailureAction result;
- result = ShowFileTransferFailedDialog(ex);
- return result;
- }
- }
-
- private WorkItemFailureAction ShowFileTransferFailedDialog(Exception ex)
- {
- WorkItemFailureAction result;
- Icon formIcon = this.progressDialog.Icon;
-
- string formTitle = PdnResources.GetString("DocumentWorkspace.ShowFileDialog.ItemFailureDialog.Title");
-
- Image taskImage = PdnResources.GetImageResource("Icons.WarningIcon.png").Reference;
-
- string introTextFormat = PdnResources.GetString("DocumentWorkspace.ShowFileDialog.ItemFailureDialog.IntroText.Format");
- string introText = string.Format(introTextFormat, ex.Message);
-
- TaskButton retryTB = new TaskButton(
- PdnResources.GetImageResource("Icons.MenuImageRotate90CWIcon.png").Reference,
- PdnResources.GetString("DocumentWorkspace.ShowFileDialog.RetryTB.ActionText"),
- PdnResources.GetString("DocumentWorkspace.ShowFileDialog.RetryTB.ExplanationText"));
-
- TaskButton skipTB = new TaskButton(
- PdnResources.GetImageResource("Icons.HistoryFastForwardIcon.png").Reference,
- PdnResources.GetString("DocumentWorkspace.ShowFileDialog.SkipTB.ActionText"),
- PdnResources.GetString("DocumentWorkspace.ShowFileDialog.SkipTB.ExplanationText"));
-
- TaskButton cancelTB = new TaskButton(
- PdnResources.GetImageResource("Icons.CancelIcon.png").Reference,
- PdnResources.GetString("DocumentWorkspace.ShowFileDialog.CancelTB.ActionText"),
- PdnResources.GetString("DocumentWorkspace.ShowFileDialog.CancelTB.ExplanationText"));
-
- List<TaskButton> taskButtons = new List<TaskButton>();
- taskButtons.Add(retryTB);
-
- // Only have the Skip button if there is more than 1 item being transferred.
- // If only 1 item is begin transferred, Skip and Cancel are essentially synonymous.
- if (this.itemCount > 1)
- {
- taskButtons.Add(skipTB);
- }
-
- taskButtons.Add(cancelTB);
-
- int width96 = (TaskDialog.DefaultPixelWidth96Dpi * 4) / 3; // 33% wider
-
- TaskButton clickedTB = TaskDialog.Show(
- this.progressDialog,
- formIcon,
- formTitle,
- taskImage,
- true,
- introText,
- taskButtons.ToArray(),
- retryTB,
- cancelTB,
- width96);
-
- if (clickedTB == retryTB)
- {
- result = WorkItemFailureAction.RetryItem;
- }
- else if (clickedTB == skipTB)
- {
- result = WorkItemFailureAction.SkipItem;
- }
- else
- {
- result = WorkItemFailureAction.CancelOperation;
- }
-
- return result;
- }
-
- private void UpdateUI()
- {
- int itemCount2 = Math.Max(1, this.itemCount);
-
- double startValue = (double)this.itemOrdinal / (double)itemCount2;
- double endValue = (double)(this.itemOrdinal + 1) / (double)itemCount2;
-
- long totalWork2 = Math.Max(1, this.totalWork);
- double lerp = (double)this.totalProgress / (double)totalWork2;
-
- double newValue = Utility.Lerp(startValue, endValue, lerp);
- int newValueInt = (int)Math.Ceiling(maxPBValue * newValue);
-
- if (this.cancelRequested)
- {
- this.progressDialog.CancelEnabled = false;
- this.progressDialog.ItemText = PdnResources.GetString("DocumentWorkspace.ShowFileDialog.ItemText.Canceling");
- this.progressDialog.OperationProgress = string.Empty;
- this.progressDialog.ProgressBar.Style = ProgressBarStyle.Marquee;
- }
- else
- {
- this.progressDialog.CancelEnabled = true;
- this.progressDialog.ItemText = this.itemName;
- string progressFormat = PdnResources.GetString("DocumentWorkspace.ShowFileDialog.ProgressText.Format");
- string progressText = string.Format(progressFormat, this.itemOrdinal + 1, this.itemCount);
- this.progressDialog.OperationProgress = progressText;
- this.progressDialog.ProgressBar.Style = ProgressBarStyle.Continuous;
- this.progressDialog.ProgressBar.Value = newValueInt;
- }
- }
- }
-
- public static DialogResult ChooseFile(Control parent, out string fileName)
- {
- return ChooseFile(parent, out fileName, null);
- }
-
- public static DialogResult ChooseFile(Control parent, out string fileName, string startingDir)
- {
- string[] fileNames;
- DialogResult result = ChooseFiles(parent, out fileNames, false, startingDir);
-
- if (result == DialogResult.OK)
- {
- fileName = fileNames[0];
- }
- else
- {
- fileName = null;
- }
-
- return result;
- }
-
- public static DialogResult ChooseFiles(Control owner, out string[] fileNames, bool multiselect)
- {
- return ChooseFiles(owner, out fileNames, multiselect, null);
- }
-
- public static DialogResult ChooseFiles(Control owner, out string[] fileNames, bool multiselect, string startingDir)
- {
- FileTypeCollection fileTypes = FileTypes.GetFileTypes();
-
- using (IFileOpenDialog ofd = SystemLayer.CommonDialogs.CreateFileOpenDialog())
- {
- if (startingDir != null)
- {
- ofd.InitialDirectory = startingDir;
- }
- else
- {
- ofd.InitialDirectory = GetDefaultSavePath();
- }
-
- ofd.CheckFileExists = true;
- ofd.CheckPathExists = true;
- ofd.Multiselect = multiselect;
-
- ofd.Filter = fileTypes.ToString(true, PdnResources.GetString("FileDialog.Types.AllImages"), false, true);
- ofd.FilterIndex = 0;
-
- DialogResult result = ShowFileDialog(owner, ofd);
-
- if (result == DialogResult.OK)
- {
- fileNames = ofd.FileNames;
- }
- else
- {
- fileNames = new string[0];
- }
-
- return result;
- }
- }
-
- /// <summary>
- /// Use this to get a save config token. You should already know the filename and file type.
- /// An existing save config token is optional and will be used to pre-populate the config dialog.
- /// </summary>
- /// <param name="fileType"></param>
- /// <param name="saveConfigToken"></param>
- /// <param name="newSaveConfigToken"></param>
- /// <returns>false if the user cancelled, otherwise true</returns>
- private bool GetSaveConfigToken(
- FileType currentFileType,
- SaveConfigToken currentSaveConfigToken,
- out SaveConfigToken newSaveConfigToken,
- Surface saveScratchSurface)
- {
- if (currentFileType.SupportsConfiguration)
- {
- using (SaveConfigDialog scd = new SaveConfigDialog())
- {
- scd.ScratchSurface = saveScratchSurface;
-
- ProgressEventHandler peh = delegate(object sender, ProgressEventArgs e)
- {
- if (e.Percent < 0 || e.Percent >= 100)
- {
- AppWorkspace.Widgets.StatusBarProgress.ResetProgressStatusBar();
- AppWorkspace.Widgets.StatusBarProgress.EraseProgressStatusBar();
- }
- else
- {
- AppWorkspace.Widgets.StatusBarProgress.SetProgressStatusBar(e.Percent);
- }
- };
-
- //if (currentFileType.SavesWithProgress)
- {
- scd.Progress += peh;
- }
-
- scd.Document = Document;
- scd.FileType = currentFileType;
-
- SaveConfigToken token = currentFileType.GetLastSaveConfigToken();
- if (currentSaveConfigToken != null &&
- token.GetType() == currentSaveConfigToken.GetType())
- {
- scd.SaveConfigToken = currentSaveConfigToken;
- }
-
- scd.EnableInstanceOpacity = false;
-
- // show configuration/preview dialog
- DialogResult dr = scd.ShowDialog(this);
-
- //if (currentFileType.SavesWithProgress)
- {
- scd.Progress -= peh;
- AppWorkspace.Widgets.StatusBarProgress.ResetProgressStatusBar();
- AppWorkspace.Widgets.StatusBarProgress.EraseProgressStatusBar();
- }
-
- if (dr == DialogResult.OK)
- {
- newSaveConfigToken = scd.SaveConfigToken;
- return true;
- }
- else
- {
- newSaveConfigToken = null;
- return false;
- }
- }
- }
- else
- {
- newSaveConfigToken = currentFileType.GetLastSaveConfigToken();
- return true;
- }
- }
-
- /// <summary>
- /// Used to set the file name, file type, and save config token
- /// </summary>
- /// <param name="newFileName"></param>
- /// <param name="newFileType"></param>
- /// <param name="newSaveConfigToken"></param>
- /// <returns>true if the user clicked through and accepted, or false if they cancelled at any point</returns>
- private bool DoSaveAsDialog(
- out string newFileName,
- out FileType newFileType,
- out SaveConfigToken newSaveConfigToken,
- Surface saveScratchSurface)
- {
- FileTypeCollection fileTypes = FileTypes.GetFileTypes();
-
- using (IFileSaveDialog sfd = SystemLayer.CommonDialogs.CreateFileSaveDialog())
- {
- sfd.AddExtension = true;
- sfd.CheckPathExists = true;
- sfd.OverwritePrompt = true;
- string filter = fileTypes.ToString(false, null, true, false);
- sfd.Filter = filter;
-
- string localFileName;
- FileType localFileType;
- SaveConfigToken localSaveConfigToken;
- GetDocumentSaveOptions(out localFileName, out localFileType, out localSaveConfigToken);
-
- if (Document.Layers.Count > 1 &&
- localFileType != null &&
- !localFileType.SupportsLayers)
- {
- localFileType = null;
- }
-
- if (localFileType == null)
- {
- if (Document.Layers.Count == 1)
- {
- localFileType = PdnFileTypes.Png;
- }
- else
- {
- localFileType = PdnFileTypes.Pdn;
- }
-
- localFileName = Path.ChangeExtension(localFileName, localFileType.DefaultExtension);
- }
-
- if (localFileName == null)
- {
- string name = GetDefaultSaveName();
- string newName = Path.ChangeExtension(name, localFileType.DefaultExtension);
- localFileName = Path.Combine(GetDefaultSavePath(), newName);
- }
-
- // If the filename is only an extension (i.e. ".lmnop") then we must treat it specially
- string fileNameOnly = Path.GetFileName(localFileName);
- if (fileNameOnly.Length >= 1 && fileNameOnly[0] == '.')
- {
- sfd.FileName = localFileName;
- }
- else
- {
- sfd.FileName = Path.ChangeExtension(localFileName, null);
- }
-
- sfd.FilterIndex = 1 + fileTypes.IndexOfFileType(localFileType);
- sfd.InitialDirectory = Path.GetDirectoryName(localFileName);
- sfd.Title = PdnResources.GetString("SaveAsDialog.Title");
-
- DialogResult dr1 = ShowFileDialog(this, sfd);
- bool result;
-
- if (dr1 != DialogResult.OK)
- {
- result = false;
- }
- else
- {
- localFileName = sfd.FileName;
- FileType fileType2 = fileTypes[sfd.FilterIndex - 1];
- result = GetSaveConfigToken(fileType2, localSaveConfigToken, out localSaveConfigToken, saveScratchSurface);
- localFileType = fileType2;
- }
-
- if (result)
- {
- newFileName = localFileName;
- newFileType = localFileType;
- newSaveConfigToken = localSaveConfigToken;
- }
- else
- {
- newFileName = null;
- newFileType = null;
- newSaveConfigToken = null;
- }
-
- return result;
- }
- }
-
- /// <summary>
- /// Warns the user that we need to flatten the image.
- /// </summary>
- /// <returns>Returns DialogResult.Yes if they want to proceed or DialogResult.No if they don't.</returns>
- private DialogResult WarnAboutFlattening()
- {
- Icon formIcon = Utility.ImageToIcon(PdnResources.GetImageResource("Icons.MenuFileSaveIcon.png").Reference);
- string formTitle = PdnResources.GetString("WarnAboutFlattening.Title");
-
- string introText = PdnResources.GetString("WarnAboutFlattening.IntroText");
- Image taskImage = null;
-
- TaskButton flattenTB = new TaskButton(
- PdnResources.GetImageResource("Icons.MenuImageFlattenIcon.png").Reference,
- PdnResources.GetString("WarnAboutFlattening.FlattenTB.ActionText"),
- PdnResources.GetString("WarnAboutFlattening.FlattenTB.ExplanationText"));
-
- TaskButton cancelTB = new TaskButton(
- TaskButton.Cancel.Image,
- PdnResources.GetString("WarnAboutFlattening.CancelTB.ActionText"),
- PdnResources.GetString("WarnAboutFlattening.CancelTB.ExplanationText"));
-
- TaskButton clickedTB = TaskDialog.Show(
- AppWorkspace,
- formIcon,
- formTitle,
- taskImage,
- true,
- introText,
- new TaskButton[] { flattenTB, cancelTB },
- flattenTB,
- cancelTB,
- (TaskDialog.DefaultPixelWidth96Dpi * 5) / 4);
-
- if (clickedTB == flattenTB)
- {
- return DialogResult.Yes;
- }
- else
- {
- return DialogResult.No;
- }
- }
-
- private static string GetDefaultSaveName()
- {
- return PdnResources.GetString("Untitled.FriendlyName");
- }
-
- private static string GetDefaultSavePath()
- {
- string myPics;
-
- try
- {
- myPics = Shell.GetVirtualPath(VirtualFolderName.UserPictures, false);
- DirectoryInfo dirInfo = new DirectoryInfo(myPics); // validate
- }
-
- catch (Exception)
- {
- myPics = "";
- }
-
- string dir = Settings.CurrentUser.GetString(SettingNames.LastFileDialogDirectory, null);
-
- if (dir == null)
- {
- dir = myPics;
- }
- else
- {
- try
- {
- DirectoryInfo dirInfo = new DirectoryInfo(dir);
-
- if (!dirInfo.Exists)
- {
- dir = myPics;
- }
- }
-
- catch (Exception)
- {
- dir = myPics;
- }
- }
-
- return dir;
- }
-
- public bool DoSave()
- {
- return DoSave(false);
- }
-
- /// <summary>
- /// Does the dirty work for a File->Save operation. If any of the "Save Options" in the
- /// DocumentWorkspace are null, this will call DoSaveAs(). If the image has more than 1
- /// layer but the file type they want to save with does not support layers, then it will
- /// ask the user about flattening the image.
- /// </summary>
- /// <param name="tryToFlatten">
- /// If true, will ask the user about flattening if the workspace's saveFileType does not
- /// support layers and the image has more than 1 layer.
- /// If false, then DoSaveAs will be called and the fileType will be prepopulated with
- /// the .PDN type.
- /// </param>
- /// <returns><b>true</b> if the file was saved, <b>false</b> if the user cancelled</returns>
- protected bool DoSave(bool tryToFlatten)
- {
- using (new PushNullToolMode(this))
- {
- string newFileName;
- FileType newFileType;
- SaveConfigToken newSaveConfigToken;
-
- GetDocumentSaveOptions(out newFileName, out newFileType, out newSaveConfigToken);
-
- // if they haven't specified a filename, then revert to "Save As" behavior
- if (newFileName == null)
- {
- return DoSaveAs();
- }
-
- // if we have a filename but no file type, try to infer the file type
- if (newFileType == null)
- {
- FileTypeCollection fileTypes = FileTypes.GetFileTypes();
- string ext = Path.GetExtension(newFileName);
- int index = fileTypes.IndexOfExtension(ext);
- FileType inferredFileType = fileTypes[index];
- newFileType = inferredFileType;
- }
-
- // if the image has more than 1 layer but is saving with a file type that
- // does not support layers, then we must ask them if we may flatten the
- // image first
- if (Document.Layers.Count > 1 && !newFileType.SupportsLayers)
- {
- if (!tryToFlatten)
- {
- return DoSaveAs();
- }
- else
- {
- DialogResult dr = WarnAboutFlattening();
-
- if (dr == DialogResult.Yes)
- {
- ExecuteFunction(new FlattenFunction());
- }
- else
- {
- return false;
- }
- }
- }
-
- // get the configuration!
- if (newSaveConfigToken == null)
- {
- Surface scratch = BorrowScratchSurface(this.GetType().Name + ".DoSave() calling GetSaveConfigToken()");
-
- bool result;
- try
- {
- result = GetSaveConfigToken(newFileType, newSaveConfigToken, out newSaveConfigToken, scratch);
- }
-
- finally
- {
- ReturnScratchSurface(scratch);
- }
-
- if (!result)
- {
- return false;
- }
- }
-
- // At this point fileName, fileType, and saveConfigToken must all be non-null
-
- // if the document supports custom headers, embed a thumbnail in there
- if (newFileType.SupportsCustomHeaders)
- {
- using (new WaitCursorChanger(this))
- {
- Utility.GCFullCollect();
- const int maxDim = 256;
-
- Surface thumb;
- Surface flattened = BorrowScratchSurface(this.GetType().Name + ".DoSave() preparing embedded thumbnail");
-
- try
- {
- Document.Flatten(flattened);
-
- if (Document.Width > maxDim || Document.Height > maxDim)
- {
- int width;
- int height;
-
- if (Document.Width > Document.Height)
- {
- width = maxDim;
- height = (Document.Height * maxDim) / Document.Width;
- }
- else
- {
- height = maxDim;
- width = (Document.Width * maxDim) / Document.Height;
- }
-
- int thumbWidth = Math.Max(1, width);
- int thumbHeight = Math.Max(1, height);
-
- thumb = new Surface(thumbWidth, thumbHeight);
- thumb.SuperSamplingFitSurface(flattened);
- }
- else
- {
- thumb = new Surface(flattened.Size);
- thumb.CopySurface(flattened);
- }
- }
-
- finally
- {
- ReturnScratchSurface(flattened);
- }
-
- Document thumbDoc = new Document(thumb.Width, thumb.Height);
- BitmapLayer thumbLayer = new BitmapLayer(thumb);
- BitmapLayer backLayer = new BitmapLayer(thumb.Width, thumb.Height);
- backLayer.Surface.Clear(ColorBgra.Transparent);
- thumb.Dispose();
- thumbDoc.Layers.Add(backLayer);
- thumbDoc.Layers.Add(thumbLayer);
- MemoryStream thumbPng = new MemoryStream();
- PropertyBasedSaveConfigToken pngToken = PdnFileTypes.Png.CreateDefaultSaveConfigToken();
- PdnFileTypes.Png.Save(thumbDoc, thumbPng, pngToken, null, null, false);
- byte[] thumbBytes = thumbPng.ToArray();
-
- string thumbString = Convert.ToBase64String(thumbBytes, Base64FormattingOptions.None);
- thumbDoc.Dispose();
-
- string thumbXml = "<thumb png=\"" + thumbString + "\" />";
- Document.CustomHeaders = thumbXml;
- }
- }
-
- // save!
- bool success = false;
- Stream stream = null;
-
- try
- {
- stream = (Stream)new FileStream(newFileName, FileMode.Create, FileAccess.Write);
-
- using (new WaitCursorChanger(this))
- {
- Utility.GCFullCollect();
-
- SaveProgressDialog sd = new SaveProgressDialog(this);
- Surface scratch = BorrowScratchSurface(this.GetType().Name + ".DoSave() handing off scratch surface to SaveProgressDialog.Save()");
-
- try
- {
- sd.Save(stream, Document, newFileType, newSaveConfigToken, scratch);
- }
-
- finally
- {
- ReturnScratchSurface(scratch);
- }
-
- success = true;
-
- this.lastSaveTime = DateTime.Now;
-
- stream.Close();
- stream = null;
- }
- }
-
- catch (UnauthorizedAccessException)
- {
- Utility.ErrorBox(this, PdnResources.GetString("SaveImage.Error.UnauthorizedAccessException"));
- }
-
- catch (SecurityException)
- {
- Utility.ErrorBox(this, PdnResources.GetString("SaveImage.Error.SecurityException"));
- }
-
- catch (DirectoryNotFoundException)
- {
- Utility.ErrorBox(this, PdnResources.GetString("SaveImage.Error.DirectoryNotFoundException"));
- }
-
- catch (IOException)
- {
- Utility.ErrorBox(this, PdnResources.GetString("SaveImage.Error.IOException"));
- }
-
- catch (OutOfMemoryException)
- {
- Utility.ErrorBox(this, PdnResources.GetString("SaveImage.Error.OutOfMemoryException"));
- }
-
- #if !DEBUG
- catch (Exception)
- {
- Utility.ErrorBox(this, PdnResources.GetString("SaveImage.Error.Exception"));
- }
- #endif
-
- finally
- {
- if (stream != null)
- {
- stream.Close();
- stream = null;
- }
- }
-
- if (success)
- {
- Shell.AddToRecentDocumentsList(newFileName);
- }
- else
- {
- return false;
- }
-
- // reset the dirty bit so they won't be asked to save on quitting
- Document.Dirty = false;
-
- // some misc. book keeping ...
- AddToMruList();
-
- // and finally, shout happiness by way of ...
- return true;
- }
- }
-
- /// <summary>
- /// Does the grunt work to do a File->Save As operation.
- /// </summary>
- /// <returns><b>true</b> if the file was saved correctly, <b>false</b> if the user cancelled</returns>
- public bool DoSaveAs()
- {
- using (new PushNullToolMode(this))
- {
- string newFileName;
- FileType newFileType;
- SaveConfigToken newSaveConfigToken;
-
- Surface scratch = BorrowScratchSurface(this.GetType() + ".DoSaveAs() handing off scratch surface to DoSaveAsDialog()");
-
- bool result;
- try
- {
- result = DoSaveAsDialog(out newFileName, out newFileType, out newSaveConfigToken, scratch);
- }
-
- finally
- {
- ReturnScratchSurface(scratch);
- }
-
- if (result)
- {
- string oldFileName;
- FileType oldFileType;
- SaveConfigToken oldSaveConfigToken;
-
- GetDocumentSaveOptions(out oldFileName, out oldFileType, out oldSaveConfigToken);
- SetDocumentSaveOptions(newFileName, newFileType, newSaveConfigToken);
-
- bool result2 = DoSave(true);
-
- if (!result2)
- {
- SetDocumentSaveOptions(oldFileName, oldFileType, oldSaveConfigToken);
- }
-
- return result2;
- }
- else
- {
- return false;
- }
- }
- }
-
- public static Document LoadDocument(Control owner, string fileName, out FileType fileTypeResult, ProgressEventHandler progressCallback)
- {
- FileTypeCollection fileTypes;
- int ftIndex;
- FileType fileType;
-
- fileTypeResult = null;
-
- try
- {
- fileTypes = FileTypes.GetFileTypes();
- ftIndex = fileTypes.IndexOfExtension(Path.GetExtension(fileName));
-
- if (ftIndex == -1)
- {
- Utility.ErrorBox(owner, PdnResources.GetString("LoadImage.Error.ImageTypeNotRecognized"));
- return null;
- }
-
- fileType = fileTypes[ftIndex];
- fileTypeResult = fileType;
- }
-
- catch (ArgumentException)
- {
- string format = PdnResources.GetString("LoadImage.Error.InvalidFileName.Format");
- string error = string.Format(format, fileName);
- Utility.ErrorBox(owner, error);
- return null;
- }
-
- Document document = null;
-
- using (new WaitCursorChanger(owner))
- {
- Utility.GCFullCollect();
- Stream stream = null;
-
- try
- {
- try
- {
- stream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
- long totalBytes = 0;
-
- SiphonStream siphonStream = new SiphonStream(stream);
-
- IOEventHandler ioEventHandler = null;
- ioEventHandler =
- delegate(object sender, IOEventArgs e)
- {
- if (progressCallback != null)
- {
- totalBytes += (long)e.Count;
- double percent = Utility.Clamp(100.0 * ((double)totalBytes / (double)siphonStream.Length), 0, 100);
- progressCallback(null, new ProgressEventArgs(percent));
- }
- };
-
- siphonStream.IOFinished += ioEventHandler;
-
- using (new WaitCursorChanger(owner))
- {
- document = fileType.Load(siphonStream);
-
- if (progressCallback != null)
- {
- progressCallback(null, new ProgressEventArgs(100.0));
- }
- }
-
- siphonStream.IOFinished -= ioEventHandler;
- siphonStream.Close();
- }
-
- catch (WorkerThreadException ex)
- {
- Type innerExType = ex.InnerException.GetType();
- ConstructorInfo ci = innerExType.GetConstructor(new Type[] { typeof(string), typeof(Exception) });
-
- if (ci == null)
- {
- throw;
- }
- else
- {
- Exception ex2 = (Exception)ci.Invoke(new object[] { "Worker thread threw an exception of this type", ex.InnerException });
- throw ex2;
- }
- }
- }
-
- catch (ArgumentException)
- {
- if (fileName.Length == 0)
- {
- Utility.ErrorBox(owner, PdnResources.GetString("LoadImage.Error.BlankFileName"));
- }
- else
- {
- Utility.ErrorBox(owner, PdnResources.GetString("LoadImage.Error.ArgumentException"));
- }
- }
-
- catch (UnauthorizedAccessException)
- {
- Utility.ErrorBox(owner, PdnResources.GetString("LoadImage.Error.UnauthorizedAccessException"));
- }
-
- catch (SecurityException)
- {
- Utility.ErrorBox(owner, PdnResources.GetString("LoadImage.Error.SecurityException"));
- }
-
- catch (FileNotFoundException)
- {
- Utility.ErrorBox(owner, PdnResources.GetString("LoadImage.Error.FileNotFoundException"));
- }
-
- catch (DirectoryNotFoundException)
- {
- Utility.ErrorBox(owner, PdnResources.GetString("LoadImage.Error.DirectoryNotFoundException"));
- }
-
- catch (PathTooLongException)
- {
- Utility.ErrorBox(owner, PdnResources.GetString("LoadImage.Error.PathTooLongException"));
- }
-
- catch (IOException)
- {
- Utility.ErrorBox(owner, PdnResources.GetString("LoadImage.Error.IOException"));
- }
-
- catch (SerializationException)
- {
- Utility.ErrorBox(owner, PdnResources.GetString("LoadImage.Error.SerializationException"));
- }
-
- catch (OutOfMemoryException)
- {
- Utility.ErrorBox(owner, PdnResources.GetString("LoadImage.Error.OutOfMemoryException"));
- }
-
- catch (Exception)
- {
- Utility.ErrorBox(owner, PdnResources.GetString("LoadImage.Error.Exception"));
- }
-
- finally
- {
- if (stream != null)
- {
- stream.Close();
- stream = null;
- }
- }
- }
-
- return document;
- }
-
- public Surface RenderThumbnail(int maxEdgeLength, bool highQuality, bool forceUpToDate)
- {
- if (Document == null)
- {
- Surface ret = new Surface(maxEdgeLength, maxEdgeLength);
- ret.Clear(ColorBgra.Transparent);
- return ret;
- }
-
- Size thumbSize = Utility.ComputeThumbnailSize(Document.Size, maxEdgeLength);
- Surface thumb = new Surface(thumbSize);
- thumb.Clear(ColorBgra.Transparent);
-
- RenderCompositionTo(thumb, highQuality, forceUpToDate);
-
- return thumb;
- }
-
- Surface IThumbnailProvider.RenderThumbnail(int maxEdgeLength)
- {
- return RenderThumbnail(maxEdgeLength, true, false);
- }
- }
- }