Browse Source

merged userstory12 into develop

Vincenz Mechler 5 years ago
parent
commit
b8491bfe8f

+ 3 - 0
SketchAssistant/SketchAssistant.Tests/SketchAssistant.Tests.csproj

@@ -48,6 +48,9 @@
     <Reference Include="System" />
     <Reference Include="System.Core" />
     <Reference Include="System.Drawing" />
+    <Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll</HintPath>
+    </Reference>
     <Reference Include="System.Windows.Forms" />
   </ItemGroup>
   <ItemGroup>

+ 97 - 0
SketchAssistant/SketchAssistant.Tests/UnitTest1.cs

@@ -273,4 +273,101 @@ namespace Tests
             Assert.AreEqual(currLabel, message);
         }
     }
+
+    [TestClass]
+    public class FileImporterTests
+    {
+        [DataTestMethod]
+        [DataRow(new int[] { 54, 43, 57, 11, 145, 34, 113, 299, 0 }, new int[] { 33, 42, 140, 30, 30, 30, 32, 145, 2 })]
+        [DataRow(new int[] { 33, 42, 140, 30, 30, 30, 32, 145, 2 }, new int[] { 33, 42, 140, 30, 30, 30, 32, 145, 2 })]
+        [DataRow(new int[] { 33, 42, 140, 30, 30, 30, 32, 145, 2 }, new int[] { 54, 43, 57, 11, 145, 34, 113, 199, 0 })]
+        public void ParseISADInputSuccessfulTest(int[] xCoordinates, int[] yCoordinates)
+        {
+            Form1 program = new Form1();
+            FileImporter uut = new SketchAssistant.FileImporter(program);
+
+            List<String> file = new List<string>();
+            file.Add("drawing");
+            file.Add("300x200");
+            for (int i = 0; i < xCoordinates.Length - 2; i += 3)
+            {
+                file.Add("line");
+                file.Add(xCoordinates[i] + ";" + yCoordinates[i]);
+                file.Add(xCoordinates[i + 1] + ";" + yCoordinates[i + 1]);
+                file.Add(xCoordinates[i + 2] + ";" + yCoordinates[i + 2]);
+                file.Add("endline");
+            }
+            file.Add("enddrawing");
+
+            (int, int, List<Line>) values = uut.ParseISADInputForTesting(file.ToArray());
+            program.CreateCanvasAndSetPictureForTesting(values.Item1, values.Item2, values.Item3);
+
+            Line[] drawing = GetLeftImage(program).ToArray();
+
+            Assert.AreEqual(xCoordinates.Length / 3, drawing.Length);
+            for (int i = 0; i < xCoordinates.Length - 2; i += 3)
+            {
+                Point[] currentLine = drawing[i / 3].GetPoints().ToArray();
+                Assert.AreEqual(3, currentLine.Length);
+                for (int j = 0; j < 3; j++)
+                {
+                    Assert.IsTrue(currentLine[j].X == xCoordinates[i + j] && currentLine[j].Y == yCoordinates[i + j]);
+                }
+            }
+        }
+
+        [DataTestMethod]
+        [DataRow(new String[] {})]
+        [DataRow(new String[] { "begindrawing", "300x300", "line", "50;50", "100;50", "endline", "enddrawing" })]
+        [DataRow(new String[] { "drawing", "300;300", "line", "50;50", "100;50", "endline", "enddrawing" })]
+        [DataRow(new String[] { "drawing", "30.5x300", "line", "50;50", "100;50", "endline", "enddrawing" })]
+        [DataRow(new String[] { "drawing", "line", "50;50", "100;50", "endline", "enddrawing" })]
+        [DataRow(new String[] { "drawing", "300x300", "beginline", "50;50", "100;50", "endline", "enddrawing" })]
+        [DataRow(new String[] { "drawing", "300x300", "line", "500;50", "100;50", "endline", "enddrawing" })]
+        [DataRow(new String[] { "drawing", "300x300", "line", "50x50", "100;50", "endline", "enddrawing" })]
+        [DataRow(new String[] { "drawing", "300x300", "line", "50", "100", "endline", "enddrawing" })]
+        [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "line", "endline", "enddrawing" })]
+        [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "100;50", "stopline", "enddrawing" })]
+        [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "100;50", "enddrawing" })]
+        [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "100;50", "endline", "endrawing" })]
+        [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "100;50", "endline" })]
+        public void ParseISADInputExceptionTest(String[] file)
+        {
+            bool exceptionThrown = false;
+            Form1 program = new Form1();
+            FileImporter uut = new SketchAssistant.FileImporter(program);
+            //check that left image initially is uninitialized
+            Assert.IsNull(GetLeftImage(program));
+            //initialize left image with a valid isad drawing
+            (int, int, List<Line>) values = uut.ParseISADInputForTesting(new string[] { "drawing", "300x205", "line", "40;40", "140;140", "endline", "enddrawing" });
+            program.CreateCanvasAndSetPictureForTesting(values.Item1, values.Item2, values.Item3);
+            //save left image for later comparison
+            List<Line> oldLeftImage = GetLeftImage(program);
+            try
+            {
+                //try to initialize the left image with an invalid isad drawing
+                (int, int, List<Line>) values1 = uut.ParseISADInputForTesting(file);
+                program.CreateCanvasAndSetPictureForTesting(values1.Item1, values1.Item2, values1.Item3);
+            }
+            catch(FileImporterException)
+            {
+                //save the occurence of an exception
+                exceptionThrown = true;
+            }
+            //check that an exception has been thrown
+            Assert.IsTrue(exceptionThrown);
+            //check that the left image has not been changed by the failed image import
+            Assert.AreEqual(oldLeftImage, GetLeftImage(program));
+        }
+
+        /// <summary>
+        /// local helper method retrieving the left image from a Form1 instance
+        /// </summary>
+        /// <returns>the left image of the given Form1 instance</returns>
+        private List<Line> GetLeftImage(Form1 program)
+        {
+            //cast is save as long as Form1#GetAllVariables() is conform to its contract
+            return (List<Line>) program.GetAllVariables()[4];
+        }
+    }
 }

+ 1 - 0
SketchAssistant/SketchAssistant.Tests/packages.config

@@ -2,4 +2,5 @@
 <packages>
   <package id="MSTest.TestAdapter" version="1.4.0" targetFramework="net461" />
   <package id="MSTest.TestFramework" version="1.4.0" targetFramework="net461" />
+  <package id="System.ValueTuple" version="4.5.0" targetFramework="net461" />
 </packages>

+ 155 - 0
SketchAssistant/SketchAssistant/FileImporter.cs

@@ -0,0 +1,155 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+namespace SketchAssistant
+{
+    public class FileImporter
+    {
+
+        /// <summary>
+        /// pointer to the running instance of main program
+        /// </summary>
+        Form1 program;
+
+        public FileImporter(Form1 newProgram)
+        {
+            program = newProgram;
+        }
+
+        /// <summary>
+        /// parses a drawing consisting of line objects, given as a file in the application specific .isad format
+        /// </summary>
+        /// <param name="fileName">the path of the input file</param>
+        /// <returns>the width and height of the left canvas and the parsed picture as a list of lines</returns>
+        public (int, int, List<Line>) ParseISADInputFile(String fileName)
+        {
+            return ParseISADInput(System.IO.File.ReadAllLines(fileName));
+        }
+
+        /// <summary>
+        /// parses a drawing consisting of line objects, given as the content of a .isad file, seperated into lines
+        /// </summary>
+        /// <param name="allLines">an array holding all lines of the input file</param>
+        /// <returns>the width and height of the left canvas and the parsed picture as a list of lines</returns>
+        private (int, int, List<Line>) ParseISADInput(String[] allLines)
+        {
+
+            if (allLines.Length == 0)
+            {
+                throw new FileImporterException("file is empty", "", -1);
+            }
+            if (!"drawing".Equals(allLines[0]))
+            {
+                throw new FileImporterException("file is not an interactive sketch assistant drawing", ".isad files have to start with the 'drawing' token", 1);
+            }
+            if (!"enddrawing".Equals(allLines[allLines.Length - 1]))
+            {
+                throw new FileImporterException("unterminated drawing definition", ".isad files have to end with the 'enddrawing' token", allLines.Length);
+            }
+
+            (int, int) dimensions = ParseISADHeader(allLines);
+            List<Line> picture = ParseISADBody(allLines, dimensions.Item1, dimensions.Item2);
+
+            return (dimensions.Item1, dimensions.Item2, picture);
+        }
+
+
+
+        /// <summary>
+        /// parses the first two lines of an input file in .isad format
+        /// </summary>
+        /// <param name="allLines">the input file as an array of lines</param>
+        /// <returns>the width and height of the left canvas</returns>
+        private (int, int) ParseISADHeader(String[] allLines)
+        {
+            int width;
+            int height;
+            if (!(allLines.Length > 1) || !Regex.Match(allLines[1], @"^\d+x?\d+$", RegexOptions.None).Success)
+            {
+                throw new FileImporterException("invalid or missing canvas size definition", "format: [width]x[heigth]", 2);
+            }
+            String[] size = allLines[1].Split('x');
+            width = Convert.ToInt32(size[0]);
+            height = Convert.ToInt32(size[1]);
+            return (width, height);
+        }
+
+        /// <summary>
+        /// parses all line entries of an input file in .isad format
+        /// </summary>
+        /// <param name="allLines">the input file as an array of lines</param>
+        /// <returns>the parsed picture as a list of lines</returns>
+        private List<Line> ParseISADBody(String[] allLines, int width, int height)
+        {
+
+            String lineStartString = "line";
+            String lineEndString = "endline";
+
+            List<Line> drawing = new List<Line>();
+
+            //number of the line currently being parsed, enumeration starting at 0, body starts at the third line, therefore lin number 2
+            int i = 2;
+            //parse 'line' token and complete line definition
+            int lineStartPointer = i;
+            //holds the line number of the next expected beginning of a line definition, or of the enddrawing token
+            while (lineStartString.Equals(allLines[i]))
+            {
+                //start parsing next line
+                i++;
+                List<Point> newLine = new List<Point>();
+                while (!lineEndString.Equals(allLines[i]))
+                {
+                    if (i == allLines.Length)
+                    {
+                        throw new FileImporterException("unterminated line definition", null, (i + 1));
+                    }
+                    //parse single point definition
+                    if (!Regex.Match(allLines[i], @"^\d+;\d+$", RegexOptions.None).Success)
+                    {
+                        throw new FileImporterException("invalid Point definition: wrong format", "format: [xCoordinate];[yCoordinate]", (i + 1) );
+                    }
+                    String[] coordinates = allLines[i].Split(';');
+                    //no errors possible, convertability to int already checked above
+                    int xCoordinate = Convert.ToInt32(coordinates[0]);
+                    int yCoordinate = Convert.ToInt32(coordinates[1]);
+                    if (xCoordinate < 0 || yCoordinate < 0 || xCoordinate > width - 1 || yCoordinate > height - 1)
+                    {
+                        throw new FileImporterException("invalid Point definition: point out of bounds", null, (i + 1) );
+                    }
+                    newLine.Add(new Point(xCoordinate, yCoordinate));
+                    //start parsing next line
+                    i++;
+                }
+                //"parse" 'endline' token, syntax already checked at the beginning,  and start parsing next line
+                i++;
+                //add line to drawing
+                drawing.Add(new Line(newLine));
+                //update lineStartPointer to the presumable start of the next line
+                lineStartPointer = i;
+            }
+            //check if end of body is reached after there are no more line definitions
+            if(i != allLines.Length - 1)
+            {
+                throw new FileImporterException("missing or invalid line definition token", "line definitions start with the 'line' token", (i + 1));
+            }
+            //return parsed picture
+            return drawing;
+        }
+
+        /// <summary>
+        /// connection point for testing use only: calls ParseISADInput(String[] allLines) and directly passes the given argument (effectively bypassing the File Input functionality)
+        /// </summary>
+        /// <param name="allLines">an array holding all lines of the input file</param>
+        /// <returns>the width and height of the left canvas and the parsed picture as a list of lines</returns>
+        public (int, int, List<Line>) ParseISADInputForTesting(String[] allLines)
+        {
+            return ParseISADInput(allLines);
+        }
+
+    }
+}

+ 26 - 0
SketchAssistant/SketchAssistant/FileImporterException.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SketchAssistant
+{
+    public class FileImporterException : Exception
+    {
+        /// <summary>
+        /// the clean and formatted message to show to the user
+        /// </summary>
+        String showMessage;
+
+        public FileImporterException(String message, String hint, int lineNumber) : base (message)
+        {
+            showMessage = "Could not import file:\n\n" + message + (hint == null ? "" : "\n(Hint: " + hint + ")") + (lineNumber == -1 ? "" : "\n\n-line: " + lineNumber );
+        }
+
+        public override string ToString()
+        {
+            return showMessage;
+        }
+    }
+}

+ 22 - 2
SketchAssistant/SketchAssistant/Form1.Designer.cs

@@ -37,6 +37,8 @@ namespace SketchAssistant
             this.menuStrip1 = new System.Windows.Forms.MenuStrip();
             this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
             this.loadToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+            this.importToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+            this.examplePictureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
             this.toolStrip1 = new System.Windows.Forms.ToolStrip();
             this.canvasButton = new System.Windows.Forms.ToolStripButton();
             this.drawButton = new System.Windows.Forms.ToolStripButton();
@@ -115,7 +117,8 @@ namespace SketchAssistant
             // fileToolStripMenuItem
             // 
             this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.loadToolStripMenuItem});
+            this.loadToolStripMenuItem,
+            this.importToolStripMenuItem});
             this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
             this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
             this.fileToolStripMenuItem.Text = "File";
@@ -123,10 +126,25 @@ namespace SketchAssistant
             // loadToolStripMenuItem
             // 
             this.loadToolStripMenuItem.Name = "loadToolStripMenuItem";
-            this.loadToolStripMenuItem.Size = new System.Drawing.Size(109, 22);
+            this.loadToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
             this.loadToolStripMenuItem.Text = "Load...";
             this.loadToolStripMenuItem.Click += new System.EventHandler(this.loadToolStripMenuItem_Click);
             // 
+            // importToolStripMenuItem
+            // 
+            this.importToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+            this.examplePictureToolStripMenuItem});
+            this.importToolStripMenuItem.Name = "importToolStripMenuItem";
+            this.importToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
+            this.importToolStripMenuItem.Text = "Import...";
+            // 
+            // examplePictureToolStripMenuItem
+            // 
+            this.examplePictureToolStripMenuItem.Name = "examplePictureToolStripMenuItem";
+            this.examplePictureToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
+            this.examplePictureToolStripMenuItem.Text = "Example picture";
+            this.examplePictureToolStripMenuItem.Click += new System.EventHandler(this.examplePictureToolStripMenuItem_Click);
+            // 
             // toolStrip1
             // 
             this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
@@ -271,6 +289,8 @@ namespace SketchAssistant
         private System.Windows.Forms.ToolStripButton canvasButton;
         private System.Windows.Forms.ToolStripButton drawButton;
         private System.Windows.Forms.ToolStripButton deleteButton;
+        private System.Windows.Forms.ToolStripMenuItem importToolStripMenuItem;
+        private System.Windows.Forms.ToolStripMenuItem examplePictureToolStripMenuItem;
         private System.Windows.Forms.ToolStripStatusLabel lastActionTakenLabel;
         private System.Windows.Forms.ToolStripButton undoButton;
         private System.Windows.Forms.ToolStripButton redoButton;

+ 175 - 42
SketchAssistant/SketchAssistant/Form1.cs

@@ -7,6 +7,7 @@ using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using System.Windows.Forms;
+using System.Text.RegularExpressions;
 
 
 // This is the code for your desktop app.
@@ -19,47 +20,88 @@ namespace SketchAssistant
         public Form1()
         {
             InitializeComponent();
+            fileImporter = new FileImporter(this);
         }
 
         /**********************************/
         /*** CLASS VARIABLES START HERE ***/
         /**********************************/
 
-        //Different Program States
+        //important: add new variables only at the end of the list to keep the order of definition consistent with the order in which they are returned by GetAllVariables()
+
+        /// <summary>
+        /// Different Program States
+        /// </summary>
         public enum ProgramState
         {
             Idle,
             Draw,
             Delete
         }
-        //Current Program State
+        /// <summary>
+        /// Current Program State
+        /// </summary>
         private ProgramState currentState;
-        //Dialog to select a file.
-        OpenFileDialog openFileDialogLeft = new OpenFileDialog();
-        //Image loaded on the left
-        Image leftImage = null;
-        //Image on the right
+        /// <summary>
+        /// instance of FileImporter to handle drawing imports
+        /// </summary>
+        private FileImporter fileImporter;
+        /// <summary>
+        /// Dialog to select a file.
+        /// </summary>
+        OpenFileDialog openFileDialog = new OpenFileDialog();
+        /// <summary>
+        /// Image loaded on the left
+        /// </summary>
+        private Image leftImage = null;
+        /// <summary>
+        /// the graphic shown in the left window, represented as a list of polylines
+        /// </summary>
+        private List<Line> leftLineList;
+        /// <summary>
+        /// Image on the right
+        /// </summary>
         Image rightImage = null;
-        //Current Line being Drawn
+        /// <summary>
+        /// Current Line being Drawn
+        /// </summary>
         List<Point> currentLine;
-        //All Lines in the current session
-        List<Tuple<bool,Line>> lineList = new List<Tuple<bool, Line>>();
-        //Whether the Mouse is currently pressed in the rightPictureBox
+        /// <summary>
+        /// All Lines in the current session
+        /// </summary>
+        List<Tuple<bool,Line>> rightLineList = new List<Tuple<bool, Line>>();
+        /// <summary>
+        /// Whether the Mouse is currently pressed in the rightPictureBox
+        /// </summary>
         bool mousePressed = false;
-        //The Position of the Cursor in the right picture box
+        /// <summary>
+        /// The Position of the Cursor in the right picture box
+        /// </summary>
         Point currentCursorPosition;
-        //The Previous Cursor Position in the right picture box
+        /// <summary>
+        /// The Previous Cursor Position in the right picture box
+        /// </summary>
         Point previousCursorPosition;
-        //Queue for the cursorPositions
+        /// <summary>
+        /// Queue for the cursorPositions
+        /// </summary>
         Queue<Point> cursorPositions = new Queue<Point>();
-        //The graphic representation of the right image
-        Graphics graph = null;
-        //Deletion Matrixes for checking postions of lines in the image
+        /// <summary>
+        /// The graphic representation of the right image
+        /// </summary>
+        Graphics rightGraph = null;
+        /// <summary>
+        /// Deletion Matrixes for checking postions of lines in the image
+        /// </summary>
         bool[,] isFilledMatrix;
         HashSet<int>[,] linesMatrix;
-        //Size of deletion area
+        /// <summary>
+        /// Size of deletion area
+        /// </summary>
         uint deletionSize = 2;
-        //History of Actions
+        /// <summary>
+        /// History of Actions
+        /// </summary>
         ActionHistory historyOfActions;
 
         /******************************************/
@@ -83,11 +125,11 @@ namespace SketchAssistant
         //Load button, will open an OpenFileDialog
         private void loadToolStripMenuItem_Click(object sender, EventArgs e)
         {
-            openFileDialogLeft.Filter = "Image|*.jpg;*.png;*.jpeg";
-            if(openFileDialogLeft.ShowDialog() == DialogResult.OK)
+            openFileDialog.Filter = "Image|*.jpg;*.png;*.jpeg";
+            if(openFileDialog.ShowDialog() == DialogResult.OK)
             {
-                toolStripLoadStatus.Text = openFileDialogLeft.SafeFileName;
-                leftImage = Image.FromFile(openFileDialogLeft.FileName);
+                toolStripLoadStatus.Text = openFileDialog.SafeFileName;
+                leftImage = Image.FromFile(openFileDialog.FileName);
                 pictureBoxLeft.Image = leftImage;
                 //Refresh the left image box when the content is changed
                 this.Refresh();
@@ -95,6 +137,29 @@ namespace SketchAssistant
             UpdateButtonStatus();
         }
 
+        /// <summary>
+        /// Import button, will open an OpenFileDialog
+        /// </summary>
+        private void examplePictureToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            openFileDialog.Filter = "Interactive Sketch-Assistant Drawing|*.isad";
+            if (openFileDialog.ShowDialog() == DialogResult.OK)
+            {
+                toolStripLoadStatus.Text = openFileDialog.SafeFileName;
+                try
+                {
+                    (int, int, List<Line>) values = fileImporter.ParseISADInputFile(openFileDialog.FileName);
+                    DrawEmptyCanvasLeft(values.Item1, values.Item2);
+                    BindAndDrawLeftImage(values.Item3);
+                    this.Refresh();
+                }
+                catch(FileImporterException ex)
+                {
+                    ShowInfoMessage(ex.ToString());
+                }
+            }
+        }
+
         //Changes the state of the program to drawing
         private void drawButton_Click(object sender, EventArgs e)
         {
@@ -214,8 +279,8 @@ namespace SketchAssistant
             mousePressed = false;
             if (currentState.Equals(ProgramState.Draw) && currentLine.Count > 0)
             {
-                Line newLine = new Line(currentLine, lineList.Count);
-                lineList.Add(new Tuple<bool, Line>(true, newLine));
+                Line newLine = new Line(currentLine, rightLineList.Count);
+                rightLineList.Add(new Tuple<bool, Line>(true, newLine));
                 newLine.PopulateMatrixes(isFilledMatrix, linesMatrix);
                 historyOfActions.AddNewAction(new SketchAction(SketchAction.ActionType.Draw, newLine.GetID()));
             }
@@ -233,21 +298,21 @@ namespace SketchAssistant
                     "Attention", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK)
                 {
                     historyOfActions = new ActionHistory(lastActionTakenLabel);
-                    DrawEmptyCanvas();
+                    DrawEmptyCanvasRight();
                     //The following lines cannot be in DrawEmptyCanvas()
                     isFilledMatrix = new bool[rightImage.Width, rightImage.Height];
                     linesMatrix = new HashSet<int>[rightImage.Width, rightImage.Height];
-                    lineList = new List<Tuple<bool, Line>>();
+                    rightLineList = new List<Tuple<bool, Line>>();
                 }
             }
             else
             {
                 historyOfActions = new ActionHistory(lastActionTakenLabel);
-                DrawEmptyCanvas();
+                DrawEmptyCanvasRight();
                 //The following lines cannot be in DrawEmptyCanvas()
                 isFilledMatrix = new bool[rightImage.Width, rightImage.Height];
                 linesMatrix = new HashSet<int>[rightImage.Width, rightImage.Height];
-                lineList = new List<Tuple<bool, Line>>();
+                rightLineList = new List<Tuple<bool, Line>>();
             }
             UpdateButtonStatus();
         }
@@ -261,7 +326,7 @@ namespace SketchAssistant
             {
                 currentLine.Add(currentCursorPosition);
                 Line drawline = new Line(currentLine);
-                drawline.DrawLine(graph);
+                drawline.DrawLine(rightGraph);
                 pictureBoxRight.Image = rightImage;
             }
             if (currentState.Equals(ProgramState.Delete) && mousePressed)
@@ -275,7 +340,7 @@ namespace SketchAssistant
                         historyOfActions.AddNewAction(new SketchAction(SketchAction.ActionType.Delete, linesToDelete));
                         foreach (int lineID in linesToDelete)
                         {
-                            lineList[lineID] = new Tuple<bool, Line>(false, lineList[lineID].Item2);
+                            rightLineList[lineID] = new Tuple<bool, Line>(false, rightLineList[lineID].Item2);
                         }
                         RepopulateDeletionMatrixes();
                         RedrawRightImage();
@@ -291,37 +356,59 @@ namespace SketchAssistant
         /// <summary>
         /// Creates an empty Canvas
         /// </summary>
-        private void DrawEmptyCanvas()
+        private void DrawEmptyCanvasRight()
         {
             if (leftImage == null)
             {
                 rightImage = new Bitmap(pictureBoxRight.Width, pictureBoxRight.Height);
-                graph = Graphics.FromImage(rightImage);
-                graph.FillRectangle(Brushes.White, 0, 0, pictureBoxRight.Width + 10, pictureBoxRight.Height + 10);
+                rightGraph = Graphics.FromImage(rightImage);
+                rightGraph.FillRectangle(Brushes.White, 0, 0, pictureBoxRight.Width + 10, pictureBoxRight.Height + 10);
                 pictureBoxRight.Image = rightImage;
             }
             else
             {
                 rightImage = new Bitmap(leftImage.Width, leftImage.Height);
-                graph = Graphics.FromImage(rightImage);
-                graph.FillRectangle(Brushes.White, 0, 0, leftImage.Width + 10, leftImage.Height + 10);
+                rightGraph = Graphics.FromImage(rightImage);
+                rightGraph.FillRectangle(Brushes.White, 0, 0, leftImage.Width + 10, leftImage.Height + 10);
                 pictureBoxRight.Image = rightImage;
             }
             this.Refresh();
             pictureBoxRight.Refresh();
         }
 
+        /// <summary>
+        /// Creates an empty Canvas on the left
+        /// </summary>
+        /// <param name="width"> width of the new canvas in pixels </param>
+        /// <param name="height"> height of the new canvas in pixels </param>
+        private void DrawEmptyCanvasLeft(int width, int height)
+        {
+            if (width == 0)
+            {
+                leftImage = new Bitmap(pictureBoxLeft.Width, pictureBoxLeft.Height);
+            }
+            else
+            {
+                leftImage = new Bitmap(width, height);
+            }
+            Graphics.FromImage(leftImage).FillRectangle(Brushes.White, 0, 0, pictureBoxLeft.Width + 10, pictureBoxLeft.Height + 10);
+            pictureBoxLeft.Image = leftImage;
+            
+            this.Refresh();
+            pictureBoxLeft.Refresh();
+        }
+
         /// <summary>
         /// Redraws all lines in lineList, for which their associated boolean value equals true.
         /// </summary>
         private void RedrawRightImage()
         {
-            DrawEmptyCanvas();
-            foreach (Tuple<bool, Line> lineBoolTuple in lineList)
+            DrawEmptyCanvasRight();
+            foreach (Tuple<bool, Line> lineBoolTuple in rightLineList)
             {
                 if (lineBoolTuple.Item1)
                 {
-                    lineBoolTuple.Item2.DrawLine(graph);
+                    lineBoolTuple.Item2.DrawLine(rightGraph);
                 }
             }
             pictureBoxRight.Refresh();
@@ -336,9 +423,9 @@ namespace SketchAssistant
         {
             foreach (int lineId in lines)
             {
-                if (lineId <= lineList.Count - 1 && lineId >= 0)
+                if (lineId <= rightLineList.Count - 1 && lineId >= 0)
                 {
-                    lineList[lineId] = new Tuple<bool, Line>(shown, lineList[lineId].Item2);
+                    rightLineList[lineId] = new Tuple<bool, Line>(shown, rightLineList[lineId].Item2);
                 }
             }
             RedrawRightImage();
@@ -443,7 +530,7 @@ namespace SketchAssistant
             {
                 isFilledMatrix = new bool[rightImage.Width,rightImage.Height];
                 linesMatrix = new HashSet<int>[rightImage.Width, rightImage.Height];
-                foreach(Tuple<bool,Line> lineTuple in lineList)
+                foreach(Tuple<bool,Line> lineTuple in rightLineList)
                 {
                     if (lineTuple.Item1)
                     {
@@ -486,5 +573,51 @@ namespace SketchAssistant
             }
             return returnSet;
         }
+
+        /// <summary>
+        /// binds the given picture to templatePicture and draws it
+        /// </summary>
+        /// <param name="newTemplatePicture"> the new template picture, represented as a list of polylines </param>
+        /// <returns></returns>
+        private void BindAndDrawLeftImage(List<Line> newTemplatePicture)
+        {
+            leftLineList = newTemplatePicture;
+            foreach(Line l in leftLineList)
+            {
+                l.DrawLine(Graphics.FromImage(leftImage));
+            }
+        }
+
+        /// <summary>
+        /// shows the given info message in a popup and asks the user to aknowledge it
+        /// </summary>
+        /// <param name="message">the message to show</param>
+        private void ShowInfoMessage(String message)
+        {
+            MessageBox.Show(message);
+        }
+
+        /// <summary>
+        /// returns all instance variables in the order of their definition for testing
+        /// </summary>
+        /// <returns>all instance variables in the order of their definition</returns>
+        public Object[]/*(ProgramState, FileImporter, OpenFileDialog, Image, List<Line>, Image, List<Point>, List<Tuple<bool, Line>>, bool, Point, Point, Queue<Point>, Graphics, bool[,], HashSet<int>[,], uint, ActionHistory)*/ GetAllVariables()
+        {
+            return new Object[] { currentState, fileImporter, openFileDialog, leftImage, leftLineList, rightImage, currentLine, rightLineList, mousePressed, currentCursorPosition, previousCursorPosition, cursorPositions, rightGraph, isFilledMatrix, linesMatrix, deletionSize, historyOfActions };
+        }
+
+        /// <summary>
+        /// public method wrapper for testing purposes, invoking DrawEmptyCanvas(...) and BindAndDrawLeftImage(...)
+        /// </summary>
+        /// <param name="width">width of the parsed image</param>
+        /// <param name="height">height of the parsed image</param>
+        /// <param name="newImage">the parsed image</param>
+        public void CreateCanvasAndSetPictureForTesting(int width, int height, List<Line> newImage)
+        {
+            DrawEmptyCanvasLeft(width, height);
+            BindAndDrawLeftImage(newImage);
+        }
+
+
     }
 }

+ 9 - 0
SketchAssistant/SketchAssistant/Line.cs

@@ -9,8 +9,17 @@ namespace SketchAssistant
 {
     public class Line
     {
+        /// <summary>
+        /// list saving all the points of the line in the order of the path from start to end point
+        /// </summary>
         private List<Point> linePoints;
+        /// <summary>
+        /// unique identifier of this Line object
+        /// </summary>
         private int identifier;
+        /// <summary>
+        /// flag showing if this is only a temporary line
+        /// </summary>
         private bool isTemporary;
 
         /// <summary>

+ 2 - 0
SketchAssistant/SketchAssistant/SketchAssistant.csproj

@@ -69,6 +69,8 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="FileImporter.cs" />
+    <Compile Include="FileImporterException.cs" />
     <Compile Include="SketchAction.cs" />
     <Compile Include="ActionHistory.cs" />
     <Compile Include="Line.cs" />