CreateAndSaveSubgraphImages ( IGraph oSubgraph, String sVertexName, CreateSubgraphImagesAsyncArgs oCreateSubgraphImagesAsyncArgs, TemporaryImages oThumbnailImages ) { Debug.Assert(oSubgraph != null); Debug.Assert(!String.IsNullOrEmpty(sVertexName)); Debug.Assert(oCreateSubgraphImagesAsyncArgs != null); Debug.Assert(oThumbnailImages != null); AssertValid(); if (oCreateSubgraphImagesAsyncArgs.SaveToFolder) { CreateAndSaveSubgraphImageInFolder(oSubgraph, sVertexName, oCreateSubgraphImagesAsyncArgs); } if (oCreateSubgraphImagesAsyncArgs.CreateThumbnails) { CreateAndSaveThumbnailImage(oSubgraph, sVertexName, oCreateSubgraphImagesAsyncArgs, oThumbnailImages); } }
CreateAndSaveSubgraphImageInFolder ( IGraph oSubgraph, String sVertexName, CreateSubgraphImagesAsyncArgs oCreateSubgraphImagesAsyncArgs ) { Debug.Assert(oSubgraph != null); Debug.Assert(!String.IsNullOrEmpty(sVertexName)); Debug.Assert(oCreateSubgraphImagesAsyncArgs != null); Debug.Assert(oCreateSubgraphImagesAsyncArgs.SaveToFolder); AssertValid(); // Save the graph to a bitmap. Bitmap oBitmap = CreateSubgraphImage(oSubgraph, oCreateSubgraphImagesAsyncArgs, oCreateSubgraphImagesAsyncArgs.ImageSizePx); try { // Save the bitmap in the specified folder. SaveSubgraphImage(oBitmap, oCreateSubgraphImagesAsyncArgs.Folder, sVertexName, oCreateSubgraphImagesAsyncArgs ); } finally { GraphicsUtil.DisposeBitmap(ref oBitmap); } }
BackgroundWorker_DoWork ( object sender, DoWorkEventArgs e ) { Debug.Assert(sender is BackgroundWorker); AssertValid(); BackgroundWorker oBackgroundWorker = (BackgroundWorker)sender; Debug.Assert(e.Argument is CreateSubgraphImagesAsyncArgs); CreateSubgraphImagesAsyncArgs oCreateSubgraphImagesAsyncArgs = (CreateSubgraphImagesAsyncArgs)e.Argument; // The NodeXLVisual object couldn't be created by // CreateSubgraphImagesAsync(), because the object must be created by // the thread that uses it. Create it now. oCreateSubgraphImagesAsyncArgs.NodeXLVisual = CreateNodeXLVisual( oCreateSubgraphImagesAsyncArgs.GeneralUserSettings); CreateSubgraphImagesInternal(oCreateSubgraphImagesAsyncArgs, m_oBackgroundWorker, e); }
SaveSubgraphImage ( Bitmap oBitmap, String sFolder, String sFileNameNoExtension, CreateSubgraphImagesAsyncArgs oCreateSubgraphImagesAsyncArgs ) { Debug.Assert(oBitmap != null); Debug.Assert(!String.IsNullOrEmpty(sFolder)); Debug.Assert(!String.IsNullOrEmpty(sFileNameNoExtension)); Debug.Assert(oCreateSubgraphImagesAsyncArgs != null); AssertValid(); ImageFormat eImageFormat = oCreateSubgraphImagesAsyncArgs.ImageFormat; String sFileNameWithoutPath = FileUtil.EncodeIllegalFileNameChars(sFileNameNoExtension) + "." + SaveableImageFormats.GetFileExtension(eImageFormat); String sFileNameWithPath = Path.Combine(sFolder, sFileNameWithoutPath); SaveBitmap(oBitmap, sFileNameWithPath, eImageFormat); return(sFileNameWithoutPath); }
CreateAndSaveThumbnailImage ( IGraph oSubgraph, String sVertexName, CreateSubgraphImagesAsyncArgs oCreateSubgraphImagesAsyncArgs, TemporaryImages oThumbnailImages ) { Debug.Assert(oSubgraph != null); Debug.Assert(!String.IsNullOrEmpty(sVertexName)); Debug.Assert(oCreateSubgraphImagesAsyncArgs != null); Debug.Assert(oCreateSubgraphImagesAsyncArgs.CreateThumbnails); Debug.Assert(oThumbnailImages != null); AssertValid(); if (oThumbnailImages.Folder == null) { // Create a temporary folder where the thumbnail images will be // stored. String sTemporaryFolder = Path.Combine( Path.GetTempPath(), Path.GetRandomFileName() ); Directory.CreateDirectory(sTemporaryFolder); oThumbnailImages.Folder = sTemporaryFolder; } // Save the graph to a bitmap. Bitmap oBitmap = CreateSubgraphImage(oSubgraph, oCreateSubgraphImagesAsyncArgs, oCreateSubgraphImagesAsyncArgs.ThumbnailSizePx); try { // Save the bitmap in the temporary folder. String sTemporaryFileName = SaveSubgraphImage(oBitmap, oThumbnailImages.Folder, sVertexName, oCreateSubgraphImagesAsyncArgs ); // Add the file name to the dictionary. They key is the vertex // name and the value is the file name, without a path. oThumbnailImages.FileNames[sVertexName] = sTemporaryFileName; } finally { GraphicsUtil.DisposeBitmap(ref oBitmap); } }
CreateSubgraph ( IVertex oOriginalVertex, CreateSubgraphImagesAsyncArgs oCreateSubgraphImagesAsyncArgs ) { Debug.Assert(oOriginalVertex != null); Debug.Assert(oCreateSubgraphImagesAsyncArgs != null); AssertValid(); // Create a new empty graph that will contain the vertex's subgraph. IGraph oSubgraph = new Graph(); // Clone the original vertex, its adjacent vertices, and the connecting // edges into the subgraph. Decimal decLevels = oCreateSubgraphImagesAsyncArgs.Levels; IVertex oSubgraphVertex = CloneVertexIntoSubgraph(oOriginalVertex, oSubgraph, decLevels); if (oCreateSubgraphImagesAsyncArgs.SelectVertex) { // Select the vertex. oSubgraphVertex.SetValue(ReservedMetadataKeys.IsSelected, true); } if (oCreateSubgraphImagesAsyncArgs.SelectIncidentEdges) { // Select the vertex's incident edges. foreach (IEdge oIncidentEdge in oSubgraphVertex.IncidentEdges) { oIncidentEdge.SetValue(ReservedMetadataKeys.IsSelected, true); } } return(oSubgraph); }
SaveSubgraphImage ( Bitmap oBitmap, String sFolder, String sVertexName, CreateSubgraphImagesAsyncArgs oCreateSubgraphImagesAsyncArgs ) { Debug.Assert(oBitmap != null); Debug.Assert(!String.IsNullOrEmpty(sFolder)); Debug.Assert(!String.IsNullOrEmpty(sVertexName)); Debug.Assert(oCreateSubgraphImagesAsyncArgs != null); AssertValid(); ImageFormat eImageFormat = oCreateSubgraphImagesAsyncArgs.ImageFormat; // The "Img-" prefix is to prevent a vertex name like "con" or "lpt" // from causing the following exception when // System.Drawing.Image.Save() is called: // // [ExternalException]: A generic error occurred in GDI+. // // The exception occurs because "con" (console), "lpt" (line printer) // and some other names are reserved file names in Windows. String sFileNameNoPath = String.Format( "Img-{0}.{1}" , FileUtil.EncodeIllegalFileNameChars(sVertexName), SaveableImageFormats.GetFileExtension(eImageFormat) ); String sFileNameWithPath = Path.Combine(sFolder, sFileNameNoPath); SaveBitmap(oBitmap, sFileNameWithPath, eImageFormat); return(sFileNameNoPath); }
CreateSubgraphImage ( IGraph oSubgraph, CreateSubgraphImagesAsyncArgs oCreateSubgraphImagesAsyncArgs, Size oImageSizePx ) { Debug.Assert(oSubgraph != null); Debug.Assert(oCreateSubgraphImagesAsyncArgs != null); AssertValid(); Rectangle oSubgraphRectangle = new Rectangle(new Point(0, 0), oImageSizePx); // Lay out the graph, then draw it using the NodeXLVisual object. IAsyncLayout oLayout = oCreateSubgraphImagesAsyncArgs.Layout; oLayout.LayOutGraph(oSubgraph, new LayoutContext(oSubgraphRectangle)); NodeXLVisual oNodeXLVisual = oCreateSubgraphImagesAsyncArgs.NodeXLVisual; GraphDrawingContext oGraphDrawingContext = CreateGraphDrawingContext(oSubgraphRectangle, oLayout.Margin, oCreateSubgraphImagesAsyncArgs.GeneralUserSettings); oNodeXLVisual.GraphDrawer.DrawGraph(oSubgraph, oGraphDrawingContext); // Save the graph to a bitmap. Bitmap oBitmap = WpfGraphicsUtil.VisualToBitmap(oNodeXLVisual, oSubgraphRectangle.Width, oSubgraphRectangle.Height); return(oBitmap); }
SaveSubgraphImage ( Bitmap oBitmap, String sFolder, String sVertexName, CreateSubgraphImagesAsyncArgs oCreateSubgraphImagesAsyncArgs ) { Debug.Assert(oBitmap != null); Debug.Assert( !String.IsNullOrEmpty(sFolder) ); Debug.Assert( !String.IsNullOrEmpty(sVertexName) ); Debug.Assert(oCreateSubgraphImagesAsyncArgs != null); AssertValid(); ImageFormat eImageFormat = oCreateSubgraphImagesAsyncArgs.ImageFormat; // The "Img-" prefix is to prevent a vertex name like "con" or "lpt" // from causing the following exception when // System.Drawing.Image.Save() is called: // // [ExternalException]: A generic error occurred in GDI+. // // The exception occurs because "con" (console), "lpt" (line printer) // and some other names are reserved file names in Windows. String sFileNameNoPath = String.Format( "Img-{0}.{1}" , FileUtil.EncodeIllegalFileNameChars(sVertexName), SaveableImageFormats.GetFileExtension(eImageFormat) ); String sFileNameWithPath = Path.Combine(sFolder, sFileNameNoPath); SaveBitmap(oBitmap, sFileNameWithPath, eImageFormat); return (sFileNameNoPath); }
//************************************************************************* // Method: SaveSubgraphImage() // /// <summary> /// Saves an image of a subgraph to disk. /// </summary> /// /// <param name="oBitmap"> /// Subgraph image. /// </param> /// /// <param name="sFolder"> /// Full path to the folder to save the image to. /// </param> /// /// <param name="sFileNameNoExtension"> /// Name of the file to save the image to, without a path or extension. /// </param> /// /// <param name="oCreateSubgraphImagesAsyncArgs"> /// Contains the arguments needed to asynchronously create subgraph images. /// </param> /// /// <returns> /// The name of the file the image was saved to, without a path. /// </returns> //************************************************************************* protected String SaveSubgraphImage( Bitmap oBitmap, String sFolder, String sFileNameNoExtension, CreateSubgraphImagesAsyncArgs oCreateSubgraphImagesAsyncArgs ) { Debug.Assert(oBitmap != null); Debug.Assert( !String.IsNullOrEmpty(sFolder) ); Debug.Assert( !String.IsNullOrEmpty(sFileNameNoExtension) ); Debug.Assert(oCreateSubgraphImagesAsyncArgs != null); AssertValid(); ImageFormat eImageFormat = oCreateSubgraphImagesAsyncArgs.ImageFormat; String sFileNameWithoutPath = FileUtil.EncodeIllegalFileNameChars(sFileNameNoExtension) + "." + SaveableImageFormats.GetFileExtension(eImageFormat); String sFileNameWithPath = Path.Combine(sFolder, sFileNameWithoutPath); SaveBitmap(oBitmap, sFileNameWithPath, eImageFormat); return (sFileNameWithoutPath); }
//************************************************************************* // Method: CreateAndSaveSubgraphImageInFolder() // /// <summary> /// Creates an image of a subgraph for one of a graph's vertices and saves /// the image to a specified folder. /// </summary> /// /// <param name="oSubgraph"> /// The subgraph to create an image for. /// </param> /// /// <param name="sVertexName"> /// Name of the vertex the subgraph is for. /// </param> /// /// <param name="oCreateSubgraphImagesAsyncArgs"> /// Contains the arguments needed to asynchronously create subgraph images. /// </param> //************************************************************************* protected void CreateAndSaveSubgraphImageInFolder( IGraph oSubgraph, String sVertexName, CreateSubgraphImagesAsyncArgs oCreateSubgraphImagesAsyncArgs ) { Debug.Assert(oSubgraph != null); Debug.Assert( !String.IsNullOrEmpty(sVertexName) ); Debug.Assert(oCreateSubgraphImagesAsyncArgs != null); Debug.Assert(oCreateSubgraphImagesAsyncArgs.SaveToFolder); AssertValid(); // Save the graph to a bitmap. Bitmap oBitmap = CreateSubgraphImage(oSubgraph, oCreateSubgraphImagesAsyncArgs, oCreateSubgraphImagesAsyncArgs.ImageSizePx); try { // Save the bitmap in the specified folder. SaveSubgraphImage(oBitmap, oCreateSubgraphImagesAsyncArgs.Folder, sVertexName, oCreateSubgraphImagesAsyncArgs ); } finally { GraphicsUtil.DisposeBitmap(ref oBitmap); } }
//************************************************************************* // Method: CreateSubgraphImagesAsync() // /// <summary> /// Asynchronously creates images of a subgraph for each of a graph's /// vertices and saves the images to disk. /// </summary> /// /// <param name="graph"> /// The graph to use. /// </param> /// /// <param name="selectedVertices"> /// Collection of the vertices in <paramref name="graph" /> that were /// selected by the user in the workbook from which the graph was created. /// Can be empty but not null. /// </param> /// /// <param name="levels"> /// The number of levels of adjacent vertices to include in each subgraph. /// Must be a multiple of 0.5. If 0, a subgraph includes just the vertex; /// if 1, it includes the vertex and its adjacent vertices; if 2, it /// includes the vertex, its adjacent vertices, and their adjacent /// vertices; and so on. The difference between N.5 and N.0 is that N.5 /// includes any edges connecting the outermost vertices to each other, /// whereas N.0 does not. 1.5, for example, includes any edges that /// connect the vertex's adjacent vertices to each other, whereas 1.0 /// includes only those edges that connect the adjacent vertices to the /// vertex. /// </param> /// /// <param name="saveToFolder"> /// true to save subgraph images to a folder. /// </param> /// /// <param name="folder"> /// The folder to save subgraph images to. Used only if <paramref /// name="saveToFolder" /> is true. /// </param> /// /// <param name="imageSizePx"> /// The size of each subgraph image saved to a folder, in pixels. Used /// only if <paramref name="saveToFolder" /> is true. /// </param> /// /// <param name="imageFormat"> /// The format of each subgraph image saved to a folder. Used only if /// <paramref name="saveToFolder" /> is true. /// </param> /// /// <param name="createThumbnails"> /// true to save thumbnail images to a temporary folder. /// </param> /// /// <param name="thumbnailSizePx"> /// The size of each thumbnail image, in pixels. Used only if <paramref /// name="createThumbnails" /> is true. /// </param> /// /// <param name="selectedVerticesOnly"> /// true to create subgraph images for the vertices in <paramref /// name="selectedVertices" /> only, false to create them for all images. /// </param> /// /// <param name="selectVertex"> /// true to select the vertex around which each subgraph is created. /// </param> /// /// <param name="selectIncidentEdges"> /// true to select the incident edges of the vertex around which each /// subgraph is created. /// </param> /// /// <param name="generalUserSettings"> /// The user's general user settings. /// </param> /// /// <param name="layoutUserSettings"> /// The user's layout user settings. /// </param> /// /// <remarks> /// When image creation completes, the <see /// cref="ImageCreationCompleted" /> event fires. /// /// <para> /// If thumbnail images are created, they are saved to a temporary folder. /// Information about the thumbnail images can be found in the <see /// cref="TemporaryImages" /> object stored in the <see /// cref="RunWorkerCompletedEventArgs.Result" /> propery of the <see /// cref="RunWorkerCompletedEventArgs" /> returned by the <see /// cref="ImageCreationCompleted" /> event. /// </para> /// /// <para> /// To cancel the analysis, call <see cref="CancelAsync" />. /// </para> /// /// </remarks> //************************************************************************* public void CreateSubgraphImagesAsync( IGraph graph, ICollection<IVertex> selectedVertices, Decimal levels, Boolean saveToFolder, String folder, Size imageSizePx, ImageFormat imageFormat, Boolean createThumbnails, Size thumbnailSizePx, Boolean selectedVerticesOnly, Boolean selectVertex, Boolean selectIncidentEdges, GeneralUserSettings generalUserSettings, LayoutUserSettings layoutUserSettings ) { Debug.Assert(graph != null); Debug.Assert(selectedVertices != null); Debug.Assert(levels >= 0); Debug.Assert(Decimal.Remainder(levels, 0.5M) == 0M); Debug.Assert( !saveToFolder || !String.IsNullOrEmpty(folder) ); Debug.Assert( !saveToFolder || imageSizePx.Width > 0); Debug.Assert( !saveToFolder || imageSizePx.Height > 0); Debug.Assert( !createThumbnails || thumbnailSizePx.Width > 0); Debug.Assert( !createThumbnails || thumbnailSizePx.Height > 0); Debug.Assert(generalUserSettings != null); AssertValid(); const String MethodName = "CreateSubgraphImagesAsync"; if (this.IsBusy) { throw new InvalidOperationException( String.Format( "{0}:{1}: An asynchronous operation is already in progress." , this.ClassName, MethodName ) ); } // Wrap the arguments in an object that can be passed to // BackgroundWorker.RunWorkerAsync(). CreateSubgraphImagesAsyncArgs oCreateSubgraphImagesAsyncArgs = new CreateSubgraphImagesAsyncArgs(); oCreateSubgraphImagesAsyncArgs.Graph = graph; oCreateSubgraphImagesAsyncArgs.SelectedVertices = selectedVertices; oCreateSubgraphImagesAsyncArgs.Levels = levels; oCreateSubgraphImagesAsyncArgs.SaveToFolder = saveToFolder; oCreateSubgraphImagesAsyncArgs.Folder = folder; oCreateSubgraphImagesAsyncArgs.ImageSizePx = imageSizePx; oCreateSubgraphImagesAsyncArgs.ImageFormat = imageFormat; oCreateSubgraphImagesAsyncArgs.CreateThumbnails = createThumbnails; oCreateSubgraphImagesAsyncArgs.ThumbnailSizePx = thumbnailSizePx; oCreateSubgraphImagesAsyncArgs.SelectedVerticesOnly = selectedVerticesOnly; oCreateSubgraphImagesAsyncArgs.SelectVertex = selectVertex; oCreateSubgraphImagesAsyncArgs.SelectIncidentEdges = selectIncidentEdges; oCreateSubgraphImagesAsyncArgs.GeneralUserSettings = generalUserSettings; oCreateSubgraphImagesAsyncArgs.Layout = CreateLayout(layoutUserSettings); // Note: the NodeXLVisual object can't be created yet, because it must // be created on the same thread that uses it. It will get created by // BackgroundWorker_DoWork(). oCreateSubgraphImagesAsyncArgs.NodeXLVisual = null; // Create a BackgroundWorker and handle its events. m_oBackgroundWorker = new BackgroundWorker(); m_oBackgroundWorker.WorkerReportsProgress = true; m_oBackgroundWorker.WorkerSupportsCancellation = true; m_oBackgroundWorker.DoWork += new DoWorkEventHandler( BackgroundWorker_DoWork); m_oBackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(BackgroundWorker_ProgressChanged); m_oBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler( BackgroundWorker_RunWorkerCompleted); m_oBackgroundWorker.RunWorkerAsync(oCreateSubgraphImagesAsyncArgs); }
CreateSubgraphImagesInternal ( CreateSubgraphImagesAsyncArgs oCreateSubgraphImagesAsyncArgs, BackgroundWorker oBackgroundWorker, DoWorkEventArgs oDoWorkEventArgs ) { Debug.Assert(oCreateSubgraphImagesAsyncArgs != null); Debug.Assert(oBackgroundWorker != null); Debug.Assert(oDoWorkEventArgs != null); AssertValid(); // Create an object to keep track of the thumbnail images this method // creates and stores in a temporary folder. TemporaryImages oThumbnailImages = new TemporaryImages(); oThumbnailImages.ImageSizePx = oCreateSubgraphImagesAsyncArgs.ThumbnailSizePx; oDoWorkEventArgs.Result = oThumbnailImages; ICollection <IVertex> oVertices; if (oCreateSubgraphImagesAsyncArgs.SelectedVerticesOnly) { oVertices = oCreateSubgraphImagesAsyncArgs.SelectedVertices; } else { oVertices = oCreateSubgraphImagesAsyncArgs.Graph.Vertices; } Int32 iSubgraphsCreated = 0; Boolean bSaveToFolder = oCreateSubgraphImagesAsyncArgs.SaveToFolder; Boolean bCreateThumbnails = oCreateSubgraphImagesAsyncArgs.CreateThumbnails; if (bSaveToFolder || bCreateThumbnails) { foreach (IVertex oVertex in oVertices) { if (oBackgroundWorker.CancellationPending) { if (oThumbnailImages.Folder != null) { // Delete the entire temporary folder. Directory.Delete(oThumbnailImages.Folder, true); oThumbnailImages.Folder = null; } oDoWorkEventArgs.Cancel = true; break; } String sVertexName = oVertex.Name; oBackgroundWorker.ReportProgress(0, String.Format( "Creating subgraph image for \"{0}\"." , sVertexName )); // Create a subgraph for the vertex. IGraph oSubgraph = CreateSubgraph(oVertex, oCreateSubgraphImagesAsyncArgs); // Create and save images for the subgraph. CreateAndSaveSubgraphImages(oSubgraph, sVertexName, oCreateSubgraphImagesAsyncArgs, oThumbnailImages); iSubgraphsCreated++; } } oBackgroundWorker.ReportProgress(0, String.Format( "Done. Created {0} subgraph {1}." , iSubgraphsCreated.ToString(ExcelTemplateForm.Int32Format), StringUtil.MakePlural("image", iSubgraphsCreated) )); }
//************************************************************************* // Method: CreateAndSaveSubgraphImages() // /// <summary> /// Creates images of a subgraph for one of a graph's vertices and saves /// the images to disk. /// </summary> /// /// <param name="oSubgraph"> /// The subgraph to create images for. /// </param> /// /// <param name="sVertexName"> /// Name of the vertex the subgraph is for. /// </param> /// /// <param name="oCreateSubgraphImagesAsyncArgs"> /// Contains the arguments needed to asynchronously create subgraph images. /// </param> /// /// <param name="oThumbnailImages"> /// Keeps track of the thumbnail images this method creates and stores in a /// temporary folder. /// </param> /// /// <remarks> /// This method creates zero, one, or two images of a subgraph and saves /// them to disk. /// </remarks> //************************************************************************* protected void CreateAndSaveSubgraphImages( IGraph oSubgraph, String sVertexName, CreateSubgraphImagesAsyncArgs oCreateSubgraphImagesAsyncArgs, TemporaryImages oThumbnailImages ) { Debug.Assert(oSubgraph != null); Debug.Assert( !String.IsNullOrEmpty(sVertexName) ); Debug.Assert(oCreateSubgraphImagesAsyncArgs != null); Debug.Assert(oThumbnailImages != null); AssertValid(); if (oCreateSubgraphImagesAsyncArgs.SaveToFolder) { CreateAndSaveSubgraphImageInFolder(oSubgraph, sVertexName, oCreateSubgraphImagesAsyncArgs); } if (oCreateSubgraphImagesAsyncArgs.CreateThumbnails) { CreateAndSaveThumbnailImage(oSubgraph, sVertexName, oCreateSubgraphImagesAsyncArgs, oThumbnailImages); } }
CreateSubgraphImagesAsync ( IGraph graph, ICollection <IVertex> selectedVertices, Decimal levels, Boolean saveToFolder, String folder, Size imageSizePx, ImageFormat imageFormat, Boolean createThumbnails, Size thumbnailSizePx, Boolean selectedVerticesOnly, Boolean selectVertex, Boolean selectIncidentEdges, GeneralUserSettings generalUserSettings, LayoutUserSettings layoutUserSettings ) { Debug.Assert(graph != null); Debug.Assert(selectedVertices != null); Debug.Assert(levels >= 0); Debug.Assert(Decimal.Remainder(levels, 0.5M) == 0M); Debug.Assert(!saveToFolder || !String.IsNullOrEmpty(folder)); Debug.Assert(!saveToFolder || imageSizePx.Width > 0); Debug.Assert(!saveToFolder || imageSizePx.Height > 0); Debug.Assert(!createThumbnails || thumbnailSizePx.Width > 0); Debug.Assert(!createThumbnails || thumbnailSizePx.Height > 0); Debug.Assert(generalUserSettings != null); AssertValid(); const String MethodName = "CreateSubgraphImagesAsync"; if (this.IsBusy) { throw new InvalidOperationException(String.Format( "{0}:{1}: An asynchronous operation is already in progress." , this.ClassName, MethodName )); } // Wrap the arguments in an object that can be passed to // BackgroundWorker.RunWorkerAsync(). CreateSubgraphImagesAsyncArgs oCreateSubgraphImagesAsyncArgs = new CreateSubgraphImagesAsyncArgs(); oCreateSubgraphImagesAsyncArgs.Graph = graph; oCreateSubgraphImagesAsyncArgs.SelectedVertices = selectedVertices; oCreateSubgraphImagesAsyncArgs.Levels = levels; oCreateSubgraphImagesAsyncArgs.SaveToFolder = saveToFolder; oCreateSubgraphImagesAsyncArgs.Folder = folder; oCreateSubgraphImagesAsyncArgs.ImageSizePx = imageSizePx; oCreateSubgraphImagesAsyncArgs.ImageFormat = imageFormat; oCreateSubgraphImagesAsyncArgs.CreateThumbnails = createThumbnails; oCreateSubgraphImagesAsyncArgs.ThumbnailSizePx = thumbnailSizePx; oCreateSubgraphImagesAsyncArgs.SelectedVerticesOnly = selectedVerticesOnly; oCreateSubgraphImagesAsyncArgs.SelectVertex = selectVertex; oCreateSubgraphImagesAsyncArgs.SelectIncidentEdges = selectIncidentEdges; oCreateSubgraphImagesAsyncArgs.GeneralUserSettings = generalUserSettings; oCreateSubgraphImagesAsyncArgs.Layout = CreateLayout(layoutUserSettings); // Note: the NodeXLVisual object can't be created yet, because it must // be created on the same thread that uses it. It will get created by // BackgroundWorker_DoWork(). oCreateSubgraphImagesAsyncArgs.NodeXLVisual = null; // Create a BackgroundWorker and handle its events. m_oBackgroundWorker = new BackgroundWorker(); m_oBackgroundWorker.WorkerReportsProgress = true; m_oBackgroundWorker.WorkerSupportsCancellation = true; m_oBackgroundWorker.DoWork += new DoWorkEventHandler( BackgroundWorker_DoWork); m_oBackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(BackgroundWorker_ProgressChanged); m_oBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler( BackgroundWorker_RunWorkerCompleted); m_oBackgroundWorker.RunWorkerAsync(oCreateSubgraphImagesAsyncArgs); }
//************************************************************************* // Method: CreateAndSaveThumbnailImage() // /// <summary> /// Creates a thumbnail image of a subgraph for one of a graph's vertices. /// </summary> /// /// <param name="oSubgraph"> /// The subgraph to create an image for. /// </param> /// /// <param name="sVertexName"> /// Name of the vertex the subgraph is for. /// </param> /// /// <param name="oCreateSubgraphImagesAsyncArgs"> /// Contains the arguments needed to asynchronously create subgraph images. /// </param> /// /// <param name="oThumbnailImages"> /// Keeps track of the thumbnail images this method creates and stores in a /// temporary folder. /// </param> //************************************************************************* protected void CreateAndSaveThumbnailImage( IGraph oSubgraph, String sVertexName, CreateSubgraphImagesAsyncArgs oCreateSubgraphImagesAsyncArgs, TemporaryImages oThumbnailImages ) { Debug.Assert(oSubgraph != null); Debug.Assert( !String.IsNullOrEmpty(sVertexName) ); Debug.Assert(oCreateSubgraphImagesAsyncArgs != null); Debug.Assert(oCreateSubgraphImagesAsyncArgs.CreateThumbnails); Debug.Assert(oThumbnailImages != null); AssertValid(); if (oThumbnailImages.Folder == null) { // Create a temporary folder where the thumbnail images will be // stored. String sTemporaryFolder = Path.Combine( Path.GetTempPath(), Path.GetRandomFileName() ); Directory.CreateDirectory(sTemporaryFolder); oThumbnailImages.Folder = sTemporaryFolder; } // Save the graph to a bitmap. Bitmap oBitmap = CreateSubgraphImage(oSubgraph, oCreateSubgraphImagesAsyncArgs, oCreateSubgraphImagesAsyncArgs.ThumbnailSizePx); try { // Save the bitmap in the temporary folder. String sTemporaryFileName = SaveSubgraphImage(oBitmap, oThumbnailImages.Folder, sVertexName, oCreateSubgraphImagesAsyncArgs ); // Add the file name to the dictionary. They key is the vertex // name and the value is the file name, without a path. oThumbnailImages.FileNames[sVertexName] = sTemporaryFileName; } finally { GraphicsUtil.DisposeBitmap(ref oBitmap); } }
//************************************************************************* // Method: CreateSubgraphImagesInternal() // /// <summary> /// Creates an image of a subgraph for each of a graph's vertices and saves /// the images to disk. /// </summary> /// /// <param name="oCreateSubgraphImagesAsyncArgs"> /// Contains the arguments needed to asynchronously create subgraph images. /// </param> /// /// <param name="oBackgroundWorker"> /// A BackgroundWorker object. /// </param> /// /// <param name="oDoWorkEventArgs"> /// A DoWorkEventArgs object. /// </param> //************************************************************************* protected void CreateSubgraphImagesInternal( CreateSubgraphImagesAsyncArgs oCreateSubgraphImagesAsyncArgs, BackgroundWorker oBackgroundWorker, DoWorkEventArgs oDoWorkEventArgs ) { Debug.Assert(oCreateSubgraphImagesAsyncArgs != null); Debug.Assert(oBackgroundWorker != null); Debug.Assert(oDoWorkEventArgs != null); AssertValid(); // Create an object to keep track of the thumbnail images this method // creates and stores in a temporary folder. TemporaryImages oThumbnailImages = new TemporaryImages(); oThumbnailImages.ImageSizePx = oCreateSubgraphImagesAsyncArgs.ThumbnailSizePx; oDoWorkEventArgs.Result = oThumbnailImages; ICollection<IVertex> oVertices; if (oCreateSubgraphImagesAsyncArgs.SelectedVerticesOnly) { oVertices = oCreateSubgraphImagesAsyncArgs.SelectedVertices; } else { oVertices = oCreateSubgraphImagesAsyncArgs.Graph.Vertices; } Int32 iSubgraphsCreated = 0; Boolean bSaveToFolder = oCreateSubgraphImagesAsyncArgs.SaveToFolder; Boolean bCreateThumbnails = oCreateSubgraphImagesAsyncArgs.CreateThumbnails; if (bSaveToFolder || bCreateThumbnails) { foreach (IVertex oVertex in oVertices) { if (oBackgroundWorker.CancellationPending) { if (oThumbnailImages.Folder != null) { // Delete the entire temporary folder. Directory.Delete(oThumbnailImages.Folder, true); oThumbnailImages.Folder = null; } oDoWorkEventArgs.Cancel = true; break; } String sVertexName = oVertex.Name; oBackgroundWorker.ReportProgress(0, String.Format( "Creating subgraph image for \"{0}\"." , sVertexName ) ); // Create a subgraph for the vertex. IGraph oSubgraph = CreateSubgraph(oVertex, oCreateSubgraphImagesAsyncArgs); // Create and save images for the subgraph. CreateAndSaveSubgraphImages(oSubgraph, sVertexName, oCreateSubgraphImagesAsyncArgs, oThumbnailImages); iSubgraphsCreated++; } } oBackgroundWorker.ReportProgress(0, String.Format( "Done. Created {0} subgraph {1}." , iSubgraphsCreated.ToString(ExcelTemplateForm.Int32Format), StringUtil.MakePlural("image", iSubgraphsCreated) ) ); }
//************************************************************************* // Method: CreateSubgraphImage() // /// <summary> /// Creates an image of a subgraph for one of a graph's vertices. /// </summary> /// /// <param name="oSubgraph"> /// The subgraph to create an image for. /// </param> /// /// <param name="oCreateSubgraphImagesAsyncArgs"> /// Contains the arguments needed to asynchronously create subgraph images. /// </param> /// /// <param name="oImageSizePx"> /// Size of the image, in pixels. /// </param> /// /// <returns> /// The subgraph image, as a Bitmap. /// </returns> //************************************************************************* protected Bitmap CreateSubgraphImage( IGraph oSubgraph, CreateSubgraphImagesAsyncArgs oCreateSubgraphImagesAsyncArgs, Size oImageSizePx ) { Debug.Assert(oSubgraph != null); Debug.Assert(oCreateSubgraphImagesAsyncArgs != null); AssertValid(); Rectangle oSubgraphRectangle = new Rectangle(new Point(0, 0), oImageSizePx); // Lay out the graph, then draw it using the NodeXLVisual object. IAsyncLayout oLayout = oCreateSubgraphImagesAsyncArgs.Layout; oLayout.LayOutGraph( oSubgraph, new LayoutContext(oSubgraphRectangle) ); NodeXLVisual oNodeXLVisual = oCreateSubgraphImagesAsyncArgs.NodeXLVisual; GraphDrawingContext oGraphDrawingContext = CreateGraphDrawingContext(oSubgraphRectangle, oLayout.Margin, oCreateSubgraphImagesAsyncArgs.GeneralUserSettings); oNodeXLVisual.GraphDrawer.DrawGraph(oSubgraph, oGraphDrawingContext); // Save the graph to a bitmap. Bitmap oBitmap = WpfGraphicsUtil.VisualToBitmap(oNodeXLVisual, oSubgraphRectangle.Width, oSubgraphRectangle.Height); return (oBitmap); }
//************************************************************************* // Method: CreateSubgraph() // /// <summary> /// Creates a subgraph for one of a graph's vertices. /// </summary> /// /// <param name="oOriginalVertex"> /// The vertex to create a subgraph for. /// </param> /// /// <param name="oCreateSubgraphImagesAsyncArgs"> /// Contains the arguments needed to asynchronously create subgraph images. /// </param> /// /// <returns> /// A new subgraph. /// </returns> //************************************************************************* protected IGraph CreateSubgraph( IVertex oOriginalVertex, CreateSubgraphImagesAsyncArgs oCreateSubgraphImagesAsyncArgs ) { Debug.Assert(oOriginalVertex != null); Debug.Assert(oCreateSubgraphImagesAsyncArgs != null); AssertValid(); // Create a new empty graph that will contain the vertex's subgraph. IGraph oSubgraph = new Graph(); // Clone the original vertex, its adjacent vertices, and the connecting // edges into the subgraph. Decimal decLevels = oCreateSubgraphImagesAsyncArgs.Levels; IVertex oSubgraphVertex = CloneVertexIntoSubgraph(oOriginalVertex, oSubgraph, decLevels); if (oCreateSubgraphImagesAsyncArgs.SelectVertex) { // Select the vertex. oSubgraphVertex.SetValue(ReservedMetadataKeys.IsSelected, true); } if (oCreateSubgraphImagesAsyncArgs.SelectIncidentEdges) { // Select the vertex's incident edges. foreach (IEdge oIncidentEdge in oSubgraphVertex.IncidentEdges) { oIncidentEdge.SetValue(ReservedMetadataKeys.IsSelected, true); } } return (oSubgraph); }