home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / i / iv26_w_3.zip / EXAMPLES / IDRAW / EDITOR2.C < prev    next >
C/C++ Source or Header  |  1991-12-30  |  36KB  |  1,374 lines

  1. /*
  2.  * Copyright (c) 1987, 1988, 1989 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software and its
  5.  * documentation for any purpose is hereby granted without fee, provided
  6.  * that the above copyright notice appear in all copies and that both that
  7.  * copyright notice and this permission notice appear in supporting
  8.  * documentation, and that the name of Stanford not be used in advertising or
  9.  * publicity pertaining to distribution of the software without specific,
  10.  * written prior permission.  Stanford makes no representations about
  11.  * the suitability of this software for any purpose.  It is provided "as is"
  12.  * without express or implied warranty.
  13.  *
  14.  * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  19.  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  20.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  21.  */
  22.  
  23. /* $Header: editor.c,v 1.24 90/02/05 16:16:53 linton Exp $ */
  24.  
  25. /*
  26.  * implements class Editor.
  27.  */
  28.  
  29. #include "dialogbox.h"
  30. #include "drawing.h"
  31. #include "drawingview.h"
  32. #include "editor.h"
  33. #include "history.h"
  34. #include "idraw.h"
  35. #include "listchange.h"
  36. #include "listselectn.h"
  37. #include "rubbands.h"
  38. #include "slellipses.h"
  39. #include "sllines.h"
  40. #include "slpolygons.h"
  41. #include "slsplines.h"
  42. #include "sltext.h"
  43. #include "state.h"
  44. #include "textedit.h"
  45. #include "version.h"
  46. #include <InterViews/event.h>
  47. #include <InterViews/transformer.h>
  48. #include <InterViews/Graphic/util.h>
  49. #include <stdio.h>
  50.  
  51. /*
  52.  * Editor creates its history and dialog boxes.
  53.  */
  54.  
  55. Editor::Editor (Interactor* i) {
  56.     history = new History(i);
  57.     numberofdialog = new Messager(i);
  58.     opendialog = new Finder(i, "Enter name of drawing to open:");
  59.     overwritedialog= new Confirmer(i, "already exists; overwrite?");
  60.     precmovedialog = new NamerNUnit(i,"Enter X and Y movement:",
  61.                    "points", "pixels");
  62.     precrotdialog = new Namer(i, "Enter rotation in degrees:");
  63.     precscaledialog = new Namer(i, "Enter X and Y scaling:");
  64.     printdialog = new Namer(i, "Enter print command:");
  65.     readonlydialog = new Messager(i, "Drawing is readonly.");
  66.     revertdialog = new Confirmer(i, "Really revert to original?");
  67.     saveasdialog = new Finder(i, "Enter a name for this drawing:");
  68.     savecurdialog = new Confirmer(i, "Save current drawing?");
  69.     spacingdialog = new NamerNUnit(i, "Enter grid spacing:",
  70.                    "points", "pixels");
  71.     versiondialog = new Messager(i, version);
  72.  
  73.     drawing = nil;
  74.     drawingview = nil;
  75.     state = nil;
  76. }
  77.  
  78. /*
  79.  * ~Editor frees storage allocated for its history and dialog boxes.
  80.  */
  81.  
  82. Editor::~Editor () {
  83.     delete history;
  84.     delete numberofdialog;
  85.     delete opendialog;
  86.     delete overwritedialog;
  87.     delete precmovedialog;
  88.     delete precrotdialog;
  89.     delete precscaledialog;
  90.     delete printdialog;
  91.     delete readonlydialog;
  92.     delete revertdialog;
  93.     delete saveasdialog;
  94.     delete savecurdialog;
  95.     delete spacingdialog;
  96.     delete versiondialog;
  97. }
  98.  
  99. /*
  100.  * Define access functions to set members' values.  Only Idraw sets
  101.  * their values.
  102.  */
  103.  
  104. void Editor::SetDrawing (Drawing* d) {
  105.     drawing = d;
  106. }
  107.  
  108. void Editor::SetDrawingView (DrawingView* dv) {
  109.     drawingview = dv;
  110. }
  111.  
  112. void Editor::SetState (State* s) {
  113.     state = s;
  114. }
  115.  
  116. /*
  117.  * HandleSelect lets the user pick a Selection if one's under the
  118.  * mouse, otherwise it lets the user manipulate a rubber rectangle to
  119.  * enclose the Selection he wants to pick.  HandleSelect clears all
  120.  * previous Selections unless the user holds down the shift key to
  121.  * extend the Selections being made.
  122.  */
  123.  
  124. void Editor::HandleSelect (Event& e) {
  125.     Selection* pick = drawing->PickSelectionIntersecting(e.x, e.y);
  126.     if (!e.shift) {        /* replacing previous Selections */
  127.     drawingview->EraseHandles();
  128.     if (pick != nil) {
  129.         drawing->Select(pick);
  130.     } else {
  131.         RubberRect* rubberrect =
  132.         new RubberRect(nil, nil, e.x, e.y, e.x, e.y);
  133.         drawingview->Manipulate(e, rubberrect, UpEvent, false);
  134.         Coord l, b, r, t;
  135.         rubberrect->GetCurrent(l, b, r, t);
  136.         delete rubberrect;
  137.  
  138.         SelectionList* picklist= drawing->PickSelectionsWithin(l, b, r, t);
  139.         drawing->Select(picklist);
  140.         delete picklist;
  141.     }
  142.     } else {            /* extending Selections */
  143.     if (pick != nil) {
  144.         drawingview->ErasePickedHandles(pick);
  145.         drawing->Extend(pick);
  146.     } else {
  147.         RubberRect* rubberrect =
  148.         new RubberRect(nil, nil, e.x, e.y, e.x, e.y);
  149.         drawingview->Manipulate(e, rubberrect, UpEvent, false);
  150.         Coord l, b, r, t;
  151.         rubberrect->GetCurrent(l, b, r, t);
  152.         delete rubberrect;
  153.  
  154.         SelectionList* picklist= drawing->PickSelectionsWithin(l, b, r, t);
  155.         drawingview->ErasePickedHandles(picklist);
  156.         drawing->Extend(picklist);
  157.         delete picklist;
  158.     }
  159.     }
  160.     drawingview->DrawHandles();
  161. }
  162.  
  163. /*
  164.  * HandleMove lets the user manipulate a sliding rectangle enclosing
  165.  * the Selections and moves them the same way when the user releases
  166.  * the button.
  167.  */
  168.  
  169. void Editor::HandleMove (Event& e) {
  170.     Selection* pick = drawing->PickSelectionIntersecting(e.x, e.y);
  171.     if (pick != nil) {
  172.     drawingview->EraseUngraspedHandles(pick);
  173.     drawing->Grasp(pick);
  174.     drawingview->DrawHandles();
  175.  
  176.     Coord l, b, r, t;
  177.     drawing->GetBox(l, b, r, t);
  178.     state->Constrain(e.x, e.y);
  179.     SlidingRect* slidingrect =
  180.         new SlidingRect(nil, nil, l, b, r, t, e.x, e.y);
  181.     drawingview->Manipulate(e, slidingrect, UpEvent);
  182.     Coord nl, nb, nr, nt;
  183.     slidingrect->GetCurrent(nl, nb, nr, nt);
  184.     delete slidingrect;
  185.  
  186.     if (nl != l || nb != b) {
  187.         float x0, y0, x1, y1;
  188.         Transformer t;
  189.         drawing->GetPictureTT(t);
  190.         t.InvTransform(float(l), float(b), x0, y0);
  191.         t.InvTransform(float(nl), float(nb), x1, y1);
  192.         Do(new MoveChange(drawing, drawingview, x1 - x0, y1 - y0));
  193.     }
  194.     }
  195. }
  196.  
  197. /*
  198.  * HandleScale lets the user manipulate a scaling rectangle enclosing
  199.  * the picked Selection and scales the Selections to the new scale
  200.  * when the user releases the button.
  201.  */
  202.  
  203. void Editor::HandleScale (Event& e) {
  204.     Selection* pick = drawing->PickSelectionIntersecting(e.x, e.y);
  205.     if (pick != nil) {
  206.     drawingview->EraseUngraspedHandles(pick);
  207.     drawing->Grasp(pick);
  208.     drawingview->DrawHandles();
  209.  
  210.     float l, b, r, t;
  211.     pick->GetBounds(l, b, r, t);
  212.     float cx, cy;
  213.     pick->GetCenter(cx, cy);
  214.     ScalingRect* scalingrect =
  215.         new ScalingRect(nil, nil, round(l), round(b), round(r), round(t),
  216.                 round(cx), round(cy));
  217.     drawingview->Manipulate(e, scalingrect, UpEvent);
  218.     float scale = scalingrect->CurrentScaling();
  219.     delete scalingrect;
  220.  
  221.     if (scale != 0) {
  222.         Do(new ScaleChange(drawing, drawingview, scale, scale));
  223.     }
  224.     }
  225. }
  226.  
  227. /*
  228.  * HandleStretch lets the user manipulate a stretching rectangle
  229.  * enclosing the picked Selection and stretches the Selections the
  230.  * same way when the user releases the button.
  231.  */
  232.  
  233. void Editor::HandleStretch (Event& e) {
  234.     Selection* pick = drawing->PickSelectionIntersecting(e.x, e.y);
  235.     if (pick != nil) {
  236.     drawingview->EraseUngraspedHandles(pick);
  237.     drawing->Grasp(pick);
  238.     drawingview->DrawHandles();
  239.  
  240.     float l, b, r, t;
  241.     pick->GetBounds(l, b, r, t);
  242.     IStretchingRect* istretchingrect = new
  243.         IStretchingRect(nil, nil, round(l), round(b), round(r), round(t));
  244.     drawingview->Manipulate(e, istretchingrect, UpEvent);
  245.     float stretch = istretchingrect->CurrentStretching();
  246.     Alignment side = istretchingrect->CurrentSide(drawing->GetLandscape());
  247.     delete istretchingrect;
  248.  
  249.     if (stretch != 0) {
  250.         Do(new StretchChange(drawing, drawingview, stretch, side));
  251.     }
  252.     }
  253. }
  254.  
  255. /*
  256.  * HandleRotate lets the user manipulate a rotating rectangle
  257.  * enclosing the picked Selection and rotates the Selections the same
  258.  * way when the user releases the button.
  259.  */
  260.  
  261. void Editor::HandleRotate (Event& e) {
  262.     Selection* pick = drawing->PickSelectionIntersecting(e.x, e.y);
  263.     if (pick != nil) {
  264.     drawingview->EraseUngraspedHandles(pick);
  265.     drawing->Grasp(pick);
  266.     drawingview->DrawHandles();
  267.  
  268.     Coord l, b, r, t;
  269.     pick->GetBox(l, b, r, t);
  270.     float cx, cy;
  271.     pick->GetCenter(cx, cy);
  272.     state->Constrain(e.x, e.y);
  273.     RotatingRect* rotatingrect =
  274.         new RotatingRect(nil, nil, l, b, r, t, round(cx), round(cy),
  275.                  e.x, e.y);
  276.     drawingview->Manipulate(e, rotatingrect, UpEvent);
  277.     float angle = rotatingrect->CurrentAngle();
  278.     delete rotatingrect;
  279.  
  280.     if (angle != 0) {
  281.         Do(new RotateChange(drawing, drawingview, angle));
  282.     }
  283.     }
  284. }
  285.  
  286. /*
  287.  * HandleReshape lets the user reshape an already existing Selection
  288.  * and replaces the Selection with the reshaped Selection.  Text
  289.  * Selections "reshape" themselves using different code below.
  290.  */
  291.  
  292. void Editor::HandleReshape (Event& e) {
  293.     Selection* pick = drawing->PickSelectionShapedBy(e.x, e.y);
  294.     if (pick != nil) {
  295.     drawingview->EraseHandles();
  296.     drawing->Select(pick);
  297.     drawingview->DrawHandles();
  298.     Selection* reshapedpick = nil;
  299.     if (pick->IsA(TEXTSELECTION)) {
  300.         int len;
  301.         const char* text = ((TextSelection*) pick)->GetOriginal(len);
  302.         TextEdit* textedit = new TextEdit(text, len);
  303.         drawingview->EraseHandles();
  304.         drawingview->Edit(e, textedit, pick);
  305.         text = textedit->GetText(len);
  306.         reshapedpick = new TextSelection(text, len, pick);
  307.         delete textedit;
  308.     } else {
  309.         Rubberband* shape = pick->CreateShape(e.x, e.y);
  310.         drawingview->Manipulate(e, shape, UpEvent);
  311.         reshapedpick = pick->GetReshapedCopy();
  312.     }
  313.     if (reshapedpick != nil) {
  314.         Do(new ReplaceChange(drawing, drawingview, pick, reshapedpick));
  315.     }
  316.     }
  317. }
  318.  
  319. /*
  320.  * HandleMagnify lets the user manipulate a rubber rectangle and
  321.  * expands the given area to fill the view.
  322.  */
  323.  
  324. void Editor::HandleMagnify (Event& e) {
  325.     RubberRect* rubberrect = NewRubberRectOrSquare(e);
  326.     drawingview->Manipulate(e, rubberrect, UpEvent, false);
  327.     Coord fx, fy;
  328.     rubberrect->GetCurrent(fx, fy, e.x, e.y);
  329.     delete rubberrect;
  330.  
  331.     drawingview->Magnify(fx, fy, e.x, e.y);
  332. }
  333.  
  334. /*
  335.  * HandleText lets the user type some text and creates a new
  336.  * TextSelection when the user finishes typing the text.  It must
  337.  * clear the selection list because DrawingView will redraw the
  338.  * handles obscured by the TextEdit if the list's not empty.
  339.  */
  340.  
  341. void Editor::HandleText (Event& e) {
  342.     drawingview->EraseHandles();
  343.     drawing->Clear();
  344.     TextEdit* textedit = new TextEdit;
  345.     drawingview->Edit(e, textedit);
  346.     int len;
  347.     const char* text = textedit->GetText(len);
  348.     if (len > 0) {
  349.     drawing->Select(new TextSelection(text, len, state->GetTextGS()));
  350.     Do(new AddChange(drawing, drawingview));
  351.     }
  352.     delete textedit;
  353. }
  354.  
  355. /*
  356.  * HandleLine lets the user manipulate a rubber line and creates
  357.  * a LineSelection when the user releases the button.
  358.  */
  359.  
  360. void Editor::HandleLine (Event& e) {
  361.     drawingview->EraseHandles();
  362.     state->Constrain(e.x, e.y);
  363.     RubberLine* rubberline = NewRubberLineOrAxis(e);
  364.     drawingview->Manipulate(e, rubberline, UpEvent);
  365.     Coord x0, y0, x1, y1;
  366.     rubberline->GetCurrent(x0, y0, x1, y1);
  367.     delete rubberline;
  368.  
  369.     if (x0 != x1 || y0 != y1) {
  370.     drawing->Select(
  371.         new LineSelection(x0, y0, x1, y1, state->GetGraphicGS())
  372.     );
  373.     Do(new AddChange(drawing, drawingview));
  374.     }
  375. }
  376.  
  377. /*
  378.  * HandleMultiLine lets the user draw a series of connected lines and
  379.  * creates a MultiLineSelection when the user presses the middle
  380.  * button.
  381.  */
  382.  
  383. void Editor::HandleMultiLine (Event& e) {
  384.     Coord* x;
  385.     Coord* y;
  386.     int n;
  387.  
  388.     drawingview->EraseHandles();
  389.     InputVertices(e, x, y, n);
  390.  
  391.     if (n != 2 || x[0] != x[1] || y[0] != y[1]) {
  392.     drawing->Select(
  393.         new MultiLineSelection(x, y, n, state->GetGraphicGS())
  394.     );
  395.     Do(new AddChange(drawing, drawingview));
  396.     }
  397. }
  398.  
  399. /*
  400.  * HandleBSpline lets the user draw a series of connected lines and
  401.  * creates a BSplineSelection when the user presses the middle button.
  402.  */
  403.  
  404. void Editor::HandleBSpline (Event& e) {
  405.     Coord* x;
  406.     Coord* y;
  407.     int n;
  408.  
  409.     drawingview->EraseHandles();
  410.     InputVertices(e, x, y, n);
  411.  
  412.     if (n != 2 || x[0] != x[1] || y[0] != y[1]) {
  413.     drawing->Select(
  414.         new BSplineSelection(x, y, n, state->GetGraphicGS())
  415.     );
  416.     Do(new AddChange(drawing, drawingview));
  417.     }
  418. }
  419.  
  420. /*
  421.  * HandleEllipse lets the user manipulate a rubber ellipse and creates
  422.  * an EllipseSelection when the user releases the button.
  423.  */
  424.  
  425. void Editor::HandleEllipse (Event& e) {
  426.     drawingview->EraseHandles();
  427.     state->Constrain(e.x, e.y);
  428.     RubberEllipse* rubberellipse = NewRubberEllipseOrCircle(e);
  429.     drawingview->Manipulate(e, rubberellipse, UpEvent);
  430.     Coord cx, cy, rx, ry;
  431.     int xr, yr;
  432.     rubberellipse->GetCurrent(cx, cy, rx, ry);
  433.     rubberellipse->CurrentRadii(xr, yr);
  434.     delete rubberellipse;
  435.  
  436.     if (xr > 0 || yr > 0) {
  437.     drawing->Select(
  438.         new EllipseSelection(cx, cy, xr, yr, state->GetGraphicGS())
  439.             );
  440.     Do(new AddChange(drawing, drawingview));
  441.     }
  442. }
  443.  
  444. /*
  445.  * HandleRect lets the user manipulate a rubber rectangle and creates
  446.  * a RectSelection when the user releases the button.
  447.  */
  448.  
  449. void Editor::HandleRect (Event& e) {
  450.     drawingview->EraseHandles();
  451.     state->Constrain(e.x, e.y);
  452.     RubberRect* rubberrect = NewRubberRectOrSquare(e);
  453.     drawingview->Manipulate(e, rubberrect, UpEvent);
  454.     Coord l, b, r, t;
  455.     rubberrect->GetCurrent(l, b, r, t);
  456.     delete rubberrect;
  457.  
  458.     if (l != r || b != t) {
  459.     drawing->Select(new RectSelection(l, b, r, t, state->GetGraphicGS()));
  460.     Do(new AddChange(drawing, drawingview));
  461.     }
  462. }
  463.  
  464. /*
  465.  * HandlePolygon lets the user draw a series of connected lines and
  466.  * creates a PolygonSelection when the user presses the middle button.
  467.  */
  468.  
  469. void Editor::HandlePolygon (Event& e) {
  470.     Coord* x;
  471.     Coord* y;
  472.     int n;
  473.  
  474.     drawingview->EraseHandles();
  475.     InputVertices(e, x, y, n);
  476.  
  477.     if (n != 2 || x[0] != x[1] || y[0] != y[1]) {
  478.     drawing->Select(new PolygonSelection(x, y, n, state->GetGraphicGS()));
  479.     Do(new AddChange(drawing, drawingview));
  480.     }
  481. }
  482.  
  483. /*
  484.  * HandleClosedBSpline lets the user draw a series of connected lines
  485.  * and creates a ClosedBSplineSelection when the user presses the
  486.  * middle button.
  487.  */
  488.  
  489. void Editor::HandleClosedBSpline (Event& e) {
  490.     Coord* x;
  491.     Coord* y;
  492.     int n;
  493.  
  494.     drawingview->EraseHandles();
  495.     InputVertices(e, x, y, n);
  496.  
  497.     if (n != 2 || x[0] != x[1] || y[0] != y[1]) {
  498.     drawing->Select(
  499.         new ClosedBSplineSelection(x, y, n, state->GetGraphicGS())
  500.     );
  501.     Do(new AddChange(drawing, drawingview));
  502.     }
  503. }
  504.  
  505. /*
  506.  * New offers to write an unsaved drawing and creates a new empty
  507.  * drawing if the save succeeds or the user refuses the offer.
  508.  */
  509.  
  510. void Editor::New () {
  511.     boolean successful = OfferToSave();
  512.     if (successful) {
  513.     drawing->ClearPicture();
  514.     Reset(nil);
  515.     }
  516. }
  517.  
  518. /*
  519.  * Revert rereads the drawing from its file.  It asks for confirmation
  520.  * before reverting an unsaved drawing.
  521.  */
  522.  
  523. void Editor::Revert () {
  524.     const char* name = state->GetDrawingName();
  525.     if (name != nil) {
  526.     char response = revertdialog->Confirm();
  527.     if (response == 'y') {
  528.         boolean successful = drawing->ReadPicture(name, state);
  529.         if (successful) {
  530.         Reset(name);
  531.         } else {
  532.         savecurdialog->
  533.             SetWarning("couldn't revert! (file nonexistent?)");
  534.         Open();
  535.         }
  536.     }
  537.     }
  538. }
  539.  
  540. /*
  541.  * Open reads a drawing from the given file.  If it fails, it calls
  542.  * the interactive Open to ask the user to type another name.
  543.  */
  544.  
  545. void Editor::Open (const char* name) {
  546.     boolean successful = drawing->ReadPicture(name, state);
  547.     if (successful) {
  548.     Reset(name);
  549.     } else {
  550.     opendialog->SetTitle("Open failed!");
  551.     Open();
  552.     }
  553. }
  554.  
  555. /*
  556.  * Open prompts for a file name and reads a drawing from that file.
  557.  * It offers to save an unsaved drawing and it keeps trying to read a
  558.  * drawing until it succeeds or the user cancels the command.
  559.  */
  560.  
  561. void Editor::Open () {
  562.     boolean successful = OfferToSave();
  563.     if (successful) {
  564.     const char* name = nil;
  565.     for (;;) {
  566.         name = opendialog->Find();
  567.         if (name == nil) {
  568.         break;
  569.         }
  570.         boolean successful = drawing->ReadPicture(name, state);
  571.         if (successful) {
  572.         Reset(name);
  573.         break;
  574.         } else {
  575.         opendialog->SetTitle("Open failed!");
  576.         }
  577.     }
  578.     }
  579. }
  580.  
  581. /*
  582.  * Save writes the drawing to the file it was read from unless there's
  583.  * no file or it can't write the drawing to that file, in which case
  584.  * it hands the job off to SaveAs.
  585.  */
  586.  
  587. void Editor::Save () {
  588.     const char* name = state->GetDrawingName();
  589.     if (name == nil) {
  590.     SaveAs();
  591.     } else if (state->GetModifStatus() == ReadOnly) {
  592.     saveasdialog->SetTitle("Can't save in read-only file!");
  593.     SaveAs();
  594.     } else {
  595.     boolean successful = drawing->WritePicture(name, state);
  596.     if (successful) {
  597.         state->SetModifStatus(Unmodified);
  598.         state->UpdateViews();
  599.     } else {
  600.         saveasdialog->SetTitle("Couldn't save!");
  601.         SaveAs();
  602.     }
  603.     }
  604. }
  605.  
  606. /*
  607.  * SaveAs prompts for a file name and writes the drawing to that file.
  608.  * It asks for confirmation before overwriting an already existing
  609.  * file and it keeps trying to write the drawing until it succeeds or
  610.  * the user cancels the command.
  611.  */
  612.  
  613. void Editor::SaveAs () {
  614.     const char* name = nil;
  615.     for (;;) {
  616.     name = saveasdialog->Find();
  617.     if (name == nil) {
  618.         break;
  619.     }
  620.     if (drawing->Exists(name)) {
  621.         overwritedialog->SetWarning("a drawing named ", name);
  622.         char response = overwritedialog->Confirm();
  623.         if (response != 'y') {
  624.         break;
  625.         }
  626.     }
  627.     boolean successful = drawing->WritePicture(name, state);
  628.     if (successful) {
  629.         state->SetDrawingName(name);
  630.         state->SetModifStatus(Unmodified);
  631.         state->UpdateViews();
  632.         break;
  633.     } else {
  634.         saveasdialog->SetTitle("Couldn't save!");
  635.     }
  636.     }
  637.     saveasdialog->SetTitle("");
  638. }
  639.  
  640. /*
  641.  * Print prompts for a print command and writes the drawing through a
  642.  * pipe to that command's standard input.  It keeps trying to print
  643.  * the drawing until it succeeds or the user cancels the command.
  644.  */
  645.  
  646. void Editor::Print () {
  647.     if (state->GetModifStatus() == Modified) {
  648.     savecurdialog->SetWarning("a broken pipe signal won't be caught");
  649.     }
  650.     boolean successful = OfferToSave();
  651.     if (successful) {
  652.     char* cmd = nil;
  653.     for (;;) {
  654.         delete cmd;
  655.         cmd = printdialog->Edit(nil);
  656.         if (cmd == nil) {
  657.         break;
  658.         }
  659.         boolean successful = drawing->PrintPicture(cmd, state);
  660.         if (successful) {
  661.         break;
  662.         } else {
  663.         printdialog->SetWarning("couldn't execute ", cmd);
  664.         }
  665.     }
  666.     delete cmd;
  667.     }
  668. }
  669.  
  670. /*
  671.  * Quit offers to save an unsaved drawing and tells Idraw to quit
  672.  * running if the save succeeds or the user refuses the offer.
  673.  */
  674.  
  675. void Editor::Quit (Event& e) {
  676.     boolean successful = OfferToSave();
  677.     if (successful) {
  678.     e.target = nil;
  679.     }
  680. }
  681.  
  682. /*
  683.  * Checkpoint writes an unsaved drawing to a temporary filename.  The
  684.  * program currently calls Checkpoint only when an X error occurs.
  685.  */
  686.  
  687. void Editor::Checkpoint () {
  688.     if (state->GetModifStatus() == Modified) {
  689.     char* path = tempnam("./", "idraw");
  690.     boolean successful = drawing->WritePicture(path, state);
  691.     if (successful) {
  692.         fprintf(stderr, "saved drawing as \"%s\"\n", path);
  693.     } else {
  694.         fprintf(stderr, "sorry, couldn't save drawing as \"%s\"\n", path);
  695.     }
  696.     delete path;
  697.     } else {
  698.     fprintf(stderr, "drawing was unmodified, didn't save it\n");
  699.     }
  700. }
  701.  
  702. /*
  703.  * Undo undoes the last change made to the drawing.  Undo does nothing
  704.  * if all stored changes have been undone.
  705.  */
  706.  
  707. void Editor::Undo () {
  708.     history->Undo();
  709. }
  710.  
  711. /*
  712.  * Redo redoes the last undone change made to the drawing, i.e., it
  713.  * undoes an Undo.  Redo does nothing if it follows a Do.
  714.  */
  715.  
  716. void Editor::Redo () {
  717.     history->Redo();
  718. }
  719.  
  720. /*
  721.  * Cut removes the Selections and writes them to the clipboard file,
  722.  * overwriting whatever was there previously.
  723.  */
  724.  
  725. void Editor::Cut () {
  726.     Do(new CutChange(drawing, drawingview));
  727. }
  728.  
  729. /*
  730.  * Copy copies the Selections and writes them to the clipboard file,
  731.  * overwriting whatever was there previously.
  732.  */
  733.  
  734. void Editor::Copy () {
  735.     Do(new CopyChange(drawing, drawingview));
  736. }
  737.  
  738. /*
  739.  * Paste reads new Selections from the clipboard file and appends them
  740.  * to the drawing.
  741.  */
  742.  
  743. void Editor::Paste () {
  744.     Do(new PasteChange(drawing, drawingview, state));
  745. }
  746.  
  747. /*
  748.  * Duplicate duplicates the Selections and appends the new Selections
  749.  * to the drawing.
  750.  */
  751.  
  752. void Editor::Duplicate () {
  753.     Do(new DuplicateChange(drawing, drawingview));
  754. }
  755.  
  756. /*
  757.  * Delete deletes all of the Selections.
  758.  */
  759.  
  760. void Editor::Delete () {
  761.     Do(new DeleteChange(drawing, drawingview));
  762. }
  763.  
  764. /*
  765.  * SelectAll selects all of the Selections in the drawing.
  766.  */
  767.  
  768. void Editor::SelectAll () {
  769.     drawing->SelectAll();
  770.     drawingview->DrawHandles();
  771. }
  772.  
  773. /*
  774.  * FlipHorizontal flips the Selections horizontally by scaling them by
  775.  * -1 along the x axis about their centers.
  776.  */
  777.  
  778. void Editor::FlipHorizontal () {
  779.     Do(new ScaleChange(drawing, drawingview, -1, 1));
  780. }
  781.  
  782. /*
  783.  * FlipVertical flips the Selections vertically by scaling them by -1
  784.  * along the y axis about their centers.
  785.  */
  786.  
  787. void Editor::FlipVertical () {
  788.     Do(new ScaleChange(drawing, drawingview, 1, -1));
  789. }
  790.  
  791. /*
  792.  * _90Clockwise rotates the Selections 90 degrees clockwise about
  793.  * their centers.
  794.  */
  795.  
  796. void Editor::_90Clockwise () {
  797.     Do(new RotateChange(drawing, drawingview, -90.));
  798. }
  799.  
  800. /*
  801.  * _90CounterCW rotates the Selections 90 degrees counter-clockwise
  802.  * about their centers.
  803.  */
  804.  
  805. void Editor::_90CounterCW () {
  806.     Do(new RotateChange(drawing, drawingview, 90.));
  807. }
  808.  
  809. /*
  810.  * PreciseMove prompts the user for the x and y movement in units of
  811.  * points or pixels and moves the Selections that far.
  812.  */
  813.  
  814. void Editor::PreciseMove () {
  815.     char* movement = nil;
  816.     for (;;) {
  817.     delete movement;
  818.     movement = precmovedialog->Edit(nil);
  819.     if (movement == nil) {
  820.         break;
  821.     }
  822.     float xdisp, ydisp;
  823.     char unit;
  824.     if (sscanf(movement, "%f %f p%c", &xdisp, &ydisp, &unit) == 3) {
  825.         if (xdisp != 0 || ydisp != 0) {
  826.         if (unit != 'i') {
  827.             xdisp *= points;
  828.             ydisp *= points;
  829.         }
  830.         Do(new MoveChange(drawing, drawingview, xdisp, ydisp));
  831.         }
  832.         break;
  833.     } else {
  834.         precmovedialog->SetWarning("couldn't parse ", movement);
  835.     }
  836.     }
  837.     delete movement;
  838. }
  839.  
  840. /*
  841.  * PreciseScale prompts the user for the x and y scales and scales the
  842.  * Selections that much about their centers.
  843.  */
  844.  
  845. void Editor::PreciseScale () {
  846.     char* scaling = nil;
  847.     for (;;) {
  848.     delete scaling;
  849.     scaling = precscaledialog->Edit(nil);
  850.     if (scaling == nil) {
  851.         break;
  852.     }
  853.     float xscale, yscale;
  854.     if (sscanf(scaling, "%f %f", &xscale, &yscale) == 2) {
  855.         if (xscale !=0 && yscale != 0) {
  856.         Do(new ScaleChange(drawing, drawingview, xscale, yscale));
  857.         }
  858.         break;
  859.     } else {
  860.         precscaledialog->SetWarning("couldn't parse ", scaling);
  861.     }
  862.     }
  863.     delete scaling;
  864. }
  865.  
  866. /*
  867.  * PreciseRotate prompts the user for the angle and rotates the
  868.  * Selections that many degrees about their centers.
  869.  */
  870.  
  871. void Editor::PreciseRotate () {
  872.     char* rotation = nil;
  873.     for (;;) {
  874.     delete rotation;
  875.     rotation = precrotdialog->Edit(nil);
  876.     if (rotation == nil) {
  877.         break;
  878.     }
  879.     float angle;
  880.     if (sscanf(rotation, "%f", &angle) == 1) {
  881.         if (angle != 0) {
  882.         Do(new RotateChange(drawing, drawingview, angle));
  883.         }
  884.         break;
  885.     } else {
  886.         precrotdialog->SetWarning("couldn't parse ", rotation);
  887.     }
  888.     }
  889.     delete rotation;
  890. }
  891.  
  892. /*
  893.  * Group groups the Selections together.
  894.  */
  895.  
  896. void Editor::Group () {
  897.     Do(new GroupChange(drawing, drawingview));
  898. }
  899.  
  900. /*
  901.  * Ungroup ungroups each PictSelection into its component Selections.
  902.  */
  903.  
  904. void Editor::Ungroup () {
  905.     Do(new UngroupChange(drawing, drawingview));
  906. }
  907.  
  908. /*
  909.  * BringToFront brings the Selections to the front of the drawing.
  910.  */
  911.  
  912. void Editor::BringToFront () {
  913.     Do(new BringToFrontChange(drawing, drawingview));
  914. }
  915.  
  916. /*
  917.  * SendToBack sends the Selections to the back of the drawing.
  918.  */
  919.  
  920. void Editor::SendToBack () {
  921.     Do(new SendToBackChange(drawing, drawingview));
  922. }
  923.  
  924. /*
  925.  * NumberOfGraphics counts the number of graphics in the drawing and
  926.  * displays the count.
  927.  */
  928.  
  929. void Editor::NumberOfGraphics () {
  930.     int num = drawing->GetNumberOfGraphics();
  931.     if (num == 1) {
  932.     numberofdialog->SetMessage("The selections contain 1 graphic.");
  933.     } else {
  934.     char buf[50];
  935.     sprintf(buf, "The selections contain %d graphics.", num);
  936.     numberofdialog->SetMessage(buf);
  937.     }
  938.     numberofdialog->Display();
  939. }
  940.  
  941. /*
  942.  * SetBrush sets the Selections' brush and updates the views to
  943.  * display the new current brush.
  944.  */
  945.  
  946. void Editor::SetBrush (IBrush* brush) {
  947.     state->SetBrush(brush);
  948.     state->UpdateViews();
  949.     Do(new SetBrushChange(drawing, drawingview, brush));
  950. }
  951.  
  952. /*
  953.  * SetFgColor sets the Selections' foreground color and updates the
  954.  * views to display the new current foreground color.
  955.  */
  956.  
  957. void Editor::SetFgColor (IColor* fg) {
  958.     state->SetFgColor(fg);
  959.     state->UpdateViews();
  960.     Do(new SetFgColorChange(drawing, drawingview, fg));
  961. }
  962.  
  963. /*
  964.  * SetBgColor sets the Selections' background color and updates the
  965.  * views to display the new current background color.
  966.  */
  967.  
  968. void Editor::SetBgColor (IColor* bg) {
  969.     state->SetBgColor(bg);
  970.     state->UpdateViews();
  971.     Do(new SetBgColorChange(drawing, drawingview, bg));
  972. }
  973.  
  974. /*
  975.  * SetFont sets the Selections' font and updates the views to display
  976.  * the new current font.
  977.  */
  978.  
  979. void Editor::SetFont (IFont* font) {
  980.     state->SetFont(font);
  981.     state->UpdateViews();
  982.     Do(new SetFontChange(drawing, drawingview, font));
  983. }
  984.  
  985. /*
  986.  * SetPattern sets the Selections' pattern and updates the views to
  987.  * display the new current pattern.
  988.  */
  989.  
  990. void Editor::SetPattern (IPattern* pattern) {
  991.     state->SetPattern(pattern);
  992.     state->UpdateViews();
  993.     Do(new SetPatternChange(drawing, drawingview, pattern));
  994. }
  995.  
  996. /*
  997.  * AlignLeftSides aligns the rest of the Selections's left sides with
  998.  * the first Selection's left side.
  999.  */
  1000.  
  1001. void Editor::AlignLeftSides () {
  1002.     Do(new AlignChange(drawing, drawingview, Left, Left));
  1003. }
  1004.  
  1005. /*
  1006.  * AlignRightSides aligns the rest of the Selections' right sides with
  1007.  * the first Selection's right side.
  1008.  */
  1009.  
  1010. void Editor::AlignRightSides () {
  1011.     Do(new AlignChange(drawing, drawingview, Right, Right));
  1012. }
  1013.  
  1014. /*
  1015.  * AlignBottomSides aligns the rest of the Selections' bottom sides
  1016.  * with the first Selection's bottom side.
  1017.  */
  1018.  
  1019. void Editor::AlignBottoms () {
  1020.     Do(new AlignChange(drawing, drawingview, Bottom, Bottom));
  1021. }
  1022.  
  1023. /*
  1024.  * AlignTopSides aligns the rest of the Selections' top sides with the
  1025.  * first Selection's top side.
  1026.  */
  1027.  
  1028. void Editor::AlignTops () {
  1029.     Do(new AlignChange(drawing, drawingview, Top, Top));
  1030. }
  1031.  
  1032. /*
  1033.  * AlignVertCenters aligns the rest of the Selections' vertical
  1034.  * centers with the first Selection's vertical center.
  1035.  */
  1036.  
  1037. void Editor::AlignVertCenters () {
  1038.     Do(new AlignChange(drawing, drawingview, VertCenter, VertCenter));
  1039. }
  1040.  
  1041. /*
  1042.  * AlignHorizCenters aligns the rest of the Selections' horizontal
  1043.  * centers with the first Selection's horizontal center.
  1044.  */
  1045.  
  1046. void Editor::AlignHorizCenters () {
  1047.     Do(new AlignChange(drawing, drawingview, HorizCenter, HorizCenter));
  1048. }
  1049.  
  1050. /*
  1051.  * AlignCenters aligns the rest of the Selections' centers with the
  1052.  * first Selection's center.
  1053.  */
  1054.  
  1055. void Editor::AlignCenters () {
  1056.     Do(new AlignChange(drawing, drawingview, Center, Center));
  1057. }
  1058.  
  1059. /*
  1060.  * AlignLeftToRight aligns each Selection's left side with its
  1061.  * predecessor's right side.
  1062.  */
  1063.  
  1064. void Editor::AlignLeftToRight () {
  1065.     Do(new AlignChange(drawing, drawingview, Right, Left));
  1066. }
  1067.  
  1068. /*
  1069.  * AlignRightToLeft aligns each Selection's right side with its
  1070.  * predecessor's left side.
  1071.  */
  1072.  
  1073. void Editor::AlignRightToLeft () {
  1074.     Do(new AlignChange(drawing, drawingview, Left, Right));
  1075. }
  1076.  
  1077. /*
  1078.  * AlignBottomToTop aligns each Selection's bottom side with its
  1079.  * predecessor's top side.
  1080.  */
  1081.  
  1082. void Editor::AlignBottomToTop () {
  1083.     Do(new AlignChange(drawing, drawingview, Top, Bottom));
  1084. }
  1085.  
  1086. /*
  1087.  * AlignTopToBottom aligns each Selection's top side with its
  1088.  * predecessor's bottom side.
  1089.  */
  1090.  
  1091. void Editor::AlignTopToBottom () {
  1092.     Do(new AlignChange(drawing, drawingview, Bottom, Top));
  1093. }
  1094.  
  1095. /*
  1096.  * AlignToGrid aligns the Selections' lower left corners with the
  1097.  * closest grid point.
  1098.  */
  1099.  
  1100. void Editor::AlignToGrid () {
  1101.     Do(new AlignToGridChange(drawing, drawingview));
  1102. }
  1103.  
  1104. /*
  1105.  * Reduce reduces the drawing's magnification by a factor of two.
  1106.  */
  1107.  
  1108. void Editor::Reduce () {
  1109.     drawingview->Reduce();
  1110. }
  1111.  
  1112. /*
  1113.  * Enlarge enlarges the drawing's magnification by a factor of two.
  1114.  */
  1115.  
  1116. void Editor::Enlarge () {
  1117.     drawingview->Enlarge();
  1118. }
  1119.  
  1120. /*
  1121.  * NormalSize resets the drawing's magnification.
  1122.  */
  1123.  
  1124. void Editor::NormalSize () {
  1125.     drawingview->NormalSize();
  1126. }
  1127.  
  1128. /*
  1129.  * ReduceToFit reduces the drawing's magnification enough to fit all
  1130.  * of the drawing in the window.
  1131.  */
  1132.  
  1133. void Editor::ReduceToFit () {
  1134.     drawingview->ReduceToFit();
  1135. }
  1136.  
  1137. /*
  1138.  * CenterPage scrolls the drawing so its center coincidences with the
  1139.  * window's center.
  1140.  */
  1141.  
  1142. void Editor::CenterPage () {
  1143.     drawingview->CenterPage();
  1144. }
  1145.  
  1146. /*
  1147.  * RedrawPage redraws the drawing without moving the view.
  1148.  */
  1149.  
  1150. void Editor::RedrawPage () {
  1151.     drawingview->Draw();
  1152. }
  1153.  
  1154. /*
  1155.  * GriddingOnOff toggles the grid's constraint on or off.
  1156.  */
  1157.  
  1158. void Editor::GriddingOnOff () {
  1159.     state->SetGridGravity(!state->GetGridGravity());
  1160.     state->UpdateViews();
  1161. }
  1162.  
  1163. /*
  1164.  * GridVisibleInvisible toggles the grid's visibility on or off.
  1165.  */
  1166.  
  1167. void Editor::GridVisibleInvisible () {
  1168.     state->SetGridVisibility(!state->GetGridVisibility());
  1169.     drawingview->Draw();
  1170. }
  1171.  
  1172. /*
  1173.  * GridSpacing prompts the user for the new grid spacing in units of
  1174.  * points or pixels.
  1175.  */
  1176.  
  1177. void Editor::GridSpacing () {
  1178.     static char oldspacing[50];
  1179.     sprintf(oldspacing, "%lg", state->GetGridSpacing());
  1180.     char* spacing = nil;
  1181.     for (;;) {
  1182.     delete spacing;
  1183.     spacing = spacingdialog->Edit(oldspacing);
  1184.     if (spacing == nil) {
  1185.         break;
  1186.     }
  1187.     float s;
  1188.     char unit;
  1189.     if (sscanf(spacing, "%f p%c", &s, &unit) == 2) {
  1190.         if (s > 0.) {
  1191.         state->SetGridSpacing(s, (unit == 'i'));
  1192.         if (state->GetGridVisibility() == true) {
  1193.             drawingview->Update();
  1194.         }
  1195.         }
  1196.         break;
  1197.     } else {
  1198.         spacingdialog->SetWarning("couldn't parse ", spacing);
  1199.     }
  1200.     }
  1201.     delete spacing;
  1202. }
  1203.  
  1204. /*
  1205.  * Orientation toggles the page between portrait and landscape
  1206.  * orientations.
  1207.  */
  1208.  
  1209. void Editor::Orientation () {
  1210.     state->ToggleOrientation();
  1211.     drawingview->Update();
  1212. }
  1213.  
  1214. /*
  1215.  * ShowVersion displays idraw's version level and author.
  1216.  */
  1217.  
  1218. void Editor::ShowVersion () {
  1219.     versiondialog->Display();
  1220. }
  1221.  
  1222. /*
  1223.  * Do performs a change to the drawing and updates the drawing's
  1224.  * modification status if it was unmodified.
  1225.  */
  1226.  
  1227. void Editor::Do (ChangeNode* changenode) {
  1228.     switch (state->GetModifStatus()) {
  1229.     case Unmodified:
  1230.     history->Do(changenode);
  1231.     state->SetModifStatus(Modified);
  1232.     state->UpdateViews();
  1233.     break;
  1234.     default:
  1235.     history->Do(changenode);
  1236.     break;
  1237.     }
  1238. }
  1239.  
  1240. /*
  1241.  * InputVertices lets the user keep drawing a series of connected
  1242.  * lines until the user presses a button other than the left button.
  1243.  * It returns the vertices inputted by the user.
  1244.  */
  1245.  
  1246. void Editor::InputVertices (Event& e, Coord*& xret, Coord*& yret, int& nret) {
  1247.     const int INITIALSIZE = 100;
  1248.     static int sizebuffers = 0;
  1249.     static RubberLine** rubberlines = nil;
  1250.     static Coord* x = nil;
  1251.     static Coord* y = nil;
  1252.     if (INITIALSIZE > sizebuffers) {
  1253.     sizebuffers = INITIALSIZE;
  1254.     rubberlines = new RubberLine*[sizebuffers];
  1255.     x = new Coord[sizebuffers];
  1256.     y = new Coord[sizebuffers];
  1257.     }
  1258.  
  1259.     int n = 0;
  1260.     state->Constrain(e.x, e.y);
  1261.     rubberlines[0] = nil;
  1262.     x[0] = e.x;
  1263.     y[0] = e.y;
  1264.     ++n;
  1265.  
  1266.     while (e.button == LEFTMOUSE) {
  1267.     rubberlines[n] = NewRubberLineOrAxis(e);
  1268.     e.eventType = UpEvent;
  1269.     drawingview->Manipulate(e, rubberlines[n], DownEvent, true, false);
  1270.     Coord dummy;
  1271.     rubberlines[n]->GetCurrent(dummy, dummy, e.x, e.y);
  1272.     x[n] = e.x;
  1273.     y[n] = e.y;
  1274.     ++n;
  1275.  
  1276.     if (n == sizebuffers) {
  1277.         RubberLine** oldrubberlines = rubberlines;
  1278.         Coord* oldx = x;
  1279.         Coord* oldy = y;
  1280.         sizebuffers += INITIALSIZE/2;
  1281.         rubberlines = new RubberLine*[sizebuffers];
  1282.         x = new Coord[sizebuffers];
  1283.         y = new Coord[sizebuffers];
  1284.         memmove(rubberlines, oldrubberlines, n * sizeof(RubberLine*));
  1285.         memmove(x, oldx, n * sizeof(Coord));
  1286.         memmove(y, oldy, n * sizeof(Coord));
  1287.         delete oldrubberlines;
  1288.         delete oldx;
  1289.         delete oldy;
  1290.     }
  1291.     }
  1292.  
  1293.     xret = x;
  1294.     yret = y;
  1295.     nret = n;
  1296.     for (int i = 1; i < n; i++) {
  1297.     rubberlines[i]->Erase();
  1298.     delete rubberlines[i];
  1299.     }
  1300. }
  1301.  
  1302. /*
  1303.  * NewRubberLineOrAxis creates and returns a new RubberLine or a new
  1304.  * RubberAxis depending on whether the shift key's being depressed.
  1305.  */
  1306.  
  1307. RubberLine* Editor::NewRubberLineOrAxis (Event& e) {
  1308.     return (!e.shift ? 
  1309.         new RubberLine(nil, nil, e.x, e.y, e.x, e.y) :
  1310.         new RubberAxis(nil, nil, e.x, e.y, e.x, e.y));
  1311. }
  1312.  
  1313. /*
  1314.  * NewRubberEllipseOrCircle creates and returns a new RubberEllipse or
  1315.  * a new RubberCircle depending on the shift key's state.
  1316.  */
  1317.  
  1318. RubberEllipse* Editor::NewRubberEllipseOrCircle (Event& e) {
  1319.     return (!e.shift ?
  1320.         new RubberEllipse(nil, nil, e.x, e.y, e.x, e.y) :
  1321.         new RubberCircle(nil, nil, e.x, e.y, e.x, e.y));
  1322. }
  1323.  
  1324. /*
  1325.  * NewRubberRectOrSquare creates and returns a new RubberRect or a new
  1326.  * RubberSquare depending on whether the shift key's being depressed.
  1327.  */
  1328.  
  1329. RubberRect* Editor::NewRubberRectOrSquare (Event& e) {
  1330.     return (!e.shift ? 
  1331.         new RubberRect(nil, nil, e.x, e.y, e.x, e.y) :
  1332.         new RubberSquare(nil, nil, e.x, e.y, e.x, e.y));
  1333. }
  1334.  
  1335. /*
  1336.  * OfferToSave returns true if it saves an unsaved drawing or the user
  1337.  * refuses the offer or no changes need to be saved.
  1338.  */
  1339.  
  1340. boolean Editor::OfferToSave () {
  1341.     boolean successful = false;
  1342.     if (state->GetModifStatus() == Modified) {
  1343.     char response = savecurdialog->Confirm();
  1344.     if (response == 'y') {
  1345.         Save();
  1346.         if (state->GetModifStatus() == Unmodified) {
  1347.         successful = true;
  1348.         }
  1349.     } else if (response == 'n') {
  1350.         successful = true;
  1351.     }
  1352.     } else {
  1353.     successful = true;
  1354.     }
  1355.     return successful;
  1356. }
  1357.  
  1358. /*
  1359.  * Reset redraws the view, clears the history, and resets state
  1360.  * information about the drawing's name and its modification status.
  1361.  */
  1362.  
  1363. void Editor::Reset (const char* name) {
  1364.     history->Clear();
  1365.     state->SetDrawingName(name);
  1366.     if (name != nil && !drawing->Writable(name)) {
  1367.     state->SetModifStatus(ReadOnly);
  1368.     } else {
  1369.     state->SetModifStatus(Unmodified);
  1370.     }
  1371.     state->UpdateViews();
  1372.     drawingview->Update();
  1373. }
  1374.