using System; using System.Drawing; using System.Drawing.Drawing2D; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Windows.Forms; using Newtonsoft.Json; namespace UseCases { public partial class FrmMain : Form { [DllImport("kernel32")] static extern bool AllocConsole(); enum AddAction { Nothing, Actor, UseCase } public FrmMain() { //get the command line arguments var args = Environment.GetCommandLineArgs(); InitializeComponent(); //check if there are multiple arguments if (args.Count() > 1) { //check if first arguments is a file if (File.Exists(args[1])) { //try to open the file OpenFile(args[1]); } else { Diagram = new Diagram(); //initialise default values } } else { //initialise default values Diagram = new Diagram(); } } #region variables //actors and usecases public Diagram Diagram { get; private set; } //drawing variables private readonly Font _myFont = new Font("Sans Sherif", 20f, FontStyle.Regular); private readonly Pen _drawingPen = new Pen(Color.Black, 3f); //adding elements private AddAction _toAdd = AddAction.Nothing; private IDrawable _dragged = null; //edit tracker private bool _hasEdited = false; #endregion #region menustrip private void exitToolStripMenuItem_Click(object sender, EventArgs e) { Close(); } private void btAddActor_Click(object sender, EventArgs e) { _toAdd = AddAction.Actor; } private void btAddUseCase_Click(object sender, EventArgs e) { _toAdd = AddAction.UseCase; } //save in json format private void btSave_Click(object sender, EventArgs e) { //show save file dialog and quit if canceled var saveDiag = new SaveFileDialog {Filter = @"*.ucd|*.ucd"}; if (saveDiag.ShowDialog() != DialogResult.OK) return; _hasEdited = false; Diagram.Size = Size; Diagram.Maximized = WindowState == FormWindowState.Maximized; //save to file var serialized = JsonConvert.SerializeObject(Diagram, Utils.SerializerSettings); File.WriteAllText(saveDiag.FileName, serialized); } //save png format private void btSaveImage_Click(object sender, EventArgs e) { //show save file dialog and quit if canceled var saveDiag = new SaveFileDialog {Filter = @"*.png|*.png"}; if (saveDiag.ShowDialog() != DialogResult.OK) return; //create bitmap and draw usecases and actors to it var bmp = new Bitmap(Size.Width, Size.Height); var g = Graphics.FromImage(bmp); DrawElements(g); //save image to file bmp.Save(saveDiag.FileName); } //open json format private void btOpen_Click(object sender, EventArgs e) { //check if anything has been edited if (_hasEdited) { if ( MessageBox.Show(@"Are you sure you want to load a new file?", @"Load new file", MessageBoxButtons.YesNo) == DialogResult.No) return; } //show open file dialog and quit if canceled var openDiag = new OpenFileDialog {Filter = @"*.ucd|*ucd"}; if (openDiag.ShowDialog() != DialogResult.OK) return; //open the file OpenFile(openDiag.FileName); Refresh(); } private void clearToolStripMenuItem_Click(object sender, EventArgs e) { //check if user realy wants to clear the diagram else return if (MessageBox.Show(@"Are you sure you want to clear the diagram?", @"Clear", MessageBoxButtons.YesNo) != DialogResult.Yes) return; //clear lists and refresh screen Diagram = new Diagram(new Size(430, 372)); // _actors.Clear(); // _useCases.Clear(); WindowState = FormWindowState.Normal; Size = Diagram.Size; Refresh(); } private void controlsToolStripMenuItem_Click(object sender, EventArgs e) { MessageBox.Show(@"Pres Ctrl+A or click Add>Actor to add an Actor Press Ctrl+U or click File>Use Case to add a Use Case Click somwhere on screen to add Use Case or Actor at that position Leave name empty to remove Click and drag to move usecase or actor Press Ctrl+S or click File>Save to save the diagram Press Ctrl+Shift+S or click File>Save as image to save diagram as image Click File>Clear to clear the diagram Press Alt+F4 or click the cross or click File>Exit to close the form Click Help>Controls to view this message Click Help>About to view information about the application", @"Controls"); } private void aboutToolStripMenuItem_Click(object sender, EventArgs e) { MessageBox.Show(@"Use Case Designer by Rick Rongen Version 1.0 Developed by order of Fontys Hogerescholen ICT Eindhoven", @"About"); } #endregion #region functions /// /// Opens an file into form and shows error if it could not be loaded /// /// full path of ile to load private void OpenFile(string filename) { //try to open file try { Diagram = JsonConvert.DeserializeObject(File.ReadAllText(filename), Utils.SerializerSettings); WindowState = Diagram.Maximized ? FormWindowState.Maximized : FormWindowState.Normal; Size = Diagram.Size; Refresh(); } catch (JsonException jex) { //show the console with the error if the user wan't to see it if ( MessageBox.Show( $@"Error while loading {filename}\n Invallid format or broken data\nGeeks may check console for the exception, pres yes to show console", @"Error occured, show console?", MessageBoxButtons.YesNo) == DialogResult.Yes) AllocConsole(); Console.WriteLine(jex.ToString()); } catch (IOException ioex) { //show the console with the error if the user wan't to see it if ( MessageBox.Show( $@"Error while loading {filename}\nCouldn't open the file or there was an encoding issue.", @"Error occured, show console?", MessageBoxButtons.YesNo) == DialogResult.Yes) AllocConsole(); Console.WriteLine(ioex.ToString()); } finally { _hasEdited = false; } } /// /// Draws all ellements in actors and useCases to the graphics object /// /// graphics object private void DrawElements(Graphics g) { g.SmoothingMode = SmoothingMode.AntiAlias; foreach (var drawable in Diagram.Drawable) { drawable.Draw(g, _myFont, _drawingPen); } } #endregion #region mouse //handle creation of components private void frmMain_Click(object sender, EventArgs e) { var pos = PointToClient(MousePosition); switch (_toAdd) { case AddAction.Actor: //create new actor var adiag = new EditActor(); if (adiag.ShowDialog() == DialogResult.OK && adiag.ActorName != "") { Diagram.Actors.Add(new Actor(adiag.ActorName, pos)); } Refresh(); break; case AddAction.UseCase: //create new useCase var udiag = new editUseCase(Diagram.Actors) {UseCase = new UseCase(), CasePos = pos}; if (udiag.ShowDialog() == DialogResult.OK && udiag.UseCase.Name != "") { Diagram.UseCases.Add(udiag.UseCase); udiag.UseCase.Actors.ForEach(Console.WriteLine); } Refresh(); break; default: case AddAction.Nothing: break; } _toAdd = AddAction.Nothing; if (Diagram.UseCases.Any() || Diagram.Actors.Any()) _hasEdited = true; } //handle editing of components private void frmMain_DoubleClick(object sender, EventArgs e) { var mousepos = PointToClient(MousePosition); var closest = GetClosestDrawable(mousepos); switch (closest) { case null: return; case Actor actor: var edAcDiag = new EditActor(actor.Name); if (edAcDiag.ShowDialog() == DialogResult.OK) { if (edAcDiag.ActorName == "") { //remove actor if name is equal to "" Diagram.Actors.Remove(actor); foreach (var usecase in Diagram.UseCases) { //remove this actor from all refering usecases usecase.Actors.Remove(actor); } } else { //update name actor.Name = edAcDiag.ActorName; } } break; case UseCase useCase: var edUcDiag = new editUseCase(Diagram.Actors) { UseCase = useCase, CasePos = useCase.Position }; if (edUcDiag.ShowDialog() == DialogResult.OK) { if (edUcDiag.UseCase.Name == "") { //remove usecase if name is equal to "" Diagram.UseCases.Remove(useCase); } } break; } Refresh(); } //move usecase or actor private void frmMain_MouseUp(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left && _toAdd == AddAction.Nothing) { _dragged = null; } } private void frmMain_MouseDown(object sender, MouseEventArgs e) { //quit if not left mousebutton or adding item if (e.Button != MouseButtons.Left || _toAdd != AddAction.Nothing) return; //get mouse position in client var mousepos = PointToClient(MousePosition); var closest = GetClosestDrawable(mousepos); if (closest == null) return; _dragged = closest; } private void frmMain_MouseMove(object sender, MouseEventArgs e) { if (_dragged == null) return; _dragged.Position = PointToClient(MousePosition); Refresh(); } private IDrawable GetClosestDrawable(Point position, double maxDistance = 30d) { if (!Diagram.UseCases.Any() && !Diagram.Actors.Any()) return null; // No items to check var comm = Diagram.Drawable.Select(org => new { original = org, distance = Math.Sqrt(Math.Pow(org.Position.X - position.X, 2) + Math.Pow(org.Position.Y - position.Y, 2)) }).Aggregate((a1, a2) => a1.distance < a2.distance ? a1 : a2); return comm.distance > maxDistance ? null : comm.original; } #endregion private void frmMain_Paint(object sender, PaintEventArgs e) { //draw actors, use cases and lines DrawElements(e.Graphics); } private void FrmMain_FormClosing(object sender, FormClosingEventArgs e) { if (!_hasEdited) return; if (MessageBox.Show(@"Are you sure you want to exit?", @"exit", MessageBoxButtons.YesNo) != DialogResult.Yes) e.Cancel = true; } } }