entry : codePreviewMap.entrySet()) {
- int[] range = entry.getValue();
- if (range[0] <= lineNo && range[1] > lineNo) {
- if (range[1] - range[0] < lineRangeSize || closest == null) {
- closest = entry.getKey();
- lineRangeSize = range[1] - range[0];
- }
- }
- }
- return closest;
- }
-
- // START KGU#705 2019-09-26: Enh. #738
- /**
- * Entry point for external components to get the given {@code element}
- * consistently selected in the diagram.
- *
- * @param element - the {@link Element} to be selected
- */
- public void selectElement(Element element) {
- if (element != null) {
- Element sel = root.findSelected();
- if (sel != null) {
- sel.setSelected(false);
- }
- element.setSelected(true);
- selected = element;
- selectedDown = selected;
- this.redraw(element);
- if (codeHighlighter != null) {
- codeHighlighter.removeAllHighlights();
- }
- this.highlightCodeForElement(element, false);
- }
- }
- // END KGU#705 2019-09-26
-
- /**
- * Method: print
- *
- *
- * This class is responsible for rendering a page using the provided
- * parameters. The result will be a grid where each cell will be half an
- * inch by half an inch.
- *
- * @param g a value of type Graphics
- * @param pageFormat a value of type PageFormat
- * @param page a value of type int
- * @return a value of type int
- */
- public int print(Graphics g, PageFormat pageFormat, int page) {
- if (page == 0) {
- Graphics2D g2d = (Graphics2D) g;
-
- g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
-
- /*if (pageFormat.getOrientation() != PageFormat.PORTRAIT)
- {*/
- double sX = (pageFormat.getImageableWidth() - 1) / root.width;
- double sY = (pageFormat.getImageableHeight() - 1) / root.height;
- double sca = Math.min(sX, sY);
- if (sca > 1) {
- sca = 1;
- }
- g2d.scale(sca, sca);
- /*}
- else
- {
- double sX = (pageFormat.getImageableWidth()-1)/root.width;
- double sY = (pageFormat.getImageableHeight()-1)/root.height;
- double sca = Math.min(sX,sY);
- //if (sca>1) {sca=1;}
- g2d.scale(sca,sca);
- }*/
-
- // START KGU#906 2021-01-06: Enh. #905 We don't want the triangles in the print
- //root.draw(g, null);
- root.draw(g, null, DrawingContext.DC_IMAGE_EXPORT);
- // END KGU#906 2021-01-06
-
- return (PAGE_EXISTS);
- } else {
- return (NO_SUCH_PAGE);
- }
- }
-
- /*========================================
+ */
+ @Override
+ public void mouseWheelMoved(MouseWheelEvent e) {
+ // START KGU#699 2019-03-27: Enh. #717 This is for convenience in configureWheelUnit()
+ if (e.getSource() instanceof JSpinner) {
+ SpinnerNumberModel model = (SpinnerNumberModel) ((JSpinner) e.getSource()).getModel();
+ int rotation = e.getWheelRotation();
+ Object value = null;
+ if (rotation < 0 && (value = model.getNextValue()) != null) {
+ model.setValue(value);
+ } else if (rotation > 0 && (value = model.getPreviousValue()) != null) {
+ model.setValue(value);
+ }
+ return;
+ }
+ // END KGU#699 2019-03-27
+ //System.out.println("MouseWheelMoved at (" + e.getX() + ", " + e.getY() + ")");
+ //System.out.println("MouseWheelEvent: " + e.getModifiers() + " Rotation = " + e.getWheelRotation() + " Type = " +
+ // ((e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) ? ("UNIT " + e.getScrollAmount()) : "BLOCK") );
+ // START KGU#503 2018-03-13: Enh. #519 - The mouse wheel got a new function and is permanently listened to
+ //if (selected != null)
+ if ((e.getModifiersEx() & MouseWheelEvent.CTRL_DOWN_MASK) != 0) {
+ // Ctrl + mouse wheel is now to raise or shrink the font (thus to kind of zoom)
+ int rotation = e.getWheelRotation();
+ int fontSize = Element.getFont().getSize();
+ if (Element.E_WHEEL_REVERSE_ZOOM) {
+ rotation *= -1;
+ }
+ if (rotation >= 1 && fontSize - 1 >= 4) {
+ // reduce font size
+ Element.setFont(new Font(Element.getFont().getFamily(), Font.PLAIN, fontSize - 1));
+ root.resetDrawingInfoDown();
+ redraw();
+ e.consume();
+ } else if (rotation <= -1) {
+ // enlarge font size
+ Element.setFont(new Font(Element.getFont().getFamily(), Font.PLAIN, fontSize + 1));
+ root.resetDrawingInfoDown();
+ redraw();
+ e.consume();
+ }
+ } else if (Element.E_WHEELCOLLAPSE && selected != null)
+ // END KGU#503 2018-03-13
+ {
+ // START KGU#123 2016-01-04: Bugfix #65 - heavy differences between Windows and Linux here:
+ // In Windows, the rotation result may be arbitrarily large whereas the scrollAmount is usually 1.
+ // In Linux, however, the rotation result will usually be -1 or +1, whereas the scroll amount is 3.
+ // So we just multiply both and will get a sensible threshold, we hope.
+ //if(e.getWheelRotation()<-1) selected.setCollapsed(true);
+ //else if(e.getWheelRotation()>1) selected.setCollapsed(false);
+ int rotation = e.getWheelRotation();
+ if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
+ rotation *= e.getScrollAmount();
+ } else {
+ rotation *= 2;
+ }
+ if (rotation < -1) {
+ selected.setCollapsed(true);
+ } else if (rotation > 1) {
+ selected.setCollapsed(false);
+ }
+ // END KGU#123 2016-01-04
+ // START KGU#503 2018-03-13: Enh. #519 - may not work (depends on the order of listeners)
+ e.consume();
+ // END KGU#503 2018-03-13
+ redraw();
+ }
+ // FIXME KGU 2016-01-0: Issue #65
+ // // Rough approach to test horizontal scrollability - only works near the left and right
+ // // borders, because the last mouseMoved position is used. Seems that we will have to
+ // // maintain a virtual scroll position here which is to be used instead of e.getX().
+ // if ((e.getModifiersEx() & MouseWheelEvent.SHIFT_DOWN_MASK) != 0)
+ // {
+ // int rotation = e.getWheelRotation();
+ // if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
+ // rotation *= e.getScrollAmount();
+ // }
+ // System.out.println("Horizontal scrolling by " + rotation);
+ // Rectangle r = new Rectangle(e.getX() + 50 * rotation, e.getY(), 1, 1);
+ // ((JPanel)e.getSource()).scrollRectToVisible(r);
+ // }
+ }
+
+ // START KGU#143 2016-01-21: Bugfix #114 - We need a possibility to update buttons from execution status
+ public void doButtons() {
+ if (NSDControl != null) {
+ NSDControl.doButtons();
+ }
+ }
+ // END KGU#143 2016-01-21
+
+ // START KGU#276 2016-10-09: Issue #269
+ /**
+ * Scroll to the given element and redraw the current diagram
+ *
+ * @param element - the element to gain the focus
+ */
+ public void redraw(Element element) {
+ Rectangle rect = element.getRectOffDrawPoint().getRectangle();
+ Rectangle visibleRect = new Rectangle();
+ this.computeVisibleRect(visibleRect);
+ // START KGU#276 2016-11-19: Issue #269 Ensure wide elements be shown left-bound
+ if (rect.width > visibleRect.width
+ && !(element instanceof Alternative || element instanceof Case)) {
+ rect.width = visibleRect.width;
+ }
+ // END KGU#276 2016-11-19
+ // START KGU#276 2016-11-21: Issue #269 Ensure high elements be shown top-bound
+ if (rect.height > visibleRect.height
+ && !(element instanceof Instruction || element instanceof Parallel || element instanceof Forever)) {
+ // ... except for REPEAT loops, which are to be shown bottom-aligned
+ if (element instanceof Repeat) {
+ rect.y += rect.height - visibleRect.height;
+ }
+ rect.height = visibleRect.height;
+ }
+ // END KGU#276 2016-11-21
+ try {
+ scrollRectToVisible(rect);
+ } catch (Exception ex) {
+ logger.warning(ex.toString());
+ }
+ redraw(); // This is to make sure the drawing rectangles are correct
+ // START KGU#705 2019-09-24: Enh. 738
+ if (show_CODE_PREVIEW && codeHighlighter != null && element.executed) {
+ codeHighlighter.removeAllHighlights();
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ highlightCodeForElement(element, true);
+ }
+ });
+ }
+ // END KGU#705 2019-09-24
+ }
+ // END KGU#276 2016-10-09
+
+ public void redraw() {
+ // START KGU#440 2017-11-06: Bugfix #455 - suppress drawing unless Structorizer is fully initialized
+ if (!this.isInitialized) {
+ return;
+ }
+ // END KGU#440 2017-11-06
+ boolean wasHighLight = Element.E_VARHIGHLIGHT;
+ if (wasHighLight) {
+ // START KGU#430 2017-10-10: Issue #432
+ //root.getVarNames();
+ try {
+ // START KGU#444/KGU#618 2018-12-18: Issue #417, #649
+ //root.getVarNames();
+ root.getVarNames();
+ // END KGU#444/KGU#618 2018-12-18
+ } catch (Exception ex) {
+ logger.log(Level.WARNING, "*** Possible sync problem:", ex);
+ // Avoid trouble (highlighting would require variable retrieval)
+ Element.E_VARHIGHLIGHT = false;
+ }
+ // END KGU#430 2017-10-10
+ }
+
+ Rect rect = root.prepareDraw(this.getGraphics());
+ Dimension d = new Dimension(rect.right - rect.left, rect.bottom - rect.top);
+ this.setPreferredSize(d);
+ //this.setSize(d);
+ this.setMaximumSize(d);
+ this.setMinimumSize(d);
+ //this.setSize(new Dimension(rect.right-rect.left,rect.bottom-rect.top));
+ //this.validate();
+
+ ((JViewport) this.getParent()).revalidate();
+
+ //redraw(this.getGraphics());
+ this.repaint();
+
+ // START KGU#430 2017-10-10: Issue #432
+ Element.E_VARHIGHLIGHT = wasHighLight;
+ // END KGU#430 2017-10-10
+ }
+
+ // START KGU#703 219-03-30: Issue #718, #720
+ /**
+ * Resets cached variable and type information, the drawing information
+ * including the highlight cache after routine pool changes and redraws the
+ * managed diagram. The clearing of variables, types etc. is not done if the
+ * {@link Root} is under execution.
+ */
+ public void invalidateAndRedraw() {
+ // During execution it is no good idea to reset variable, constants, and type information.
+ // Anyway the pool changes will usually only be a pseudo addition in order to get ownership
+ // of executed subroutines, so better ignore it.
+ // Otherwise, of course, we should react to a possible insertion or removal of some referred
+ // includable, and even subroutines becoming available may have an impact on derived types
+ // (result types), even recursively.
+ if (!root.isExecuted()) {
+ root.clearVarAndTypeInfo(false);
+ }
+ // START KGU#874 2020-10-18: Issue #875 Particularly the save buttons must be updated
+ this.doButtons();
+ // END KGU#874 2020-10-18
+ redraw();
+ }
+ // END KGU#703 2019-03-30
+
+ public void redraw(Graphics _g) {
+ // START KGU#906 2021-01-06: Enh. #905 - we needed to distinguish work area from export
+ redraw(_g, DrawingContext.DC_STRUCTORIZER);
+ }
+
+ public void redraw(Graphics _g, DrawingContext _context)
+ // END KGU#906 2021-01-06
+ {
+ // KGU#91 2015-12-04: Bugfix #39 - Disabled
+ //if (Element.E_TOGGLETC) root.setSwitchTextAndComments(true);
+ // START KGU#502/KGU#524/KGU#553: 2019-03-29: Issues #518, #544, #557 drawing speed
+ //root.draw(_g, ((JViewport)this.getParent()).getViewRect());
+ Rectangle clipRect = _g.getClipBounds();
+ // START KGU#906 2021-01-06: Enh. #905
+ //root.draw(_g, clipRect);
+ root.draw(_g, clipRect, _context);
+ // END KGU#906 2021-01-06
+ // END KGU#502/KGU#524/KGU#553
+
+ lu.fisch.graphics.Canvas canvas = new lu.fisch.graphics.Canvas((Graphics2D) _g);
+ Rect rect;
+ // draw dragged element
+ if ((selX != -1) && (selY != -1) && (selectedDown != null) && (mX != mouseX) && (mY != mouseY)) {
+ _g.setColor(Color.BLACK);
+ // START KGU#136 2016-03-02: Bugfix #97 - It must not play any role where the diagram was drawn before
+ //rect = selectedDown.getRect();
+ //Rect copyRect = rect.copy();
+ rect = selectedDown.getRectOffDrawPoint();
+ // END KGU#136 2016-03-02
+ int w = rect.right - rect.left;
+ int h = rect.bottom - rect.top;
+ rect.left = mX - selX;
+ rect.top = mY - selY;
+ rect.right = rect.left + w;
+ rect.bottom = rect.top + h;
+ ((Graphics2D) _g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f));
+ // START KGU#502/KGU#524/KGU#553: 2019-03-29: Issues #518, #544, #557 drawing speed
+ //selectedDown.draw(canvas, rect, ((JViewport)this.getParent()).getViewRect(), false);
+ selectedDown.draw(canvas, rect, clipRect, false);
+ // START KGU#502/KGU#524/KGU#553: 2019-03-29: Issues #518, #544, #557
+ ((Graphics2D) _g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f));
+ // START KGU#136 2016-03-01: Bugfix #97 - this is no longer necessary
+ //selectedDown.rect = copyRect;
+ // END KGU#136 2016-03-01
+ //System.out.println(selectedDown.getClass().getSimpleName()+"("+selectedDown.getText().getLongString()+
+ // ") repositioned to ("+copyRect.left+", "+copyRect.top+")");
+ //_g.drawRect(mX-selX, mY-selY, w, h);
+ }/**/
+
+ // KGU#91 2015-12-04: Bugfix #39 - Disabled
+ //if (Element.E_TOGGLETC) root.setSwitchTextAndComments(false);
+ }
+
+ @Override
+ public void paintComponent(Graphics g) {
+ super.paintComponent(g);
+ if (root != null) {
+ //logger.debug("Diagram: " + System.currentTimeMillis());
+ redraw(g, DrawingContext.DC_STRUCTORIZER);
+ }
+ }
+
+ // START KGU#444 2017-10-23: Issue #417 - polynomial scrolling time complexity
+ /**
+ * Adapts the scroll units according to the size of the current
+ * {@link Root}. With standard scroll unit of 1, large diagrams would take
+ * an eternity to get scrolled over because their redrawing time also
+ * increases with the number of elements, of course, such that it's
+ * polynomial (at least square) time growth...
+ */
+ protected void adaptScrollUnits() {
+ Container parent = this.getParent();
+ if (parent != null && (parent = parent.getParent()) instanceof javax.swing.JScrollPane) {
+ javax.swing.JScrollPane scroll = (javax.swing.JScrollPane) parent;
+ // START KGU#444 2017-11-03: Bugfix #417 - in rare cases a division by 0 exception could occur
+ //int heightFactor = root.getRect().bottom / scroll.getHeight() + 1;
+ //int widthFactor = root.getRect().right / scroll.getWidth() + 1;
+ int heightFactor = 1;
+ int widthFactor = 1;
+ Rect drawRect = root.getRect();
+ //System.out.println("rect : " + drawRect);
+ // START KGU#444/KGU#618 2018-12-18: Issue #417, #649 - scrolling too slow
+ // For new Roots, the drawing may not have had time to compute the size, so try an
+ // estimate from the total number of elements
+ if (drawRect.bottom < 10) {
+ int nElements = root.getElementCount();
+ drawRect = new Rect(0, 0,
+ (int) (Math.sqrt(nElements) * Element.getPadding()),
+ nElements * 3 * Element.getPadding()
+ );
+ }
+ // END KGU#444/KGU#618 2018-12-18
+ if (scroll.getHeight() > 0) {
+ heightFactor = drawRect.bottom / scroll.getHeight() + 1;
+ }
+ if (scroll.getWidth() > 0) {
+ widthFactor = drawRect.right / scroll.getWidth() + 1;
+ }
+ // END KGU#444 2017-11-03
+ //System.out.println("unit factors: " + widthFactor + " / " + heightFactor);
+ // START KGU#699 2019-03-27: Issue #717
+ //scroll.getHorizontalScrollBar().setUnitIncrement(widthFactor);
+ //scroll.getVerticalScrollBar().setUnitIncrement(heightFactor);
+ if (Element.E_WHEEL_SCROLL_UNIT <= 0) {
+ // The very first time Structorizer is used, we fetch the original unit increment
+ Element.E_WHEEL_SCROLL_UNIT = scroll.getVerticalScrollBar().getUnitIncrement();
+ }
+ scroll.getHorizontalScrollBar().setUnitIncrement(Element.E_WHEEL_SCROLL_UNIT + widthFactor - 1);
+ scroll.getVerticalScrollBar().setUnitIncrement(Element.E_WHEEL_SCROLL_UNIT + heightFactor - 1);
+ // END KGU#699 2019-03-27
+ }
+ }
+ // END KGU#444 2017-10-23
+
+ // START KGU#155 2016-03-08: Some additional fixing for bugfix #97
+ /**
+ * Invalidates the cached prepareDraw info of the current diagram (Root) (to
+ * be called on events with global impact on the size or shape of Elements)
+ */
+ public void resetDrawingInfo() {
+ root.resetDrawingInfoDown();
+ // START KGU#902 2021-01-01: Enh. #903
+ poppedElement = null;
+ // END KGU#902 2021-01-01
+ if (isArrangerOpen()) {
+ Arranger.getInstance().resetDrawingInfo(this.hashCode());
+ }
+ }
+ // END KGU#155 2016-03-08
+
+ public Element getSelected() {
+ return selected;
+ }
+
+ // START KGU#477 2017-12-07: Enh. #487
+ public Element getFirstSelected() {
+ if (selected instanceof IElementSequence && ((IElementSequence) selected).getSize() > 0) {
+ return ((IElementSequence) selected).getElement(0);
+ }
+ return selected;
+ }
+
+ public Element getLastSelected() {
+ if (selected instanceof IElementSequence && ((IElementSequence) selected).getSize() > 0) {
+ return ((IElementSequence) selected).getElement(((IElementSequence) selected).getSize() - 1);
+ }
+ return selected;
+ }
+ // END KGU#477 2017-12-07
+
+ // START KGU#87 2015-11-22:
+ public boolean selectedIsMultiple() {
+ return (selected instanceof IElementSequence && ((IElementSequence) selected).getSize() > 0);
+ }
+ // END KGU#87 2015-11-22
+
+ // START KGU#41 2015-10-11: Unselecting, e.g. before export, had left the diagram status inconsistent:
+ // Though the selected status of the elements was unset, the references of the formerly selected
+ // elements invisibly remained in the respective diagram attributes, possibly causing unwanted effects.
+ // So this new method was introduced to replace the selectElementByCoord(-1,-1) calls.
+ /**
+ * Resets the selected state on all elements of the current {@link Root} and
+ * redraws the diagram.
+ *
+ * @see #unselectAll(boolean)
+ */
+ public void unselectAll() // START KGU#430 2017-10-12: Issue #432 allow to suppress redrawing
+ {
+ unselectAll(true);
+ }
+
+ /**
+ * Resets the selected state on all elements of the current {@link Root} and
+ * redraws the diagram if {@code refresh} is true.
+ */
+ public void unselectAll(boolean refresh) // END KGU#430 2017-10-12
+ {
+ if (root != null) {
+ root.selectElementByCoord(-1, -1);
+ }
+ selected = selectedDown = selectedMoved = null;
+ if (refresh) {
+ redraw();
+ }
+ // START KGU#705 2019-09-24: Enh. #738
+ highlightCodeForSelection();
+ // END KGU#705 2019-09-24
+ }
+ // END KGU#41 2015-10-11
+
+ // START KGU#705 2019-09-24: Enh. #738
+ /**
+ * Highlights the code regions corresponding to the current selection in the
+ * preview area.
+ */
+ private void highlightCodeForSelection() {
+ if (show_CODE_PREVIEW && codePreviewMap != null) {
+ int pos = -1;
+ if (codeHighlighter != null) {
+ codeHighlighter.removeAllHighlights();
+ }
+ if (this.selected != null) {
+ if (this.selected instanceof IElementSequence) {
+ IElementSequence.Iterator iter = ((IElementSequence) this.selected).iterator(false);
+ while (iter.hasNext()) {
+ int p = highlightCodeForElement(iter.next(), false);
+ if (pos < 0) {
+ pos = p;
+ }
+ }
+ } else {
+ pos = highlightCodeForElement(this.selected, false);
+ }
+ }
+ if (pos >= 0) {
+ try {
+ // FIXME: from Java 9 on, modelToView() is to be replaced by modelToView2D()
+ Rectangle viewRect = codePreview.modelToView(pos);
+ // Scroll to make the rectangle visible
+ codePreview.scrollRectToVisible(viewRect);
+ } catch (BadLocationException e) {
+ // FIXME DEBUG (should not occur)
+ e.printStackTrace();
+ } catch (NullPointerException ex) {
+ // Nothing we could do here, symptom for racing hazard
+ }
+ }
+ }
+ }
+
+ /**
+ * Highlights the code regions corresponding to the given element
+ * {@code ele} in the preview area .
+ *
+ * @param ele - the {@link Element} the code for which is to be highlighted
+ * @param scrollTo TODO
+ * @return the start position of the first line of the element code
+ */
+ private int highlightCodeForElement(Element ele, boolean scrollTo) {
+ int pos = -1;
+ int[] interval = codePreviewMap.get(ele);
+ if (interval != null) {
+ if (codeHighlighter == null) {
+ codeHighlighter = codePreview.getHighlighter();
+ }
+ for (int line = interval[0]; line < interval[1]; line++) {
+ try {
+ pos = codePreview.getLineStartOffset(line);
+ int p0 = pos + interval[2];
+ int p1 = codePreview.getLineEndOffset(line);
+ if (p0 < p1) {
+ codeHighlighter.addHighlight(p0, p1, ele.executed ? execHighlightPainter : codeHighlightPainter);
+ if (scrollTo) {
+ // FIXME: from Java 9 on, modelToView() is to be replaced by modelToView2D()
+ Rectangle viewRect = codePreview.modelToView(pos);
+ // Scroll to make the rectangle visible
+ codePreview.scrollRectToVisible(viewRect);
+ }
+ }
+ } catch (BadLocationException e) {
+ // Just ignore errors
+ logger.warning("Bad code preview location for element " + ele);
+ }
+ }
+ }
+ return pos;
+ }
+ // END KGU#705 2019-09-24
+
+ /**
+ * Tries to identify the {@link Element} that is responsible for the code
+ * line with given number {@code lineNo} in the {@link #codePreview}.
+ *
+ * @param lineNo - number of a line in the {@link #codePreview}.
+ * @return the closest corresponding {@link Element}.
+ */
+ public Element identifyElementForCodeLine(int lineNo) {
+ int lineRangeSize = codePreview.getLineCount();
+ Element closest = null;
+ for (Entry entry : codePreviewMap.entrySet()) {
+ int[] range = entry.getValue();
+ if (range[0] <= lineNo && range[1] > lineNo) {
+ if (range[1] - range[0] < lineRangeSize || closest == null) {
+ closest = entry.getKey();
+ lineRangeSize = range[1] - range[0];
+ }
+ }
+ }
+ return closest;
+ }
+
+ // START KGU#705 2019-09-26: Enh. #738
+ /**
+ * Entry point for external components to get the given {@code element}
+ * consistently selected in the diagram.
+ *
+ * @param element - the {@link Element} to be selected
+ */
+ public void selectElement(Element element) {
+ if (element != null) {
+ Element sel = root.findSelected();
+ if (sel != null) {
+ sel.setSelected(false);
+ }
+ element.setSelected(true);
+ selected = element;
+ selectedDown = selected;
+ this.redraw(element);
+ if (codeHighlighter != null) {
+ codeHighlighter.removeAllHighlights();
+ }
+ this.highlightCodeForElement(element, false);
+ }
+ }
+ // END KGU#705 2019-09-26
+
+ /**
+ * Method: print
+ *
+ *
+ * This class is responsible for rendering a page using the provided
+ * parameters. The result will be a grid where each cell will be half an
+ * inch by half an inch.
+ *
+ * @param g a value of type Graphics
+ * @param pageFormat a value of type PageFormat
+ * @param page a value of type int
+ * @return a value of type int
+ */
+ public int print(Graphics g, PageFormat pageFormat, int page) {
+ if (page == 0) {
+ Graphics2D g2d = (Graphics2D) g;
+
+ g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
+
+ double sX = (pageFormat.getImageableWidth() - 1) / root.width;
+ double sY = (pageFormat.getImageableHeight() - 1) / root.height;
+ double sca = Math.min(sX, sY);
+ if (sca > 1) {
+ sca = 1;
+ }
+ g2d.scale(sca, sca);
+
+ // START KGU#906 2021-01-06: Enh. #905 We don't want the triangles in the print
+ //root.draw(g, null);
+ root.draw(g, null, DrawingContext.DC_IMAGE_EXPORT);
+ // END KGU#906 2021-01-06
+
+ return (PAGE_EXISTS);
+ } else {
+ return (NO_SUCH_PAGE);
+ }
+ }
+
+ /*========================================
* New method
*========================================*/
- /**
- * Replaces the current {@link #root} by a new empty {@link Root} unless the
- * current {@link #root} is being executed or the user refuses to make a
- * decision about unsaved changes.
- */
- public void newNSD() {
- // START KGU#157 2016-03-16: Bugfix #131 - Precaution against replacement if under execution
- if (!this.checkRunning()) {
- return; // Don't proceed if the root is being executed
- } // END KGU#157 2016-03-16
-
- // START KGU#48 2015-10-17: Arranger support
- Root oldRoot = root;
- // END KGU#48 2015-10-17
- // only save if something has been changed
- // START KGU#534 2018-06-27: Bugfix #552 We should not proceed if the user canceled the saving
- //saveNSD(true);
- if (!saveNSD(true)) {
- return;
- }
- // END KGU#534 2018-06-27
-
- // create an empty diagram
- root = new Root();
- //root.highlightVars = Element.E_VARHIGHLIGHT;
- // START KGU 2015-10-29: This didn't actually make sense
- //root.hasChanged=true;
- // END KGU 2015-10-29
- // START KGU#183 2016-04-23: Bugfix #155, Issue #169
- // We must not forget to clear a previous selection
- //this.selected = this.selectedDown = this.selectedUp = null;
- this.selectedDown = null;
- this.selected = root;
- root.setSelected(true);
- // END KGU#183 2016-04-23
- // START KGU#456 2017-11-20: Issue #452
- root.updateTutorialQueue(AnalyserPreferences.getOrderedGuideCodes());
- // END KGU#456 2017-11-20
- redraw();
- analyse();
- // START KGU#48 2015-10-17: Arranger support
- if (oldRoot != null) {
- oldRoot.notifyReplaced(root);
- }
- // END KGU#48 2015-10-17
- // START KGU#705 2019-09-23: Enh. #738
- this.updateCodePreview();
- // END KGU#705 2019-09-23
- }
-
-
- /*========================================
+ /**
+ * Replaces the current {@link #root} by a new empty {@link Root} unless the
+ * current {@link #root} is being executed or the user refuses to make a
+ * decision about unsaved changes.
+ */
+ public void newNSD() {
+ // START KGU#157 2016-03-16: Bugfix #131 - Precaution against replacement if under execution
+ if (!this.checkRunning()) {
+ return; // Don't proceed if the root is being executed
+ } // END KGU#157 2016-03-16
+
+ // START KGU#48 2015-10-17: Arranger support
+ Root oldRoot = root;
+ // END KGU#48 2015-10-17
+ // only save if something has been changed
+ // START KGU#534 2018-06-27: Bugfix #552 We should not proceed if the user canceled the saving
+ //saveNSD(true);
+ if (!saveNSD(true)) {
+ return;
+ }
+ // END KGU#534 2018-06-27
+
+ // create an empty diagram
+ root = new Root();
+ // START KGU#183 2016-04-23: Bugfix #155, Issue #169
+ // We must not forget to clear a previous selection
+ //this.selected = this.selectedDown = this.selectedUp = null;
+ this.selectedDown = null;
+ this.selected = root;
+ root.setSelected(true);
+ // END KGU#183 2016-04-23
+ // START KGU#456 2017-11-20: Issue #452
+ root.updateTutorialQueue(AnalyserPreferences.getOrderedGuideCodes());
+ // END KGU#456 2017-11-20
+ redraw();
+ analyse();
+ // START KGU#48 2015-10-17: Arranger support
+ if (oldRoot != null) {
+ oldRoot.notifyReplaced(root);
+ }
+ // END KGU#48 2015-10-17
+ // START KGU#705 2019-09-23: Enh. #738
+ this.updateCodePreview();
+ // END KGU#705 2019-09-23
+ }
+
+
+ /*========================================
* Open method
*========================================*/
- /**
- * Action method to have the user select an NSD or arrangement file to be
- * loaded (which is going to replace the current {@link #root}. Does nothing
- * if there is a pending execution.
- *
- * @see #openNSD(String)
- * @see #openNsdOrArr(String)
- */
- public void openNSD() {
- // START KGU 2015-10-17: This will be done by openNSD(String) anyway - once is enough!
- // only save if something has been changed
- //saveNSD(true);
- // END KGU 2015-10-17
-
- // START KGU#157 2016-03-16: Bugfix #131 - Precaution against replacement if under execution
- if (!this.checkRunning()) {
- return; // Don't proceed if the root is being executed
- } // END KGU#157 2016-03-16
-
- // open an existing file
- // create dialog
- JFileChooser dlgOpen = new JFileChooser();
- // START KGU#287 2017-01-09: Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
- GUIScaler.rescaleComponents(dlgOpen);
- // END KGU#287 2017-01-09
- dlgOpen.setDialogTitle(Menu.msgTitleOpen.getText());
- // set directory
- if (root.getFile() != null) {
- dlgOpen.setCurrentDirectory(root.getFile());
- } else {
- dlgOpen.setCurrentDirectory(currentDirectory);
- }
- // config dialogue
- // START KGU 2016-01-15: Enh. #110 - select the provided filter
- //dlgOpen.addChoosableFileFilter(new StructogramFilter());
- // START KGU#802 2020-02-16: Issue #815
- //StructogramFilter filter = new StructogramFilter();
- //dlgOpen.addChoosableFileFilter(filter);
- StructorizerFilter filter = new StructorizerFilter();
- dlgOpen.addChoosableFileFilter(filter);
- dlgOpen.addChoosableFileFilter(new StructogramFilter());
- // END KGU#802 2020-02-16
- // START KGU#289 2016-11-15: Enh. #290 (allow arrangement files to be selected)
- dlgOpen.addChoosableFileFilter(new ArrFilter());
- dlgOpen.addChoosableFileFilter(new ArrZipFilter());
- // END KGU#289 2016-11-15
- dlgOpen.setFileFilter(filter);
- // END KGU 2016-01-15
- // show & get result
- int result = dlgOpen.showOpenDialog(this.getFrame());
- // react on result
- if (result == JFileChooser.APPROVE_OPTION) {
- /*
- NSDParser parser = new NSDParser();
- root = parser.parse(dlgOpen.getSelectedFile().toURI().toString());
- root.filename=dlgOpen.getSelectedFile().getAbsoluteFile().toString();
- currentDirectory = new File(root.filename);
- redraw();
- */
- // START KGU#289/KGU#316 2016-11-15/2016-12-28: Enh. #290/#318 (Arranger file support)
- //openNSD(dlgOpen.getSelectedFile().getAbsoluteFile().toString());
- openNsdOrArr(dlgOpen.getSelectedFile().getAbsoluteFile().toString());
- // END KGU#289/KGU#316 2016-11-15/2016-12-28
- }
- }
-
- // START KGU#289/KGU#316 2016-11-15/2016-12-28: Enh. #290/#318: Better support for Arranger files
- /**
- * Attempts to open (load) the file specified by {@code _filepath} as .nsd,
- * .arr, or .arrz file.
- * If none of the expected file extensions match then an empty string is
- * returned.
- *
- * @param _filepath - the path of the file to be loaded
- * @return - the file extension
- * @see #openNSD()
- * @see #openNSD(String)
- */
- public String openNsdOrArr(String _filepath) {
- String ext = ExtFileFilter.getExtension(_filepath);
- if (ext.equals("arr") || ext.equals("arrz")) {
- loadArrangement(new File(_filepath));
- } // START KGU#521 2018-06-08: Bugfix #536
- //else {
- else if (ext.equals("nsd")) {
- // START KGU#521 2018-06-08: Bugfix #536
- this.openNSD(_filepath);
- } // START KGU#521 2018-06-08: Bugfix #536
- else {
- ext = "";
- }
- // END KGU#521 2018-06-08
- return ext;
- }
- // END KGU#316 2016-12-28
-
- /**
- * Method is to open an NSD file (not an arrangement file!) the path of
- * which is given by {@code _filename}.
- * If arrangement file are also to be accepted then use
- * {@link #openNsdOrArr(String)} instead.
- *
- * @param _filename - file path of an NSD file
- * @see #openNsdOrArr(String)
- */
- public void openNSD(String _filename) {
- // START KGU#48 2015-10-17: Arranger support
- Root oldRoot = this.root;
- // END KGU#48 2015-10-17
- // START KGU#111 2015-12-16: Bugfix #63: No error messages on failed load
- String errorMessage = Menu.msgErrorNoFile.getText();
- // END KGU#111 2015-12-16
- // START KGU#901 2021-01-22: Issue #901 WAIT_CURSOR on time-consuming actions
- Cursor origCursor = getCursor();
- setCursor(new Cursor(Cursor.WAIT_CURSOR));
- // END KGU#901 2021-01-22
- try {
- File f = new File(_filename);
- //System.out.println(f.toURI().toString());
- if (f.exists()) {
- // START KGU#901 2021-01-22: Issue #901 WAIT_CURSOR on time-consuming actions
- setCursor(new Cursor(Cursor.WAIT_CURSOR));
- // END KGU#901 2021-01-22
- // save current diagram (only if something has been changed)
- saveNSD(true);
-
- // open an existing file
- NSDParser parser = new NSDParser();
- //boolean hil = root.highlightVars;
- // START KGU#363 2017-05-21: Issue #372 API change
- //root = parser.parse(f.toURI().toString());
- root = parser.parse(f);
- // END KGU#363 2017-05-21
- //root.highlightVars = hil;
- if (Element.E_VARHIGHLIGHT) {
- root.retrieveVarNames(); // Initialise the variable table, otherwise the highlighting won't work
- }
- root.filename = _filename;
- currentDirectory = new File(root.filename);
- addRecentFile(root.filename);
-
- // START KGU#183 2016-04-23: Issue #169
- selected = root;
- root.setSelected(true);
- // END KGU#183 2016-04-23
- redraw();
- analyse();
- // START KGU#456 2017-11-20: Issue #452
- root.updateTutorialQueue(AnalyserPreferences.getOrderedGuideCodes());
- // END KGU#456 2017-11-20
- // START KGU#48 2015-10-17: Arranger support
- if (oldRoot != null) {
- oldRoot.notifyReplaced(root);
- }
- // END KGU#48 2015-10-17
- // START KGU#111 2015-12-16: Bugfix #63: No error messages on failed load
- errorMessage = null;
- // END KGU#111 2015-12-16
-
- // START KGU#362 2017-03-28: Issue #370
- if (root.storedParserPrefs != null) {
- this.handleKeywordDifferences(false);
- }
- // END KGU#362 2017-03-28
- // START KGU#705 2019-09-23: Enh. #738
- this.updateCodePreview();
- // END KGU#705 2019-09-23
- }
- } catch (Exception e) {
- //e.printStackTrace();
- // START KGU#111 2015-12-16: Bugfix #63: No error messages on failed load
- //System.out.println(e.getMessage());
- errorMessage = e.getLocalizedMessage();
- if (errorMessage == null) {
- errorMessage = e.getMessage();
- }
- if (errorMessage == null || errorMessage.isEmpty()) {
- errorMessage = e.toString();
- }
- Level level = Level.SEVERE;
- if (e instanceof java.util.ConcurrentModificationException) {
- level = Level.WARNING;
- }
- logger.log(level, "openNSD(\"" + _filename + "\"): ", e);
- // END KGU#111 2015-12-16
- } // START KGU#901 2021-01-22: Issue #901 WAIT_CURSOR on time-consuming actions
- finally {
- setCursor(origCursor);
- }
- // END KGU#901 2021-01-22
- // START KGU#111 2015-12-16: Bugfix #63: No error messages on failed load
- if (errorMessage != null) {
- JOptionPane.showMessageDialog(this.getFrame(), "\"" + _filename + "\": " + errorMessage,
- Menu.msgTitleLoadingError.getText(),
- JOptionPane.ERROR_MESSAGE);
- }
- // END KGU#111 2015-12-16
- // START KGU#444/KGU#618 2018-12-18: Issue #417, #649
- this.adaptScrollUnits();
- // END KGU#444/KGU#618 2018-12-18
- }
-
- // START KGU#362 2017-03-28: Issue #370
- private boolean handleKeywordDifferences(boolean isChangeRequest) {
- StringList ignoreCaseInfo = root.storedParserPrefs.get("ignoreCase");
- boolean wasCaseIgnored = ignoreCaseInfo != null && ignoreCaseInfo.getText().equals("true");
- StringList replacements = new StringList();
- for (HashMap.Entry entry : root.storedParserPrefs.entrySet()) {
- String storedValue = entry.getValue().concatenate();
- // START KGU#288 2016-11-06: Issue #279 - Method getOrDefault() missing in OpenJDK
- //String newValue = CodeParser.getKeywordOrDefault(entry.getKey(), "");
- String currentValue = (entry.getKey().equals("ignoreCase"))
- ? Boolean.toString(CodeParser.ignoreCase)
- : CodeParser.getKeywordOrDefault(entry.getKey(), "");
- // END KGU#288 2016-11-06
- if (!storedValue.equals(currentValue)) {
- replacements.add(" " + entry.getKey() + ": \"" + storedValue + "\" ≠ \"" + currentValue + "\"");
- }
- }
- String[] options = {
- Menu.lblRefactorNow.getText(),
- (isChangeRequest ? Menu.lblAllowChanges : Menu.lblAdoptPreferences).getText(),
- Menu.lblLeaveAsIs.getText()
- };
- String[] optionTexts = {
- Menu.msgRefactorNow.getText(),
- (isChangeRequest ? Menu.msgAllowChanges : Menu.msgAdoptPreferences).getText(),
- Menu.msgLeaveAsIs.getText()
- };
- String menuText = "";
- for (int i = 0; i < optionTexts.length; i++) {
- menuText += (char) ('a' + i) + ") " + optionTexts[i] + (i + 1 < optionTexts.length ? "," : ".") + "\n";
- }
- int answer = JOptionPane.showOptionDialog(this.getFrame(),
- Menu.msgKeywordsDiffer.getText().replace("%1", "\n" + replacements.getText() + "\n").replace("%2", menuText),
- Menu.msgTitleQuestion.getText(), JOptionPane.OK_CANCEL_OPTION,
- JOptionPane.QUESTION_MESSAGE,
- null,
- options, options[0]);
- boolean goAhead = false;
- switch (answer) {
- case 0: // Refactor the current diagram
- {
- HashMap storedParserPrefs = root.storedParserPrefs;
- root.storedParserPrefs = null;
- refactorDiagrams(storedParserPrefs, false, wasCaseIgnored);
- goAhead = true;
- }
- break;
- case 1:
- if (isChangeRequest) {
- // drop the old keyword information
- root.storedParserPrefs = null;
- } else {
- // Refactor all the other diagrams
- // Cache the current parser preferences
- HashMap splitPrefs = new HashMap();
- // and adopt the stored preferences of the diagram
- for (String key : CodeParser.keywordSet()) {
- splitPrefs.put(key, Element.splitLexically(CodeParser.getKeywordOrDefault(key, ""), false));
- StringList stored = root.storedParserPrefs.get(key);
- if (stored != null) {
- CodeParser.setKeyword(key, stored.concatenate());
- }
- }
- boolean tmpIgnoreCase = CodeParser.ignoreCase;
- CodeParser.ignoreCase = wasCaseIgnored;
- try {
- Ini.getInstance().save();
- } catch (Exception ex) {
- logger.log(Level.SEVERE, "Ini.getInstance().save()", ex);
- }
- // Refactor the diagrams
- refactorDiagrams(splitPrefs, true, tmpIgnoreCase);
- root.storedParserPrefs = null;
- if (Arranger.hasInstance()) {
- Arranger.getInstance().redraw();
- }
-
- offerStructPrefAdaptation(splitPrefs);
- }
- goAhead = true;
- break;
- case 2:
- if (!isChangeRequest) {
- goAhead = true;
- }
- break;
- }
- return goAhead;
- }
- // END KGU#362 2017-03-28
-
- // START KGU#289 2016-11-15: Enh. #290 (Aranger file support
- private void loadArrangement(File arrFile) {
- Arranger arr = Arranger.getInstance();
- // START KGU#671 2019-03-01: Bugfix #693 - common existence check
- //String errorMsg = arr.loadArrangement((Mainform)NSDControl.getFrame(), arrFile.toString());
- String errorMsg = "";
- if (!arrFile.exists()) {
- errorMsg = Menu.msgErrorNoFile.getText();
- } else {
- // START KGU#901 2020-12-29: Issue #901 WAIT_CURSOR on time-consuming actions
- //errorMsg = arr.loadArrangement((Mainform)this.getFrame(), arrFile);
- Cursor origCursor = getCursor();
- try {
- setCursor(new Cursor(Cursor.WAIT_CURSOR)); // Possibly this should have done Surface?
- errorMsg = arr.loadArrangement((Mainform) this.getFrame(), arrFile);
- } finally {
- setCursor(origCursor);
- }
- // END KGU#901 2020-12-29
- }
- // END KGU#671 2019-03-01
- if (!errorMsg.isEmpty()) {
- JOptionPane.showMessageDialog(this.getFrame(), "\"" + arrFile + "\": " + errorMsg,
- Menu.msgTitleLoadingError.getText(),
- JOptionPane.ERROR_MESSAGE);
- } else {
- arr.setVisible(true);
- // START KGU#316 2016-12-28: Enh. #318
- addRecentFile(arrFile.getAbsolutePath());
- this.currentDirectory = arrFile;
- // END KGU#316 2016-12-28
- }
- }
- // END KGU#289 2016-11-15
-
- /*========================================
+ /**
+ * Action method to have the user select an NSD or arrangement file to be
+ * loaded (which is going to replace the current {@link #root}. Does nothing
+ * if there is a pending execution.
+ *
+ * @see #openNSD(String)
+ * @see #openNsdOrArr(String)
+ */
+ public void openNSD() {
+ // START KGU 2015-10-17: This will be done by openNSD(String) anyway - once is enough!
+ // only save if something has been changed
+ //saveNSD(true);
+ // END KGU 2015-10-17
+
+ // START KGU#157 2016-03-16: Bugfix #131 - Precaution against replacement if under execution
+ if (!this.checkRunning()) {
+ return; // Don't proceed if the root is being executed
+ } // END KGU#157 2016-03-16
+
+ // open an existing file
+ // create dialog
+ JFileChooser dlgOpen = new JFileChooser();
+ // START KGU#287 2017-01-09: Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
+ GUIScaler.rescaleComponents(dlgOpen);
+ // END KGU#287 2017-01-09
+ dlgOpen.setDialogTitle(Menu.msgTitleOpen.getText());
+ // set directory
+ if (root.getFile() != null) {
+ dlgOpen.setCurrentDirectory(root.getFile());
+ } else {
+ dlgOpen.setCurrentDirectory(currentDirectory);
+ }
+ // config dialogue
+ // START KGU 2016-01-15: Enh. #110 - select the provided filter
+ //dlgOpen.addChoosableFileFilter(new StructogramFilter());
+ // START KGU#802 2020-02-16: Issue #815
+ //StructogramFilter filter = new StructogramFilter();
+ //dlgOpen.addChoosableFileFilter(filter);
+ StructorizerFilter filter = new StructorizerFilter();
+ dlgOpen.addChoosableFileFilter(filter);
+ dlgOpen.addChoosableFileFilter(new StructogramFilter());
+ // END KGU#802 2020-02-16
+ // START KGU#289 2016-11-15: Enh. #290 (allow arrangement files to be selected)
+ dlgOpen.addChoosableFileFilter(new ArrFilter());
+ dlgOpen.addChoosableFileFilter(new ArrZipFilter());
+ // END KGU#289 2016-11-15
+ dlgOpen.setFileFilter(filter);
+ // END KGU 2016-01-15
+ // show & get result
+ int result = dlgOpen.showOpenDialog(this.getFrame());
+ // react on result
+ if (result == JFileChooser.APPROVE_OPTION) {
+ // START KGU#289/KGU#316 2016-11-15/2016-12-28: Enh. #290/#318 (Arranger file support)
+ //openNSD(dlgOpen.getSelectedFile().getAbsoluteFile().toString());
+ openNsdOrArr(dlgOpen.getSelectedFile().getAbsoluteFile().toString());
+ // END KGU#289/KGU#316 2016-11-15/2016-12-28
+ }
+ }
+
+ // START KGU#289/KGU#316 2016-11-15/2016-12-28: Enh. #290/#318: Better support for Arranger files
+ /**
+ * Attempts to open (load) the file specified by {@code _filepath} as .nsd,
+ * .arr, or .arrz file.
+ * If none of the expected file extensions match then an empty string is
+ * returned.
+ *
+ * @param _filepath - the path of the file to be loaded
+ * @return - the file extension
+ * @see #openNSD()
+ * @see #openNSD(String)
+ */
+ public String openNsdOrArr(String _filepath) {
+ String ext = ExtFileFilter.getExtension(_filepath);
+ if (ext.equals("arr") || ext.equals("arrz")) {
+ loadArrangement(new File(_filepath));
+ } // START KGU#521 2018-06-08: Bugfix #536
+ //else {
+ else if (ext.equals("nsd")) {
+ // START KGU#521 2018-06-08: Bugfix #536
+ this.openNSD(_filepath);
+ } // START KGU#521 2018-06-08: Bugfix #536
+ else {
+ ext = "";
+ }
+ // END KGU#521 2018-06-08
+ return ext;
+ }
+ // END KGU#316 2016-12-28
+
+ /**
+ * Method is to open an NSD file (not an arrangement file!) the path of
+ * which is given by {@code _filename}.
+ * If arrangement file are also to be accepted then use
+ * {@link #openNsdOrArr(String)} instead.
+ *
+ * @param _filename - file path of an NSD file
+ * @see #openNsdOrArr(String)
+ */
+ public void openNSD(String _filename) {
+ // START KGU#48 2015-10-17: Arranger support
+ Root oldRoot = this.root;
+ // END KGU#48 2015-10-17
+ // START KGU#111 2015-12-16: Bugfix #63: No error messages on failed load
+ String errorMessage = Menu.msgErrorNoFile.getText();
+ // END KGU#111 2015-12-16
+ // START KGU#901 2021-01-22: Issue #901 WAIT_CURSOR on time-consuming actions
+ Cursor origCursor = getCursor();
+ setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ // END KGU#901 2021-01-22
+ try {
+ File f = new File(_filename);
+ //System.out.println(f.toURI().toString());
+ if (f.exists()) {
+ // START KGU#901 2021-01-22: Issue #901 WAIT_CURSOR on time-consuming actions
+ setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ // END KGU#901 2021-01-22
+ // save current diagram (only if something has been changed)
+ saveNSD(true);
+
+ // open an existing file
+ NSDParser parser = new NSDParser();
+ //boolean hil = root.highlightVars;
+ // START KGU#363 2017-05-21: Issue #372 API change
+ //root = parser.parse(f.toURI().toString());
+ root = parser.parse(f);
+ // END KGU#363 2017-05-21
+ //root.highlightVars = hil;
+ if (Element.E_VARHIGHLIGHT) {
+ root.retrieveVarNames(); // Initialise the variable table, otherwise the highlighting won't work
+ }
+ root.filename = _filename;
+ currentDirectory = new File(root.filename);
+ addRecentFile(root.filename);
+
+ // START KGU#183 2016-04-23: Issue #169
+ selected = root;
+ root.setSelected(true);
+ // END KGU#183 2016-04-23
+ redraw();
+ analyse();
+ // START KGU#456 2017-11-20: Issue #452
+ root.updateTutorialQueue(AnalyserPreferences.getOrderedGuideCodes());
+ // END KGU#456 2017-11-20
+ // START KGU#48 2015-10-17: Arranger support
+ if (oldRoot != null) {
+ oldRoot.notifyReplaced(root);
+ }
+ // END KGU#48 2015-10-17
+ // START KGU#111 2015-12-16: Bugfix #63: No error messages on failed load
+ errorMessage = null;
+ // END KGU#111 2015-12-16
+
+ // START KGU#362 2017-03-28: Issue #370
+ if (root.storedParserPrefs != null) {
+ this.handleKeywordDifferences(false);
+ }
+ // END KGU#362 2017-03-28
+ // START KGU#705 2019-09-23: Enh. #738
+ this.updateCodePreview();
+ // END KGU#705 2019-09-23
+ }
+ } catch (Exception e) {
+ //e.printStackTrace();
+ // START KGU#111 2015-12-16: Bugfix #63: No error messages on failed load
+ //System.out.println(e.getMessage());
+ errorMessage = e.getLocalizedMessage();
+ if (errorMessage == null) {
+ errorMessage = e.getMessage();
+ }
+ if (errorMessage == null || errorMessage.isEmpty()) {
+ errorMessage = e.toString();
+ }
+ Level level = Level.SEVERE;
+ if (e instanceof java.util.ConcurrentModificationException) {
+ level = Level.WARNING;
+ }
+ logger.log(level, "openNSD(\"" + _filename + "\"): ", e);
+ // END KGU#111 2015-12-16
+ }
+ // START KGU#901 2021-01-22: Issue #901 WAIT_CURSOR on time-consuming actions
+ finally {
+ setCursor(origCursor);
+ }
+ // END KGU#901 2021-01-22
+ // START KGU#111 2015-12-16: Bugfix #63: No error messages on failed load
+ if (errorMessage != null) {
+ JOptionPane.showMessageDialog(this.getFrame(), "\"" + _filename + "\": " + errorMessage,
+ Menu.msgTitleLoadingError.getText(),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ // END KGU#111 2015-12-16
+ // START KGU#444/KGU#618 2018-12-18: Issue #417, #649
+ this.adaptScrollUnits();
+ // END KGU#444/KGU#618 2018-12-18
+ }
+
+ // START KGU#362 2017-03-28: Issue #370
+ private boolean handleKeywordDifferences(boolean isChangeRequest) {
+ StringList ignoreCaseInfo = root.storedParserPrefs.get("ignoreCase");
+ boolean wasCaseIgnored = ignoreCaseInfo != null && ignoreCaseInfo.getText().equals("true");
+ StringList replacements = new StringList();
+ for (HashMap.Entry entry : root.storedParserPrefs.entrySet()) {
+ String storedValue = entry.getValue().concatenate();
+ // START KGU#288 2016-11-06: Issue #279 - Method getOrDefault() missing in OpenJDK
+ //String newValue = CodeParser.getKeywordOrDefault(entry.getKey(), "");
+ String currentValue = (entry.getKey().equals("ignoreCase"))
+ ? Boolean.toString(CodeParser.ignoreCase)
+ : CodeParser.getKeywordOrDefault(entry.getKey(), "");
+ // END KGU#288 2016-11-06
+ if (!storedValue.equals(currentValue)) {
+ replacements.add(" " + entry.getKey() + ": \"" + storedValue + "\" ≠ \"" + currentValue + "\"");
+ }
+ }
+ String[] options = {
+ Menu.lblRefactorNow.getText(),
+ (isChangeRequest ? Menu.lblAllowChanges : Menu.lblAdoptPreferences).getText(),
+ Menu.lblLeaveAsIs.getText()
+ };
+ String[] optionTexts = {
+ Menu.msgRefactorNow.getText(),
+ (isChangeRequest ? Menu.msgAllowChanges : Menu.msgAdoptPreferences).getText(),
+ Menu.msgLeaveAsIs.getText()
+ };
+ String menuText = "";
+ for (int i = 0; i < optionTexts.length; i++) {
+ menuText += (char) ('a' + i) + ") " + optionTexts[i] + (i + 1 < optionTexts.length ? "," : ".") + "\n";
+ }
+ int answer = JOptionPane.showOptionDialog(this.getFrame(),
+ Menu.msgKeywordsDiffer.getText().replace("%1", "\n" + replacements.getText() + "\n").replace("%2", menuText),
+ Menu.msgTitleQuestion.getText(), JOptionPane.OK_CANCEL_OPTION,
+ JOptionPane.QUESTION_MESSAGE,
+ null,
+ options, options[0]);
+ boolean goAhead = false;
+ switch (answer) {
+ case 0: // Refactor the current diagram
+ {
+ HashMap storedParserPrefs = root.storedParserPrefs;
+ root.storedParserPrefs = null;
+ refactorDiagrams(storedParserPrefs, false, wasCaseIgnored);
+ goAhead = true;
+ }
+ break;
+ case 1:
+ if (isChangeRequest) {
+ // drop the old keyword information
+ root.storedParserPrefs = null;
+ } else {
+ // Refactor all the other diagrams
+ // Cache the current parser preferences
+ HashMap splitPrefs = new HashMap();
+ // and adopt the stored preferences of the diagram
+ for (String key : CodeParser.keywordSet()) {
+ splitPrefs.put(key, Element.splitLexically(CodeParser.getKeywordOrDefault(key, ""), false));
+ StringList stored = root.storedParserPrefs.get(key);
+ if (stored != null) {
+ CodeParser.setKeyword(key, stored.concatenate());
+ }
+ }
+ boolean tmpIgnoreCase = CodeParser.ignoreCase;
+ CodeParser.ignoreCase = wasCaseIgnored;
+ try {
+ Ini.getInstance().save();
+ } catch (Exception ex) {
+ logger.log(Level.SEVERE, "Ini.getInstance().save()", ex);
+ }
+ // Refactor the diagrams
+ refactorDiagrams(splitPrefs, true, tmpIgnoreCase);
+ root.storedParserPrefs = null;
+ if (Arranger.hasInstance()) {
+ Arranger.getInstance().redraw();
+ }
+
+ offerStructPrefAdaptation(splitPrefs);
+ }
+ goAhead = true;
+ break;
+ case 2:
+ if (!isChangeRequest) {
+ goAhead = true;
+ }
+ break;
+ }
+ return goAhead;
+ }
+ // END KGU#362 2017-03-28
+
+ // START KGU#289 2016-11-15: Enh. #290 (Aranger file support
+ private void loadArrangement(File arrFile) {
+ Arranger arr = Arranger.getInstance();
+ // START KGU#671 2019-03-01: Bugfix #693 - common existence check
+ //String errorMsg = arr.loadArrangement((Mainform)NSDControl.getFrame(), arrFile.toString());
+ String errorMsg = "";
+ if (!arrFile.exists()) {
+ errorMsg = Menu.msgErrorNoFile.getText();
+ } else {
+ // START KGU#901 2020-12-29: Issue #901 WAIT_CURSOR on time-consuming actions
+ //errorMsg = arr.loadArrangement((Mainform)this.getFrame(), arrFile);
+ Cursor origCursor = getCursor();
+ try {
+ setCursor(new Cursor(Cursor.WAIT_CURSOR)); // Possibly this should have done Surface?
+ errorMsg = arr.loadArrangement((Mainform) this.getFrame(), arrFile);
+ } finally {
+ setCursor(origCursor);
+ }
+ // END KGU#901 2020-12-29
+ }
+ // END KGU#671 2019-03-01
+ if (!errorMsg.isEmpty()) {
+ JOptionPane.showMessageDialog(this.getFrame(), "\"" + arrFile + "\": " + errorMsg,
+ Menu.msgTitleLoadingError.getText(),
+ JOptionPane.ERROR_MESSAGE);
+ } else {
+ arr.setVisible(true);
+ // START KGU#316 2016-12-28: Enh. #318
+ addRecentFile(arrFile.getAbsolutePath());
+ this.currentDirectory = arrFile;
+ // END KGU#316 2016-12-28
+ }
+ }
+ // END KGU#289 2016-11-15
+
+ /*========================================
* SaveAll method
*========================================*/
- /**
- * Saves all NSD (and arrangement) files without file association or with
- * unsaved changes in a serial action.
- */
- public void saveAllNSD() // START KGU#320 2017-01-04: Bugfix #321(?) We need a possibility to save a different root
- {
- startSerialMode();
- // START KGU#901 2020-12-30: Issue #901
- Cursor origCursor = getCursor();
- // END KGU#901 2020-12-30
- try {
- if ((saveNSD(false)
- || JOptionPane.showConfirmDialog(this.getFrame(),
- Menu.msgCancelAll.getText(),
- Menu.msgTitleSave.getText(),
- JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION)
- && Arranger.hasInstance()) {
- // START KGU#901 2020-12-30: Issue #901
- setCursor(new Cursor(Cursor.WAIT_CURSOR));
- // END KGU#901 2020-12-30
- Arranger.getInstance().saveAll(this.getFrame());
- }
- } finally {
- // START KGU#901 2020-12-30: Issue #901
- setCursor(origCursor);
- // END KGU#901 2020-12-30
- endSerialMode();
- }
- }
-
- /*========================================
+ /**
+ * Saves all NSD (and arrangement) files without file association or with
+ * unsaved changes in a serial action.
+ */
+ public void saveAllNSD()
+ {
+ startSerialMode();
+ // START KGU#901 2020-12-30: Issue #901
+ Cursor origCursor = getCursor();
+ // END KGU#901 2020-12-30
+ try {
+ if ((saveNSD(false)
+ || JOptionPane.showConfirmDialog(this.getFrame(),
+ Menu.msgCancelAll.getText(),
+ Menu.msgTitleSave.getText(),
+ JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION)
+ && Arranger.hasInstance()) {
+ // START KGU#901 2020-12-30: Issue #901
+ setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ // END KGU#901 2020-12-30
+ Arranger.getInstance().saveAll(this.getFrame());
+ }
+ } finally {
+ // START KGU#901 2020-12-30: Issue #901
+ setCursor(origCursor);
+ // END KGU#901 2020-12-30
+ endSerialMode();
+ }
+ }
+
+ /*========================================
* SaveAs method
*========================================*/
- /**
- * Tries to save the current {@link Root} under a new path. Opens a
- * FileChooser for this purpose
- *
- * @return true if the diagram was saved, false otherwise.
- */
- public boolean saveAsNSD() // START KGU#320 2017-01-04: Bugfix #321(?) We need a possibility to save a different root
- {
- // START KGU#893 2020-12-20: Bugfix #892 - Arrangment group members must be cloned!
- //return saveAsNSD(this.root);
- Root rootToSave = this.root;
- // Check membership in named group: if there is any, clone the Root
- if (Arranger.hasInstance()
- && !Arranger.getInstance().getGroupsFromRoot(root, true).isEmpty()) {
- rootToSave = (Root) root.copy();
- }
- boolean done = saveAsNSD(rootToSave);
- if (done && rootToSave != this.root) {
- JOptionPane.showMessageDialog(
- this.getFrame(),
- Menu.msgRootCloned.getText().replace("%1", this.root.getSignatureString(false, false))
- .replace("%2", rootToSave.getSignatureString(true, false)));
- this.setRoot(rootToSave, true, true);
- }
- return done;
- // END KGU#893 2020-12-20
- }
-
- /**
- * Tries to save the {@link Root} given as {@code root} under a new path.
- * Opens a FileChooser for this purpose.
- *
- * @param root - the diagram to be saved.
- * @return true if the diagram was saved, false otherwise
- */
- private boolean saveAsNSD(Root root) // END KGU#320 2017-01-04
- {
- // START KGU#911 2021-01-10: Enh. #910 suppress saving
- if (root.isRepresentingDiagramController()) {
- return true; // Fake success
- }
- // END KGU#911 2021-01-10
- // propose name
- String nsdName = root.proposeFileName();
-
- // START KGU#534/KGU#553 2018-07-10: Enh. #552, issue #557 - special treatment for mass serial save
- File dir = this.currentDirectory;
- if (dir != null && isInSerialMode() && getSerialDecision(SerialDecisionAspect.SERIAL_SAVE) == SerialDecisionStatus.YES_TO_ALL) {
- // We have a target directory and the user has already confirmed to save all with proposed names
- if (!dir.isDirectory()) {
- // A file name had been stored as current directory, so reduce it to its directory
- dir = dir.getParentFile();
- }
- // Accomplish the proposed file name...
- File f = new File(dir.getAbsolutePath() + File.separator + nsdName + ".nsd");
- // ... check whether a file with this name has existed
- int answer = this.checkOverwrite(f, true);
- if (answer == 0) {
- // Okay, we are entitled to overwrite
- root.filename = f.getAbsolutePath();
- root.shadowFilepath = null;
- return doSaveNSD(root);
- } else if (answer < 0) {
- // User wants to cancel the serial saving
- return false;
- } else if (answer == 2) {
- // Skip this file here, no further attempt
- return true;
- }
- }
- // END KGU#534/KGU#553 2018-07-10
-
- // Now we are either not in serial mode or a name conflict is to be solved via file chooser
- JFileChooser dlgSave = new JFileChooser();
-
- // START KGU#553 2018-07-13: Issue #557
- // Add a checkbox to adhere to the proposed names for all remaining roots if we are in serial mode
- JCheckBox chkAcceptProposals = addSerialAccessory(dlgSave);
- // END KGU#553 2018-07-13
- // START KGU#287 2017-01-09: Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
- GUIScaler.rescaleComponents(dlgSave);
- // END KGU#287 2017-01-09
- dlgSave.setDialogTitle(Menu.msgTitleSaveAs.getText());
- File rootFile = root.getFile();
- // set directory
- if (rootFile != null) {
- dlgSave.setCurrentDirectory(rootFile);
- } else {
- dlgSave.setCurrentDirectory(currentDirectory);
- }
-
- dlgSave.setSelectedFile(new File(nsdName));
- dlgSave.addChoosableFileFilter(new StructogramFilter());
-
- // START KGU#248 2016-09-15: Bugfix #244 - allow more than one chance
- //int result = dlgSave.showSaveDialog(this);
- int result = JFileChooser.ERROR_OPTION;
- do {
- result = dlgSave.showSaveDialog(this.getFrame());
- // END KGU#248 2016-9-15
- if (result == JFileChooser.APPROVE_OPTION) {
- String newFilename = dlgSave.getSelectedFile().getAbsoluteFile().toString();
- if (!newFilename.substring(newFilename.length() - 4, newFilename.length()).toLowerCase().equals(".nsd")) {
- newFilename += ".nsd";
- }
- if (chkAcceptProposals != null && chkAcceptProposals.isSelected()) {
- setSerialDecision(SerialDecisionAspect.SERIAL_SAVE, true);
- }
-
- File f = new File(newFilename);
- int writePerm = checkOverwrite(f, false);
-
- if (writePerm < 0) {
- // Cancelled all
- return false;
- } else if (writePerm == 2) {
- // No further attempt
- return true;
- } else if (writePerm != 0) {
- // START KGU#248 2016-09-15: Bugfix #244 - message no longer needed (due to new loop)
- //JOptionPane.showMessageDialog(this, Menu.msgRepeatSaveAttempt.getText());
- result = JFileChooser.ERROR_OPTION;
- // END KGU#248 2016-09-15
- } else {
- root.filename = newFilename;
- // START KGU#316 2016-12-28: Enh. #318
- root.shadowFilepath = null;
- // END KGU#316 2016-12-28
- // START KGU#874 2020-10-19: Enh. #875 set the signature from file name for dummies
- replaceDummyHeader(root, f);
- // END KGU#874 2020-10-19
- // START KGU#94 2015.12.04: out-sourced to auxiliary method
- // START KGU#320 2017-01-04: Bugfix #321(?) Need a parameter now
- //doSaveNSD();
- doSaveNSD(root);
- // END KGU#320 2017-01-04
- // END KGU#94 2015-12-04
- // START KGU#273 2016-10-07: Bugfix #263 - remember the directory as current directory
- this.currentDirectory = f;
- // END KGU#273 2016-10-07
- }
- }
- // START KGU#248 2016-09-15: Bugfix #244 - allow to leave the new loop
-// else
-// {
-// // User cancelled the file dialog -> leave the loop
-// result = JFileChooser.CANCEL_OPTION;
-// }
- } while (result == JFileChooser.ERROR_OPTION);
- // END KGU#248 2016-09-15
-
- return result != JFileChooser.CANCEL_OPTION;
- }
-
- // START KGU#874 2020-10-19: Issue #875 - try to make sense from the filename
- /**
- * IN case {@code _root} has a dummy header (empty or "???"), we try to
- * derive a header from the name of the chosen target file {@code _file}
- *
- * @param _root - the {@link Root} to be saved
- * @param _file - the chosen target file
- */
- private void replaceDummyHeader(Root _root, File _file) {
- String header = _root.getMethodName().trim();
- if (header.isEmpty() || header.equals("???")) {
- header = _file.getName();
- // Remove the ".nsd" extension
- header = header.substring(0, header.length() - 4);
- String argList = "";
- if (_root.isSubroutine()) {
- header = header.split(Matcher.quoteReplacement("" + Element.E_FILENAME_SIG_SEPARATOR), -1)[0];
- // Try to infer arguments and result type
- IRoutinePool pool = null;
- if (Arranger.hasInstance()) {
- pool = Arranger.getInstance();
- }
- StringList vars = _root.getUninitializedVars(pool);
- // TODO: Infer the argument types and the result type
- argList = "(" + vars.concatenate(", ") + ")";
- vars = _root.getVarNames();
- // START KGU#886 2020-12-10: Issue #884
- //if (vars.contains(header) || vars.contains("result", false)) {
- IElementVisitor returnFinder = new IElementVisitor() {
- private int retLen = CodeParser.getKeyword("preReturn").length();
-
- @Override
- public boolean visitPreOrder(Element _ele) {
- if (_ele instanceof Jump) {
- StringList lines = _ele.getUnbrokenText();
- for (int i = 0; i < lines.count(); i++) {
- String line = lines.get(i);
- if (Jump.isReturn(line)) {
- // Stops and returns false if a value is returned
- // TODO Try to identify the result type
- return line.substring(retLen).trim().isEmpty();
- }
- }
- }
- return true;
- }
-
- @Override
- public boolean visitPostOrder(Element _ele) {
- return true;
- }
-
- };
- boolean lastElReturnsVal = false;
- if (root.children.getSize() > 0) {
- Element lastEl = root.children.getElement(root.children.getSize() - 1);
- if (lastEl instanceof Instruction) {
- int retLen = CodeParser.getKeyword("preReturn").length();
- StringList lines = lastEl.getUnbrokenText();
- for (int i = 0; i < lines.count(); i++) {
- String line = lines.get(i);
- if (Jump.isReturn(line)) {
- // Stops and detects if a value is returned
- lastElReturnsVal = !line.substring(retLen).trim().isEmpty();
- break;
- }
- }
- }
- }
- if (vars.contains(header) || vars.contains("result", false)
- || lastElReturnsVal
- || !_root.children.traverse(returnFinder)) {
- // END KGU#886 2020-12-10: Issue #884
- // TODO try to identify the type
- argList += ": ???";
- }
- }
- if (Function.testIdentifier(header, false, null)) {
- // START KGU#886 2020-12-10: Bugfix #884
- //root.setText(header + argList);
- root.addUndo();
- root.setText(header + argList);
- this.analyse();
- // END KGU#886 2020-12-10
- this.invalidateAndRedraw();
- }
- }
-
- }
- // END KGU#874 2020-10-19
-
- /**
- * In case of serial mode adds a checkbox to {@code fileChooser}
- *
- * @param fileChooser - the {@link JFileChooser} to be decorated if in
- * serial mode.
- * @return the checkbox if it was created
- */
- private JCheckBox addSerialAccessory(JFileChooser fileChooser) {
- JCheckBox chkAcceptProposals = null;
- if (isInSerialMode() && getSerialDecision(SerialDecisionAspect.SERIAL_SAVE) == SerialDecisionStatus.INDIVIDUAL) {
- // Unfortunateley, the accessory is usally placed right of the file view.
- // So we split the caption for the checkbox to be added into words and
- // and "verticalize" the text by distributing the words over as many
- // vertically boxed labels as needed.
- JPanel pnlAccept = new JPanel();
- pnlAccept.setLayout(new BoxLayout(pnlAccept, BoxLayout.PAGE_AXIS));
- String[] words = Menu.lblAcceptProposedNames.getText().split("\\s+");
- chkAcceptProposals = new JCheckBox(words[0]);
- // Find out the maximum word length such that we may combine shorter words
- int maxWordLen = words[0].length() + 5;
- for (int i = 1; i < words.length; i++) {
- maxWordLen = Math.max(maxWordLen, words[i].length());
- }
- pnlAccept.add(chkAcceptProposals);
- int i = 1;
- while (i < words.length) {
- String word = words[i++];
- while (i < words.length && word.length() + 1 + words[i].length() <= maxWordLen) {
- word += " " + words[i++];
- }
- JLabel lbl = new JLabel(word);
- lbl.setBorder(new EmptyBorder(0, 5, 2, 0));
- pnlAccept.add(lbl);
- }
- fileChooser.setAccessory(pnlAccept);
- }
- return chkAcceptProposals;
- }
-
- /**
- * Checks if a file {@code _file} already exists and requests overwrite
- * permission in this case.
- *
- * @param f - The proposed file path
- * @param showFilename - whether the file name is to be presented in the
- * message
- * @return 0 = writing is permitted, 1 = modification requested, 2 = skip
- * (don't write), -1 - cancel all
- */
- private int checkOverwrite(File f, boolean showFilename) {
- int writeNow = 0;
- if (f.exists()) {
- writeNow = 1;
- // START KGU#534 2018-06-27: Enh. #552
- if (isInSerialMode()) {
- switch (getSerialDecision(SerialDecisionAspect.SERIAL_OVERWRITE)) {
- case INDIVIDUAL: {
- String[] options = {
- Menu.lblContinue.getText(),
- Menu.lblModify.getText(),
- Menu.lblYesToAll.getText(),
- Menu.lblSkip.getText()
- };
- String initialValue = options[0];
- String message = Menu.msgOverwriteFile.getText();
- if (showFilename) {
- message = Menu.msgOverwriteFile1.getText().replaceAll("%", f.getAbsolutePath());
- }
- int res = JOptionPane.showOptionDialog(
- this.getFrame(),
- message,
- Menu.btnConfirmOverwrite.getText(),
- JOptionPane.DEFAULT_OPTION,
- JOptionPane.QUESTION_MESSAGE,
- null,
- options,
- initialValue);
- if (res < 0) {
- writeNow = -1;
- } else if (res > 2) {
- writeNow = 2;
- } else if (res == 2) {
- setSerialDecision(SerialDecisionAspect.SERIAL_OVERWRITE, true);
- }
- if (res == 0 || res == 2) {
- writeNow = 0;
- }
- }
- break;
- case YES_TO_ALL:
- writeNow = 0;
- break;
- default: ;
- }
- } else {
- // END KGU#534 2018-06-27
- int res = JOptionPane.showConfirmDialog(
- this.getFrame(),
- Menu.msgOverwriteFile.getText(),
- Menu.btnConfirmOverwrite.getText(),
- JOptionPane.YES_NO_OPTION);
- if (res == JOptionPane.YES_OPTION) {
- writeNow = 0;
- }
- // START KGU#534 2018-06-27: Enh. #552
- }
- // END KGU#534 2018-06-27
- }
- return writeNow;
- }
-
- /*========================================
- * Save method
- *========================================*/
- /**
- * Stores unsaved changes (if any). If {@code _askToSave} is true then the
- * user may confirm or deny saving or cancel the inducing request. Otherwise
- * unsaved changes will silently be stored.
- *
- * @param _askToSave - if true and the current root has unsaved changes then
- * a user dialog will be popped up first
- * @return true if the user did not cancel the save request
- */
- public boolean saveNSD(boolean _askToSave) // START KGU#320 2017-01-04: Bugfix (#321)
- {
- // START KGU#456 2017-11-05: Enh. #452
- //return saveNSD(this.root, _askToSave);
- boolean needsSave = !root.isEmpty() && root.hasChanged();
- if (saveNSD(this.root, _askToSave)) {
- if (needsSave && root.advanceTutorialState(26, root)) {
- analyse();
- }
- return true;
- }
- return false;
- // END KGU#456 2017-11-05
- }
-
- /**
- * Stores unsaved changes (if any) of the given {@link Root} {@code root}.
- * If {@code _askToSave} is {@code true} then the user may confirm or deny
- * saving or cancel the inducing request.
- *
- * @param root - {@link Root} to be saved
- * @param _askToSave - if {@code true} and the given {@code root} has
- * unsaved changes then a user dialog will be popped up first.
- * @return {@code true} if the user did not cancel the save request
- */
- public boolean saveNSD(Root root, boolean _askToSave) // END KGU#320 2017-01-04
- {
- // START KGU#911 2021-01-10: Enh. #910 suppress saving
- if (root.isRepresentingDiagramController()) {
- return true; // Fake success
- }
- // END KGU#911 2021-01-10
- int res = 0; // Save decision: 0 = do save, 1 = don't save, -1 = cancelled (don't leave)
- // only save if something has been changed
- // START KGU#137 2016-01-11: Use the new method now
- //if(root.hasChanged==true)
- // START KGU#749 2019-10-13: Bugfix #763 - also save in case of a stale file
- //if (!root.isEmpty() && root.hasChanged())
- boolean hasValidFile = root.getFile() != null;
- if (!hasValidFile && root.shadowFilepath != null) {
- File shadow = new File(root.shadowFilepath);
- if (shadow.canRead()) {
- root.filename = shadow.getAbsolutePath();
- root.shadowFilepath = null; // FIXME: This may require refreshing / updating - is it ensured?
- hasValidFile = true;
- }
- }
- if (!root.isEmpty() && (root.hasChanged() || !hasValidFile)) // END KGU#749 2019-10-13
- // END KGU#137 2016-01-11
- {
- String message = null;
- if (_askToSave) {
- String filename = root.filename;
- if (filename == null || filename.isEmpty()) {
- filename = root.proposeFileName();
- }
- message = Menu.msgSaveChanges.getText() + "\n\"" + filename + "\"";
- }
- // START BOB 2019-10-16: Unimozer crashed with a NullPointerException
- if (this.NSDControl == null) {
- return false;
- }
- // END BOB 2019-10-16
- res = requestSaveDecision(message, this.getFrame(), SerialDecisionAspect.SERIAL_SAVE);
-
- // START KGU#534 2018-06-27: Enh. #552
- //if (res==0)
- if (res == 0 || res == 2) // END KGU#534 2018-06-27
- {
- // Check whether root has already been loaded or saved once
- //boolean saveIt = true;
-
- //System.out.println(this.currentDirectory.getAbsolutePath());
- // START KGU#749 2019-10-13: Bugfix #763 - Also save in case of a stale file
- //if (root.filename.equals(""))
- // START KGU#874 2020-10-18: Issue #875 Special handling for virgin Roots in archive groups
- boolean fileFaked = false;
- if (!hasValidFile && isArrangerOpen()) {
- Collection owners = Arranger.getInstance().getGroupsFromRoot(root, false);
- /* If there is exactly one owning group except the default group
- * and this group resides in an archive file then we will prepare
+ /**
+ * Tries to save the current {@link Root} under a new path. Opens a
+ * FileChooser for this purpose
+ *
+ * @return true if the diagram was saved, false otherwise.
+ */
+ public boolean saveAsNSD()
+ // START KGU#320 2017-01-04: Bugfix #321(?) We need a possibility to save a different root
+ {
+ // START KGU#893 2020-12-20: Bugfix #892 - Arrangment group members must be cloned!
+ //return saveAsNSD(this.root);
+ Root rootToSave = this.root;
+ // Check membership in named group: if there is any, clone the Root
+ if (Arranger.hasInstance()
+ && !Arranger.getInstance().getGroupsFromRoot(root, true).isEmpty()) {
+ rootToSave = (Root) root.copy();
+ }
+ boolean done = saveAsNSD(rootToSave);
+ if (done && rootToSave != this.root) {
+ JOptionPane.showMessageDialog(
+ this.getFrame(),
+ Menu.msgRootCloned.getText().replace("%1", this.root.getSignatureString(false, false))
+ .replace("%2", rootToSave.getSignatureString(true, false)));
+ this.setRoot(rootToSave, true, true);
+ }
+ return done;
+ // END KGU#893 2020-12-20
+ }
+
+ /**
+ * Tries to save the {@link Root} given as {@code root} under a new path.
+ * Opens a FileChooser for this purpose.
+ *
+ * @param root - the diagram to be saved.
+ * @return true if the diagram was saved, false otherwise
+ */
+ private boolean saveAsNSD(Root root)
+ // END KGU#320 2017-01-04
+ {
+ // START KGU#911 2021-01-10: Enh. #910 suppress saving
+ if (root.isRepresentingDiagramController()) {
+ return true; // Fake success
+ }
+ // END KGU#911 2021-01-10
+ // propose name
+ String nsdName = root.proposeFileName();
+
+ // START KGU#534/KGU#553 2018-07-10: Enh. #552, issue #557 - special treatment for mass serial save
+ File dir = this.currentDirectory;
+ if (dir != null && isInSerialMode() && getSerialDecision(SerialDecisionAspect.SERIAL_SAVE) == SerialDecisionStatus.YES_TO_ALL) {
+ // We have a target directory and the user has already confirmed to save all with proposed names
+ if (!dir.isDirectory()) {
+ // A file name had been stored as current directory, so reduce it to its directory
+ dir = dir.getParentFile();
+ }
+ // Accomplish the proposed file name...
+ File f = new File(dir.getAbsolutePath() + File.separator + nsdName + ".nsd");
+ // ... check whether a file with this name has existed
+ int answer = this.checkOverwrite(f, true);
+ if (answer == 0) {
+ // Okay, we are entitled to overwrite
+ root.filename = f.getAbsolutePath();
+ root.shadowFilepath = null;
+ return doSaveNSD(root);
+ } else if (answer < 0) {
+ // User wants to cancel the serial saving
+ return false;
+ } else if (answer == 2) {
+ // Skip this file here, no further attempt
+ return true;
+ }
+ }
+ // END KGU#534/KGU#553 2018-07-10
+
+ // Now we are either not in serial mode or a name conflict is to be solved via file chooser
+ JFileChooser dlgSave = new JFileChooser();
+
+ // START KGU#553 2018-07-13: Issue #557
+ // Add a checkbox to adhere to the proposed names for all remaining roots if we are in serial mode
+ JCheckBox chkAcceptProposals = addSerialAccessory(dlgSave);
+ // END KGU#553 2018-07-13
+ // START KGU#287 2017-01-09: Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
+ GUIScaler.rescaleComponents(dlgSave);
+ // END KGU#287 2017-01-09
+ dlgSave.setDialogTitle(Menu.msgTitleSaveAs.getText());
+ File rootFile = root.getFile();
+ // set directory
+ if (rootFile != null) {
+ dlgSave.setCurrentDirectory(rootFile);
+ } else {
+ dlgSave.setCurrentDirectory(currentDirectory);
+ }
+
+ dlgSave.setSelectedFile(new File(nsdName));
+ dlgSave.addChoosableFileFilter(new StructogramFilter());
+
+ // START KGU#248 2016-09-15: Bugfix #244 - allow more than one chance
+ //int result = dlgSave.showSaveDialog(this);
+ int result = JFileChooser.ERROR_OPTION;
+ do {
+ result = dlgSave.showSaveDialog(this.getFrame());
+ // END KGU#248 2016-9-15
+ if (result == JFileChooser.APPROVE_OPTION) {
+ String newFilename = dlgSave.getSelectedFile().getAbsoluteFile().toString();
+ if (!newFilename.substring(newFilename.length() - 4, newFilename.length()).toLowerCase().equals(".nsd")) {
+ newFilename += ".nsd";
+ }
+ if (chkAcceptProposals != null && chkAcceptProposals.isSelected()) {
+ setSerialDecision(SerialDecisionAspect.SERIAL_SAVE, true);
+ }
+
+ File f = new File(newFilename);
+ int writePerm = checkOverwrite(f, false);
+
+ if (writePerm < 0) {
+ // Cancelled all
+ return false;
+ } else if (writePerm == 2) {
+ // No further attempt
+ return true;
+ } else if (writePerm != 0) {
+ // START KGU#248 2016-09-15: Bugfix #244 - message no longer needed (due to new loop)
+ //JOptionPane.showMessageDialog(this, Menu.msgRepeatSaveAttempt.getText());
+ result = JFileChooser.ERROR_OPTION;
+ // END KGU#248 2016-09-15
+ } else {
+ root.filename = newFilename;
+ // START KGU#316 2016-12-28: Enh. #318
+ root.shadowFilepath = null;
+ // END KGU#316 2016-12-28
+ // START KGU#874 2020-10-19: Enh. #875 set the signature from file name for dummies
+ replaceDummyHeader(root, f);
+ // END KGU#874 2020-10-19
+ // START KGU#94 2015.12.04: out-sourced to auxiliary method
+ // START KGU#320 2017-01-04: Bugfix #321(?) Need a parameter now
+ //doSaveNSD();
+ doSaveNSD(root);
+ // END KGU#320 2017-01-04
+ // END KGU#94 2015-12-04
+ // START KGU#273 2016-10-07: Bugfix #263 - remember the directory as current directory
+ this.currentDirectory = f;
+ // END KGU#273 2016-10-07
+ }
+ }
+ // START KGU#248 2016-09-15: Bugfix #244 - allow to leave the new loop
+ // else
+ // {
+ // // User cancelled the file dialog -> leave the loop
+ // result = JFileChooser.CANCEL_OPTION;
+ // }
+ } while (result == JFileChooser.ERROR_OPTION);
+ // END KGU#248 2016-09-15
+
+ return result != JFileChooser.CANCEL_OPTION;
+ }
+
+ // START KGU#874 2020-10-19: Issue #875 - try to make sense from the filename
+ /**
+ * IN case {@code _root} has a dummy header (empty or "???"), we try to
+ * derive a header from the name of the chosen target file {@code _file}
+ *
+ * @param _root - the {@link Root} to be saved
+ * @param _file - the chosen target file
+ */
+ private void replaceDummyHeader(Root _root, File _file) {
+ String header = _root.getMethodName().trim();
+ if (header.isEmpty() || header.equals("???")) {
+ header = _file.getName();
+ // Remove the ".nsd" extension
+ header = header.substring(0, header.length() - 4);
+ String argList = "";
+ if (_root.isSubroutine()) {
+ header = header.split(Matcher.quoteReplacement("" + Element.E_FILENAME_SIG_SEPARATOR), -1)[0];
+ // Try to infer arguments and result type
+ IRoutinePool pool = null;
+ if (Arranger.hasInstance()) {
+ pool = Arranger.getInstance();
+ }
+ StringList vars = _root.getUninitializedVars(pool);
+ // TODO: Infer the argument types and the result type
+ argList = "(" + vars.concatenate(", ") + ")";
+ vars = _root.getVarNames();
+ // START KGU#886 2020-12-10: Issue #884
+ //if (vars.contains(header) || vars.contains("result", false)) {
+ IElementVisitor returnFinder = new IElementVisitor() {
+ private int retLen = CodeParser.getKeyword("preReturn").length();
+
+ @Override
+ public boolean visitPreOrder(Element _ele) {
+ if (_ele instanceof Jump) {
+ StringList lines = _ele.getUnbrokenText();
+ for (int i = 0; i < lines.count(); i++) {
+ String line = lines.get(i);
+ if (Jump.isReturn(line)) {
+ // Stops and returns false if a value is returned
+ // TODO Try to identify the result type
+ return line.substring(retLen).trim().isEmpty();
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visitPostOrder(Element _ele) {
+ return true;
+ }
+
+ };
+ boolean lastElReturnsVal = false;
+ if (root.children.getSize() > 0) {
+ Element lastEl = root.children.getElement(root.children.getSize() - 1);
+ if (lastEl instanceof Instruction) {
+ int retLen = CodeParser.getKeyword("preReturn").length();
+ StringList lines = lastEl.getUnbrokenText();
+ for (int i = 0; i < lines.count(); i++) {
+ String line = lines.get(i);
+ if (Jump.isReturn(line)) {
+ // Stops and detects if a value is returned
+ lastElReturnsVal = !line.substring(retLen).trim().isEmpty();
+ break;
+ }
+ }
+ }
+ }
+ if (vars.contains(header) || vars.contains("result", false)
+ || lastElReturnsVal
+ || !_root.children.traverse(returnFinder)) {
+ // END KGU#886 2020-12-10: Issue #884
+ // TODO try to identify the type
+ argList += ": ???";
+ }
+ }
+ if (Function.testIdentifier(header, false, null)) {
+ // START KGU#886 2020-12-10: Bugfix #884
+ //root.setText(header + argList);
+ root.addUndo();
+ root.setText(header + argList);
+ this.analyse();
+ // END KGU#886 2020-12-10
+ this.invalidateAndRedraw();
+ }
+ }
+
+ }
+ // END KGU#874 2020-10-19
+
+ /**
+ * In case of serial mode adds a checkbox to {@code fileChooser}
+ *
+ * @param fileChooser - the {@link JFileChooser} to be decorated if in
+ * serial mode.
+ * @return the checkbox if it was created
+ */
+ private JCheckBox addSerialAccessory(JFileChooser fileChooser) {
+ JCheckBox chkAcceptProposals = null;
+ if (isInSerialMode() && getSerialDecision(SerialDecisionAspect.SERIAL_SAVE) == SerialDecisionStatus.INDIVIDUAL) {
+ // Unfortunateley, the accessory is usally placed right of the file view.
+ // So we split the caption for the checkbox to be added into words and
+ // and "verticalize" the text by distributing the words over as many
+ // vertically boxed labels as needed.
+ JPanel pnlAccept = new JPanel();
+ pnlAccept.setLayout(new BoxLayout(pnlAccept, BoxLayout.PAGE_AXIS));
+ String[] words = Menu.lblAcceptProposedNames.getText().split("\\s+");
+ chkAcceptProposals = new JCheckBox(words[0]);
+ // Find out the maximum word length such that we may combine shorter words
+ int maxWordLen = words[0].length() + 5;
+ for (int i = 1; i < words.length; i++) {
+ maxWordLen = Math.max(maxWordLen, words[i].length());
+ }
+ pnlAccept.add(chkAcceptProposals);
+ int i = 1;
+ while (i < words.length) {
+ String word = words[i++];
+ while (i < words.length && word.length() + 1 + words[i].length() <= maxWordLen) {
+ word += " " + words[i++];
+ }
+ JLabel lbl = new JLabel(word);
+ lbl.setBorder(new EmptyBorder(0, 5, 2, 0));
+ pnlAccept.add(lbl);
+ }
+ fileChooser.setAccessory(pnlAccept);
+ }
+ return chkAcceptProposals;
+ }
+
+ /**
+ * Checks if a file {@code _file} already exists and requests overwrite
+ * permission in this case.
+ *
+ * @param f - The proposed file path
+ * @param showFilename - whether the file name is to be presented in the
+ * message
+ * @return 0 = writing is permitted, 1 = modification requested, 2 = skip
+ * (don't write), -1 - cancel all
+ */
+ private int checkOverwrite(File f, boolean showFilename) {
+ int writeNow = 0;
+ if (f.exists()) {
+ writeNow = 1;
+ // START KGU#534 2018-06-27: Enh. #552
+ if (isInSerialMode()) {
+ switch (getSerialDecision(SerialDecisionAspect.SERIAL_OVERWRITE)) {
+ case INDIVIDUAL: {
+ String[] options = {
+ Menu.lblContinue.getText(),
+ Menu.lblModify.getText(),
+ Menu.lblYesToAll.getText(),
+ Menu.lblSkip.getText()
+ };
+ String initialValue = options[0];
+ String message = Menu.msgOverwriteFile.getText();
+ if (showFilename) {
+ message = Menu.msgOverwriteFile1.getText().replaceAll("%", f.getAbsolutePath());
+ }
+ int res = JOptionPane.showOptionDialog(
+ this.getFrame(),
+ message,
+ Menu.btnConfirmOverwrite.getText(),
+ JOptionPane.DEFAULT_OPTION,
+ JOptionPane.QUESTION_MESSAGE,
+ null,
+ options,
+ initialValue);
+ if (res < 0) {
+ writeNow = -1;
+ } else if (res > 2) {
+ writeNow = 2;
+ } else if (res == 2) {
+ setSerialDecision(SerialDecisionAspect.SERIAL_OVERWRITE, true);
+ }
+ if (res == 0 || res == 2) {
+ writeNow = 0;
+ }
+ }
+ break;
+ case YES_TO_ALL:
+ writeNow = 0;
+ break;
+ default: ;
+ }
+ } else {
+ // END KGU#534 2018-06-27
+ int res = JOptionPane.showConfirmDialog(
+ this.getFrame(),
+ Menu.msgOverwriteFile.getText(),
+ Menu.btnConfirmOverwrite.getText(),
+ JOptionPane.YES_NO_OPTION);
+ if (res == JOptionPane.YES_OPTION) {
+ writeNow = 0;
+ }
+ // START KGU#534 2018-06-27: Enh. #552
+ }
+ // END KGU#534 2018-06-27
+ }
+ return writeNow;
+ }
+
+ /*========================================
+ * Save method
+ *========================================*/
+ /**
+ * Stores unsaved changes (if any). If {@code _askToSave} is true then the
+ * user may confirm or deny saving or cancel the inducing request. Otherwise
+ * unsaved changes will silently be stored.
+ *
+ * @param _askToSave - if true and the current root has unsaved changes then
+ * a user dialog will be popped up first
+ * @return true if the user did not cancel the save request
+ */
+ public boolean saveNSD(boolean _askToSave) // START KGU#320 2017-01-04: Bugfix (#321)
+ {
+ // START KGU#456 2017-11-05: Enh. #452
+ //return saveNSD(this.root, _askToSave);
+ boolean needsSave = !root.isEmpty() && root.hasChanged();
+ if (saveNSD(this.root, _askToSave)) {
+ if (needsSave && root.advanceTutorialState(26, root)) {
+ analyse();
+ }
+ return true;
+ }
+ return false;
+ // END KGU#456 2017-11-05
+ }
+
+ /**
+ * Stores unsaved changes (if any) of the given {@link Root} {@code root}.
+ * If {@code _askToSave} is {@code true} then the user may confirm or deny
+ * saving or cancel the inducing request.
+ *
+ * @param root - {@link Root} to be saved
+ * @param _askToSave - if {@code true} and the given {@code root} has
+ * unsaved changes then a user dialog will be popped up first.
+ * @return {@code true} if the user did not cancel the save request
+ */
+ public boolean saveNSD(Root root, boolean _askToSave) // END KGU#320 2017-01-04
+ {
+ // START KGU#911 2021-01-10: Enh. #910 suppress saving
+ if (root.isRepresentingDiagramController()) {
+ return true; // Fake success
+ }
+ // END KGU#911 2021-01-10
+ int res = 0; // Save decision: 0 = do save, 1 = don't save, -1 = cancelled (don't leave)
+ // only save if something has been changed
+ // START KGU#137 2016-01-11: Use the new method now
+ //if(root.hasChanged==true)
+ // START KGU#749 2019-10-13: Bugfix #763 - also save in case of a stale file
+ //if (!root.isEmpty() && root.hasChanged())
+ boolean hasValidFile = root.getFile() != null;
+ if (!hasValidFile && root.shadowFilepath != null) {
+ File shadow = new File(root.shadowFilepath);
+ if (shadow.canRead()) {
+ root.filename = shadow.getAbsolutePath();
+ root.shadowFilepath = null; // FIXME: This may require refreshing / updating - is it ensured?
+ hasValidFile = true;
+ }
+ }
+ if (!root.isEmpty() && (root.hasChanged() || !hasValidFile))
+ // END KGU#749 2019-10-13
+ // END KGU#137 2016-01-11
+ {
+ String message = null;
+ if (_askToSave) {
+ String filename = root.filename;
+ if (filename == null || filename.isEmpty()) {
+ filename = root.proposeFileName();
+ }
+ message = Menu.msgSaveChanges.getText() + "\n\"" + filename + "\"";
+ }
+ // START BOB 2019-10-16: Unimozer crashed with a NullPointerException
+ if (this.NSDControl == null) {
+ return false;
+ }
+ // END BOB 2019-10-16
+ res = requestSaveDecision(message, this.getFrame(), SerialDecisionAspect.SERIAL_SAVE);
+
+ // START KGU#534 2018-06-27: Enh. #552
+ //if (res==0)
+ if (res == 0 || res == 2)
+ // END KGU#534 2018-06-27
+ {
+ // Check whether root has already been loaded or saved once
+ //boolean saveIt = true;
+
+ //System.out.println(this.currentDirectory.getAbsolutePath());
+ // START KGU#749 2019-10-13: Bugfix #763 - Also save in case of a stale file
+ //if (root.filename.equals(""))
+ // START KGU#874 2020-10-18: Issue #875 Special handling for virgin Roots in archive groups
+ boolean fileFaked = false;
+ if (!hasValidFile && isArrangerOpen()) {
+ Collection owners = Arranger.getInstance().getGroupsFromRoot(root, false);
+ /* If there is exactly one owning group except the default group
+ * and this group resides in an archive file then we will prepare
* the desired file paths for integration of the virgin diagram
- */
- if (owners.size() == 1) {
- File arrzFile = null;
- for (Group owner : owners) {
- if (!owner.isDefaultGroup()) {
- arrzFile = owner.getArrzFile(true);
- }
- }
- if (arrzFile != null) {
- String fileName = root.proposeFileName();
- // We won't accept a nonsense file name
- if (!fileName.isEmpty() && !fileName.equals("???")) {
- try {
- /* Create a temporary file path */
- File tempFile = File.createTempFile("Structorizer", ".nsd");
- root.shadowFilepath = tempFile.getAbsolutePath();
- /* Build the virtual file path (within the archive,
+ */
+ if (owners.size() == 1) {
+ File arrzFile = null;
+ for (Group owner : owners) {
+ if (!owner.isDefaultGroup()) {
+ arrzFile = owner.getArrzFile(true);
+ }
+ }
+ if (arrzFile != null) {
+ String fileName = root.proposeFileName();
+ // We won't accept a nonsense file name
+ if (!fileName.isEmpty() && !fileName.equals("???")) {
+ try {
+ /* Create a temporary file path */
+ File tempFile = File.createTempFile("Structorizer", ".nsd");
+ root.shadowFilepath = tempFile.getAbsolutePath();
+ /* Build the virtual file path (within the archive,
* we hope there won't be a name collision)
- */
- root.filename = arrzFile.getAbsolutePath() + File.separator + fileName + ".nsd";
- fileFaked = true;
- /* Remove the temporary file lest it should be regarded as update */
- if (tempFile.exists()) {
- tempFile.delete();
- }
- // Only if all preparations worked we will fake file validity
- hasValidFile = true;
- } catch (IOException exc) {
- logger.log(Level.FINE, "No temporary file creatable", exc);
- }
- }
- }
- }
- }
- // END KGU#874 2020-10-18
- if (!hasValidFile) // END KGU#749 2019-10-13
- {
- // root has never been saved
+ */
+ root.filename = arrzFile.getAbsolutePath() + File.separator + fileName + ".nsd";
+ fileFaked = true;
+ /* Remove the temporary file lest it should be regarded as update */
+ if (tempFile.exists()) {
+ tempFile.delete();
+ }
+ // Only if all preparations worked we will fake file validity
+ hasValidFile = true;
+ } catch (IOException exc) {
+ logger.log(Level.FINE, "No temporary file creatable", exc);
+ }
+ }
+ }
+ }
+ }
+ // END KGU#874 2020-10-18
+ if (!hasValidFile)
+ // END KGU#749 2019-10-13
+ {
+ // root has never been saved
// START KGU#248 2016-09-15: Bugfix #244 delegate to saveAsNSD()
// JFileChooser dlgSave = new JFileChooser();
// dlgSave.setDialogTitle(Menu.msgTitleSave.getText());
@@ -3119,1299 +3076,1312 @@ public boolean saveNSD(Root root, boolean _askToSave) // END KGU#320 2017-01-04
// }
//
// if (saveIt == true)
- // START KGU#320 2017-01-04: Bugfix (#321)
- //saveAsNSD();
- if (!saveAsNSD(root)) {
- // START KGU#634 2019-01-17: Issue #664 - in mode AUTO_SAVE_ON_CLOSE, this answer my be ambiguous
- //res = -1; // Cancel all
- if (!Element.E_AUTO_SAVE_ON_CLOSE
- || !isGoingToClose
- || JOptionPane.showConfirmDialog(this.getFrame(),
- Menu.msgVetoClose.getText(),
- Menu.msgTitleWarning.getText(),
- JOptionPane.YES_NO_OPTION) == JOptionPane.OK_OPTION) {
- res = -1;
- } else {
- res = 1;
- }
- // END KGU#634 2019-01-17
- }
- // END KGU#320 2017-01-04
- } else // END KGU#248 2016-09-15
- {
- // START KGU#94 2015-12-04: Out-sourced to auxiliary method
- // START KGU#320 2017-01-04: Bugfix (#321) had to parameterize this
- //doSaveNSD();
- // START KGU#874 2020-10-18: Issue #875
- //doSaveNSD(root);
- if (!doSaveNSD(root) && fileFaked) {
- root.filename = "";
- root.shadowFilepath = null;
- }
- // END KGU#874 2020-10-18
- // END KGU#320 2017-01-04
- // END KGU#94 2015-12-04
- }
- }
- }
- return res != -1; // true if not cancelled
- }
-
- /**
- * Service method for a decision about saving a file in a potential serial
- * context.
- *
- * @param _messageText - the text of the offered question if an interactive
- * dialog is wanted at all, null otherwise
- * @param _initiator - an owning component for the modal message or question
- * boxes
- * @param _aspect - the current serial action mode (of type
- * {@link SerialDecisionAspect})
- * @return 0 for approval, 1 for disapproval, 2 for "yes to all", 3 for "no
- * to all", -1 for cancel
- */
- public static int requestSaveDecision(String _messageText, Component _initiator, SerialDecisionAspect _aspect) {
- int res = 0;
- // START KGU#534 2018-06-27: Enh. #552
- if (_messageText != null && isInSerialMode()) {
- switch (getSerialDecision(_aspect)) {
- case NO_TO_ALL:
- res = 1;
- // NO break here!
- case YES_TO_ALL:
- _messageText = null;
- break;
- default:;
- }
- }
- // END KGU#534 2018-06-27
- if (_messageText != null) {
- // START KGU#49 2015-10-18: If induced by Arranger then it's less ambiguous seeing the NSD name
- //res = JOptionPane.showOptionDialog(this,
- // "Do you want to save the current NSD-File?",
- String[] options = null;
- if (isInSerialMode()) {
- options = new String[]{
- Menu.lblContinue.getText(),
- Menu.lblSkip.getText(),
- Menu.lblYesToAll.getText(),
- Menu.lblNoToAll.getText() // Well, this is less sensible...
- };
- } else {
- options = new String[]{
- Menu.lblYes.getText(),
- Menu.lblNo.getText()
- };
- }
- Object initialValue = options[0];
- res = JOptionPane.showOptionDialog(_initiator,
- _messageText,
- // END KGU#49 2015-10-18
- Menu.msgTitleQuestion.getText(),
- JOptionPane.YES_NO_OPTION,
- JOptionPane.QUESTION_MESSAGE,
- // START KGU#534 2018-06-27: Enh. #552
- //null,null,null
- null,
- options,
- initialValue
- // END KGU#534 2018-06-27
- );
- }
- if (res >= 2) {
- setSerialDecision(_aspect, res == 2);
- }
- return res;
- }
-
- // START KGU#94 2015-12-04: Common file writing routine (on occasion of bugfix #40)
- // START KGU#320 2017-01-03: Bugfix (#321)
- //private boolean doSaveNSD()
- private boolean doSaveNSD(Root root) // END KGU#320 2017-01-03
- {
- //String[] EnvVariablesToCheck = { "TEMP", "TMP", "TMPDIR", "HOME", "HOMEPATH" };
- boolean done = false;
- try {
- // START KGU#94 2015.12.04: Bugfix #40 part 1
- // A failed saving attempt should not leave a truncated file!
- //FileOutputStream fos = new FileOutputStream(root.filename);
- String filename = root.filename;
- // START KGU#316 2016-12-28: Enh. #318
- if (root.shadowFilepath != null) {
- filename = root.shadowFilepath;
- }
- // END KGU#316 2016-12-28
- File f = new File(filename);
- boolean fileExisted = f.exists();
- // START KGU#316 2016-12-28: Enh. 318
- //if (fileExisted)
- if (fileExisted && root.shadowFilepath == null) // END KGU#316 2016-12-28
- {
- File tmpFile = File.createTempFile("Structorizer", ".nsd");
- filename = tmpFile.getAbsolutePath();
- }
- FileOutputStream fos = new FileOutputStream(filename);
- // END KGU#94 2015-12-04
- Writer out = new OutputStreamWriter(fos, "UTF-8");
- XmlGenerator xmlgen = new XmlGenerator();
- out.write(xmlgen.generateCode(root, "\t", false));
- out.close();
-
- // START KGU#94 2015-12-04: Bugfix #40 part 2
- // If the NSD file had existed then replace it by the output file after having created a backup
- // START KGU#316 2016-12-28: Enh. #318 Let nsd files reside in arrz files
- // if (fileExisted)
- if (root.shadowFilepath != null) {
- // START KGU#320 2017-01-04: Bugfix #321(?)
- //if (!zipToArrz(filename)) {
- if (!zipToArrz(root, filename)) {
- // END KGU#320 2017-01-04
- // If the saving to the original arrz file failed then make the shadow path the actual one
- root.filename = filename;
- root.shadowFilepath = null;
- }
- } else if (fileExisted) // END KGU#316 2016-12-28
- {
- File backUp = new File(root.filename + ".bak");
- if (backUp.exists()) {
- backUp.delete();
- }
- // START KGU#717 2019-07-31: Bugfix #526, #731
- //f.renameTo(backUp);
- boolean moved = Archivar.renameTo(f, backUp);
- // END KGU#717 2019-07-31
- f = new File(root.filename);
- File tmpFile = new File(filename);
- // START KGU#717 2019-07-31: Bugfix #526, #731
- //tmpFile.renameTo(f);
- moved = moved && Archivar.renameTo(tmpFile, f);
- // END KGU#717 2019-07-31
- // START KGU#509 2018-03-20: Bugfix #526 renameTo may have failed, so better check
- if (!moved || !f.exists() && tmpFile.canRead()) {
- logger.log(Level.WARNING, "Failed to rename \"{0}\" to \"{1}\"; trying a workaround...",
- new Object[]{filename, f.getAbsolutePath()});
- String errors = Archivar.copyFile(tmpFile, f, true);
- if (!errors.isEmpty()) {
- JOptionPane.showMessageDialog(this.getFrame(),
- Menu.msgErrorFileRename.getText().replace("%1", errors).replace("%2", tmpFile.getAbsolutePath()),
- Menu.msgTitleError.getText(),
- JOptionPane.ERROR_MESSAGE, null);
- }
- }
- // END KGU#509 2018-03-20
- // START KGU#309 2016-12-15: Issue #310 backup may be opted out
- if (!Element.E_MAKE_BACKUPS && backUp.exists()) {
- backUp.delete();
- }
- // END KGU#309 2016-12-15
- }
- // END KGU#94 2015.12.04
-
- // START KGU#137 2016-01-11: On successful saving, record the undo stack level
- //root.hasChanged=false;
- root.rememberSaved();
- // END KGU#137 2016-01-11
- // START KGU#316 2016-12-28: Enh. #318: Don't remember a zip-internal file path
- //addRecentFile(root.filename);
- addRecentFile(root.getPath(true));
- // END KGU#316 2016-12-28
- done = true;
- } catch (Exception ex) {
- String message = ex.getLocalizedMessage();
- if (message == null) {
- message = ex.getMessage();
- }
- if (message == null || message.isEmpty()) {
- message = ex.toString();
- }
- JOptionPane.showMessageDialog(this.getFrame(),
- Menu.msgErrorFileSave.getText().replace("%", message),
- Menu.msgTitleError.getText(),
- JOptionPane.ERROR_MESSAGE, null);
- }
- return done;
- }
-
- // END KGU#94 2015-12-04
- // START KGU#316 2016-12-28: Enh. #318
- // START KGU#320 2017-01-04: Bugfix #320 We might be forced to save a different diagram (from Arranger)
- //private boolean zipToArrz(String tmpFilename)
- private boolean zipToArrz(Root root, String tmpFilename) // END KGU#320 2017-01-04
- {
- String error = null;
- boolean isDone = false;
- final int BUFSIZE = 2048;
- byte[] buf = new byte[BUFSIZE];
- int len = 0;
-
- StringList inZipPath = new StringList();
- File arrzFile = new File(root.filename);
- while (arrzFile != null && !arrzFile.isFile()) {
- inZipPath.add(arrzFile.getName());
- arrzFile = arrzFile.getParentFile();
- }
- if (arrzFile == null) {
- int posArrz = root.filename.toLowerCase().indexOf(".arrz");
- error = ((posArrz > 0) ? root.filename.substring(0, posArrz + 5) : root.filename) + ": " + Menu.msgErrorNoFile.getText();
- } else {
- String localPath = inZipPath.reverse().concatenate(File.separator);
-
- ZipFile zipFile = null;
- try {
- zipFile = new ZipFile(arrzFile);
- File tmpZipFile = File.createTempFile("Structorizer", "zip");
- final ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(tmpZipFile));
- Enumeration extends ZipEntry> entries = zipFile.entries();
- // Copy all but the file to be updated
- while (entries.hasMoreElements()) {
- ZipEntry entryIn = entries.nextElement();
- if (!entryIn.getName().equals(localPath)) {
- zos.putNextEntry(entryIn);
- InputStream is = zipFile.getInputStream(entryIn);
- while ((len = is.read(buf)) > 0) {
- zos.write(buf, 0, len);
- }
- zos.closeEntry();
- }
- }
- // Now add the file to be updated
- zos.putNextEntry(new ZipEntry(localPath));
- FileInputStream fis = new FileInputStream(tmpFilename);
- while ((len = (fis.read(buf))) > 0) {
- zos.write(buf, 0, len);
- }
- zos.closeEntry();
- fis.close();
- zos.close();
- zipFile.close();
- String zipPath = arrzFile.getAbsolutePath();
- File bakFile = new File(zipPath + ".bak");
- if (bakFile.exists()) {
- bakFile.delete();
- }
- // START KGU#717 2019-07-31: Bugfix #526/#731
- //boolean bakOk = arrzFile.renameTo(bakFile);
- //boolean zipOk = tmpZipFile.renameTo(new File(zipPath));
- boolean bakOk = Archivar.renameTo(arrzFile, bakFile);
- boolean zipOk = Archivar.renameTo(tmpZipFile, new File(zipPath));
- // END KGU#717 2019-07-31
- if (bakOk && zipOk && !Element.E_MAKE_BACKUPS) {
- bakFile.delete();
- }
- isDone = true;
- } catch (ZipException ex) {
- error = ex.getLocalizedMessage();
- } catch (IOException ex) {
- error = ex.getLocalizedMessage();
- }
- }
- if (error != null) {
- JOptionPane.showMessageDialog(this.getFrame(),
- error,
- Menu.msgTitleError.getText(),
- JOptionPane.ERROR_MESSAGE, null);
- }
- return isDone;
- }
- // END KGU#316 2016-12-28
-
- /*========================================
+// // START KGU#320 2017-01-04: Bugfix (#321)
+ //saveAsNSD();
+ if (!saveAsNSD(root)) {
+ // START KGU#634 2019-01-17: Issue #664 - in mode AUTO_SAVE_ON_CLOSE, this answer my be ambiguous
+ //res = -1; // Cancel all
+ if (!Element.E_AUTO_SAVE_ON_CLOSE
+ || !isGoingToClose
+ || JOptionPane.showConfirmDialog(this.getFrame(),
+ Menu.msgVetoClose.getText(),
+ Menu.msgTitleWarning.getText(),
+ JOptionPane.YES_NO_OPTION) == JOptionPane.OK_OPTION) {
+ res = -1;
+ } else {
+ res = 1;
+ }
+ // END KGU#634 2019-01-17
+ }
+ // END KGU#320 2017-01-04
+ } else
+// END KGU#248 2016-09-15
+ {
+ // START KGU#94 2015-12-04: Out-sourced to auxiliary method
+ // START KGU#320 2017-01-04: Bugfix (#321) had to parameterize this
+ //doSaveNSD();
+ // START KGU#874 2020-10-18: Issue #875
+ //doSaveNSD(root);
+ if (!doSaveNSD(root) && fileFaked) {
+ root.filename = "";
+ root.shadowFilepath = null;
+ }
+ // END KGU#874 2020-10-18
+ // END KGU#320 2017-01-04
+ // END KGU#94 2015-12-04
+ }
+ }
+ }
+ return res != -1; // true if not cancelled
+ }
+
+ /**
+ * Service method for a decision about saving a file in a potential serial
+ * context.
+ *
+ * @param _messageText - the text of the offered question if an interactive
+ * dialog is wanted at all, null otherwise
+ * @param _initiator - an owning component for the modal message or question
+ * boxes
+ * @param _aspect - the current serial action mode (of type
+ * {@link SerialDecisionAspect})
+ * @return 0 for approval, 1 for disapproval, 2 for "yes to all", 3 for "no
+ * to all", -1 for cancel
+ */
+ public static int requestSaveDecision(String _messageText, Component _initiator, SerialDecisionAspect _aspect) {
+ int res = 0;
+ // START KGU#534 2018-06-27: Enh. #552
+ if (_messageText != null && isInSerialMode()) {
+ switch (getSerialDecision(_aspect)) {
+ case NO_TO_ALL:
+ res = 1;
+ // NO break here!
+ case YES_TO_ALL:
+ _messageText = null;
+ break;
+ default:;
+ }
+ }
+ // END KGU#534 2018-06-27
+ if (_messageText != null) {
+ // START KGU#49 2015-10-18: If induced by Arranger then it's less ambiguous seeing the NSD name
+ //res = JOptionPane.showOptionDialog(this,
+ // "Do you want to save the current NSD-File?",
+ String[] options = null;
+ if (isInSerialMode()) {
+ options = new String[]{
+ Menu.lblContinue.getText(),
+ Menu.lblSkip.getText(),
+ Menu.lblYesToAll.getText(),
+ Menu.lblNoToAll.getText() // Well, this is less sensible...
+ };
+ } else {
+ options = new String[]{
+ Menu.lblYes.getText(),
+ Menu.lblNo.getText()
+ };
+ }
+ Object initialValue = options[0];
+ res = JOptionPane.showOptionDialog(_initiator,
+ _messageText,
+ // END KGU#49 2015-10-18
+ Menu.msgTitleQuestion.getText(),
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE,
+ // START KGU#534 2018-06-27: Enh. #552
+ //null,null,null
+ null,
+ options,
+ initialValue
+ // END KGU#534 2018-06-27
+ );
+ }
+ if (res >= 2) {
+ setSerialDecision(_aspect, res == 2);
+ }
+ return res;
+ }
+
+ // START KGU#94 2015-12-04: Common file writing routine (on occasion of bugfix #40)
+ // START KGU#320 2017-01-03: Bugfix (#321)
+ //private boolean doSaveNSD()
+ private boolean doSaveNSD(Root root) // END KGU#320 2017-01-03
+ {
+ //String[] EnvVariablesToCheck = { "TEMP", "TMP", "TMPDIR", "HOME", "HOMEPATH" };
+ boolean done = false;
+ try {
+ // START KGU#94 2015.12.04: Bugfix #40 part 1
+ // A failed saving attempt should not leave a truncated file!
+ //FileOutputStream fos = new FileOutputStream(root.filename);
+ String filename = root.filename;
+ // START KGU#316 2016-12-28: Enh. #318
+ if (root.shadowFilepath != null) {
+ filename = root.shadowFilepath;
+ }
+ // END KGU#316 2016-12-28
+ File f = new File(filename);
+ boolean fileExisted = f.exists();
+ // START KGU#316 2016-12-28: Enh. 318
+ //if (fileExisted)
+ if (fileExisted && root.shadowFilepath == null) // END KGU#316 2016-12-28
+ {
+ File tmpFile = File.createTempFile("Structorizer", ".nsd");
+ filename = tmpFile.getAbsolutePath();
+ }
+ FileOutputStream fos = new FileOutputStream(filename);
+ // END KGU#94 2015-12-04
+ Writer out = new OutputStreamWriter(fos, "UTF-8");
+ XmlGenerator xmlgen = new XmlGenerator();
+ out.write(xmlgen.generateCode(root, "\t", false));
+ out.close();
+
+ // START KGU#94 2015-12-04: Bugfix #40 part 2
+ // If the NSD file had existed then replace it by the output file after having created a backup
+ // START KGU#316 2016-12-28: Enh. #318 Let nsd files reside in arrz files
+ // if (fileExisted)
+ if (root.shadowFilepath != null) {
+ // START KGU#320 2017-01-04: Bugfix #321(?)
+ //if (!zipToArrz(filename)) {
+ if (!zipToArrz(root, filename)) {
+ // END KGU#320 2017-01-04
+ // If the saving to the original arrz file failed then make the shadow path the actual one
+ root.filename = filename;
+ root.shadowFilepath = null;
+ }
+ } else if (fileExisted) // END KGU#316 2016-12-28
+ {
+ File backUp = new File(root.filename + ".bak");
+ if (backUp.exists()) {
+ backUp.delete();
+ }
+ // START KGU#717 2019-07-31: Bugfix #526, #731
+ //f.renameTo(backUp);
+ boolean moved = Archivar.renameTo(f, backUp);
+ // END KGU#717 2019-07-31
+ f = new File(root.filename);
+ File tmpFile = new File(filename);
+ // START KGU#717 2019-07-31: Bugfix #526, #731
+ //tmpFile.renameTo(f);
+ moved = moved && Archivar.renameTo(tmpFile, f);
+ // END KGU#717 2019-07-31
+ // START KGU#509 2018-03-20: Bugfix #526 renameTo may have failed, so better check
+ if (!moved || !f.exists() && tmpFile.canRead()) {
+ logger.log(Level.WARNING, "Failed to rename \"{0}\" to \"{1}\"; trying a workaround...",
+ new Object[]{filename, f.getAbsolutePath()});
+ String errors = Archivar.copyFile(tmpFile, f, true);
+ if (!errors.isEmpty()) {
+ JOptionPane.showMessageDialog(this.getFrame(),
+ Menu.msgErrorFileRename.getText().replace("%1", errors).replace("%2", tmpFile.getAbsolutePath()),
+ Menu.msgTitleError.getText(),
+ JOptionPane.ERROR_MESSAGE, null);
+ }
+ }
+ // END KGU#509 2018-03-20
+ // START KGU#309 2016-12-15: Issue #310 backup may be opted out
+ if (!Element.E_MAKE_BACKUPS && backUp.exists()) {
+ backUp.delete();
+ }
+ // END KGU#309 2016-12-15
+ }
+ // END KGU#94 2015.12.04
+
+ // START KGU#137 2016-01-11: On successful saving, record the undo stack level
+ //root.hasChanged=false;
+ root.rememberSaved();
+ // END KGU#137 2016-01-11
+ // START KGU#316 2016-12-28: Enh. #318: Don't remember a zip-internal file path
+ //addRecentFile(root.filename);
+ addRecentFile(root.getPath(true));
+ // END KGU#316 2016-12-28
+ done = true;
+ } catch (Exception ex) {
+ String message = ex.getLocalizedMessage();
+ if (message == null) {
+ message = ex.getMessage();
+ }
+ if (message == null || message.isEmpty()) {
+ message = ex.toString();
+ }
+ JOptionPane.showMessageDialog(this.getFrame(),
+ Menu.msgErrorFileSave.getText().replace("%", message),
+ Menu.msgTitleError.getText(),
+ JOptionPane.ERROR_MESSAGE, null);
+ }
+ return done;
+ }
+
+ // END KGU#94 2015-12-04
+ // START KGU#316 2016-12-28: Enh. #318
+ // START KGU#320 2017-01-04: Bugfix #320 We might be forced to save a different diagram (from Arranger)
+ //private boolean zipToArrz(String tmpFilename)
+ private boolean zipToArrz(Root root, String tmpFilename) // END KGU#320 2017-01-04
+ {
+ String error = null;
+ boolean isDone = false;
+ final int BUFSIZE = 2048;
+ byte[] buf = new byte[BUFSIZE];
+ int len = 0;
+
+ StringList inZipPath = new StringList();
+ File arrzFile = new File(root.filename);
+ while (arrzFile != null && !arrzFile.isFile()) {
+ inZipPath.add(arrzFile.getName());
+ arrzFile = arrzFile.getParentFile();
+ }
+ if (arrzFile == null) {
+ int posArrz = root.filename.toLowerCase().indexOf(".arrz");
+ error = ((posArrz > 0) ? root.filename.substring(0, posArrz + 5) : root.filename) + ": " + Menu.msgErrorNoFile.getText();
+ } else {
+ String localPath = inZipPath.reverse().concatenate(File.separator);
+
+ ZipFile zipFile = null;
+ try {
+ zipFile = new ZipFile(arrzFile);
+ File tmpZipFile = File.createTempFile("Structorizer", "zip");
+ final ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(tmpZipFile));
+ Enumeration extends ZipEntry> entries = zipFile.entries();
+ // Copy all but the file to be updated
+ while (entries.hasMoreElements()) {
+ ZipEntry entryIn = entries.nextElement();
+ if (!entryIn.getName().equals(localPath)) {
+ zos.putNextEntry(entryIn);
+ InputStream is = zipFile.getInputStream(entryIn);
+ while ((len = is.read(buf)) > 0) {
+ zos.write(buf, 0, len);
+ }
+ zos.closeEntry();
+ }
+ }
+ // Now add the file to be updated
+ zos.putNextEntry(new ZipEntry(localPath));
+ FileInputStream fis = new FileInputStream(tmpFilename);
+ while ((len = (fis.read(buf))) > 0) {
+ zos.write(buf, 0, len);
+ }
+ zos.closeEntry();
+ fis.close();
+ zos.close();
+ zipFile.close();
+ String zipPath = arrzFile.getAbsolutePath();
+ File bakFile = new File(zipPath + ".bak");
+ if (bakFile.exists()) {
+ bakFile.delete();
+ }
+ // START KGU#717 2019-07-31: Bugfix #526/#731
+ //boolean bakOk = arrzFile.renameTo(bakFile);
+ //boolean zipOk = tmpZipFile.renameTo(new File(zipPath));
+ boolean bakOk = Archivar.renameTo(arrzFile, bakFile);
+ boolean zipOk = Archivar.renameTo(tmpZipFile, new File(zipPath));
+ // END KGU#717 2019-07-31
+ if (bakOk && zipOk && !Element.E_MAKE_BACKUPS) {
+ bakFile.delete();
+ }
+ isDone = true;
+ } catch (ZipException ex) {
+ error = ex.getLocalizedMessage();
+ } catch (IOException ex) {
+ error = ex.getLocalizedMessage();
+ }
+ }
+ if (error != null) {
+ JOptionPane.showMessageDialog(this.getFrame(),
+ error,
+ Menu.msgTitleError.getText(),
+ JOptionPane.ERROR_MESSAGE, null);
+ }
+ return isDone;
+ }
+ // END KGU#316 2016-12-28
+
+ /*========================================
* addUndo method
*========================================*/
- /**
- * Creates an undo entry on .root, if the action wasn't cancelled.
- * (Otherwise a CancelledException is thrown.)
- *
- * @param _isRoot - if the Root itself is to be changed (such that
- * attributes are to be cached)
- * @throws CancelledException
- */
- public void addUndoNSD(boolean _isRoot) throws CancelledException {
- if (!_isRoot && root.storedParserPrefs != null) {
- // This is an un-refactored Root!
- // So care for consistency
- if (!this.handleKeywordDifferences(true)) {
- throw new CancelledException();
- }
- }
- root.addUndo(_isRoot);
- // START KGU#684 2019-06-13: Bugfix #728
- if (this.findDialog != null) {
- this.findDialog.resetResults();
- }
- // END KGU#684 2019-06-13
- }
-
- /*========================================
+ /**
+ * Creates an undo entry on .root, if the action wasn't cancelled.
+ * (Otherwise a CancelledException is thrown.)
+ *
+ * @param _isRoot - if the Root itself is to be changed (such that
+ * attributes are to be cached)
+ * @throws CancelledException
+ */
+ public void addUndoNSD(boolean _isRoot) throws CancelledException {
+ if (!_isRoot && root.storedParserPrefs != null) {
+ // This is an un-refactored Root!
+ // So care for consistency
+ if (!this.handleKeywordDifferences(true)) {
+ throw new CancelledException();
+ }
+ }
+ root.addUndo(_isRoot);
+ // START KGU#684 2019-06-13: Bugfix #728
+ if (this.findDialog != null) {
+ this.findDialog.resetResults();
+ }
+ // END KGU#684 2019-06-13
+ }
+
+ /*========================================
* Undo method
*========================================*/
- /**
- * Reverts the last action from the undo stack and updates the environment.
- */
- public void undoNSD() {
- // START KGU#684 2019-06-13: Bugfix #728
- if (this.findDialog != null) {
- this.findDialog.resetResults();
- }
- // END KGU#684 2019-06-13
- root.undo();
- // START KGU#138 2016-01-11: Bugfix #102 - All elements will be replaced by copies...
- selected = this.selectedDown = this.selectedMoved = null;
- // END KGU#138 2016-01-11
- // START KGU#272 2016-10-06: Bugfix #262: We must unselect root such that it may find a selected descendant
- root.setSelected(false);
- // END KGU#272 2016-10-06
- // START KGU#183 2016-04-24: Issue #169 - Restore previous selection if possible
- selected = root.findSelected();
- // END KGU#183 2016-04-24
- // START KGU#272 2016-10-06: Bugfix #262
- if (selected == null) {
- selected = root;
- root.setSelected(true);
- } else {
- selectedDown = selected;
- }
- // END KGU#272 2016-10-06
- redraw();
- analyse();
- // START KGU#705 2019-09-23: Enh. #738
- updateCodePreview();
- // END KGU#705 2019-09-23
- }
-
- /*========================================
+ /**
+ * Reverts the last action from the undo stack and updates the environment.
+ */
+ public void undoNSD() {
+ // START KGU#684 2019-06-13: Bugfix #728
+ if (this.findDialog != null) {
+ this.findDialog.resetResults();
+ }
+ // END KGU#684 2019-06-13
+ root.undo();
+ // START KGU#138 2016-01-11: Bugfix #102 - All elements will be replaced by copies...
+ selected = this.selectedDown = this.selectedMoved = null;
+ // END KGU#138 2016-01-11
+ // START KGU#272 2016-10-06: Bugfix #262: We must unselect root such that it may find a selected descendant
+ root.setSelected(false);
+ // END KGU#272 2016-10-06
+ // START KGU#183 2016-04-24: Issue #169 - Restore previous selection if possible
+ selected = root.findSelected();
+ // END KGU#183 2016-04-24
+ // START KGU#272 2016-10-06: Bugfix #262
+ if (selected == null) {
+ selected = root;
+ root.setSelected(true);
+ } else {
+ selectedDown = selected;
+ }
+ // END KGU#272 2016-10-06
+ redraw();
+ analyse();
+ // START KGU#705 2019-09-23: Enh. #738
+ updateCodePreview();
+ // END KGU#705 2019-09-23
+ }
+
+ /*========================================
* Redo method
*========================================*/
- /**
- * Redoes the last undone action (if possible) and updates the environment.
- */
- public void redoNSD() {
- // START KGU#684 2019-06-13: Bugfix #728
- if (this.findDialog != null) {
- this.findDialog.resetResults();
- }
- // END KGU#684 2019-06-13
- root.redo();
- // START KGU#138 2016-01-11: Bugfix #102 All elements will be replaced by copies...
- selected = this.selectedDown = this.selectedMoved = null;
- // END KGU#138 2016-01-11
- // START KGU#272 2016-10-06: Bugfix #262: We must unselect root such that it may find a selected descendant
- root.setSelected(false);
- // END KGU#272 2016-10-06
- // START KGU#183 2016-04-24: Issue #169 - Restore previous selection if possible
- selected = root.findSelected();
- // END KGU#183 2016-04-24
- // START KGU#272 2016-10-06: Bugfix #262
- if (selected == null) {
- selected = root;
- root.setSelected(true);
- } else {
- selectedDown = selected;
- }
- // END KGU#272 2016-10-06
- redraw();
- analyse();
- // START KGU#705 2019-09-23: Enh. #738
- updateCodePreview();
- // END KGU#705 2019-09-23
- }
-
- /*========================================
+ /**
+ * Redoes the last undone action (if possible) and updates the environment.
+ */
+ public void redoNSD() {
+ // START KGU#684 2019-06-13: Bugfix #728
+ if (this.findDialog != null) {
+ this.findDialog.resetResults();
+ }
+ // END KGU#684 2019-06-13
+ root.redo();
+ // START KGU#138 2016-01-11: Bugfix #102 All elements will be replaced by copies...
+ selected = this.selectedDown = this.selectedMoved = null;
+ // END KGU#138 2016-01-11
+ // START KGU#272 2016-10-06: Bugfix #262: We must unselect root such that it may find a selected descendant
+ root.setSelected(false);
+ // END KGU#272 2016-10-06
+ // START KGU#183 2016-04-24: Issue #169 - Restore previous selection if possible
+ selected = root.findSelected();
+ // END KGU#183 2016-04-24
+ // START KGU#272 2016-10-06: Bugfix #262
+ if (selected == null) {
+ selected = root;
+ root.setSelected(true);
+ } else {
+ selectedDown = selected;
+ }
+ // END KGU#272 2016-10-06
+ redraw();
+ analyse();
+ // START KGU#705 2019-09-23: Enh. #738
+ updateCodePreview();
+ // END KGU#705 2019-09-23
+ }
+
+ /*========================================
* applicability test methods
*========================================*/
- /**
- * Checks whether the prerequisites to paste elements are fulfilled.
- *
- * @return true if there is something to paste and pasting is allowed.
- */
- public boolean canPaste() {
- boolean cond = (eCopy != null && selected != null);
- if (cond) {
- // START KGU#143 2016-01-21 Bugfix #114
- // The first condition is for the case the copy is a referenced sequence
- cond = !eCopy.isExecuted();
- // We must not insert to a subqueue with an element currently executed or with pending execution
- // (usually the exection index would then be on the stack!)
- if (!(selected instanceof Subqueue) && selected.parent != null && selected.parent.isExecuted()) {
- cond = false;
- }
- // END KGU#143 2016-01-21
- cond = cond && !selected.getClass().getSimpleName().equals("Root");
- }
-
- return cond;
- }
-
- // START KGU#143 2016-01-21: Bugfix #114 - elements involved in execution must not be edited...
- /**
- * Checks whether the prerequisites to cut selected elements are fulfilled.
- *
- * @return true if there is something selected and may be cut now.
- * @see #canCopy()
- */
- //public boolean canCutCopy()
- public boolean canCut() {
- // START KGU#177 2016-04-14: Enh. #158 - we want to allow to copy diagrams e.g. to an Arranger of a different JVM
- //return canCopy() && !selected.executed && !selected.waited;
- // START KGU#177 2016-07-06: Enh #158: mere re-formulation (equivalent)
- //return canCopy() && !(selected instanceof Root) && !selected.executed && !selected.waited;
- // START KGU#911 2021-01-10: Enh. #910
- //return canCopyNoRoot() && !selected.isExecuted();
- return canCopyNoRoot() && !selected.isExecuted() && !selected.isImmutable();
- // END KGU#911 2021-01-10
- // END KGU#177 2016-07-06
- // END KGU#177 2016-04-14
- }
-
- // ... though breakpoints shall still be controllable
- /**
- * Checks whether the prerequisites to copy selected elements are fulfilled.
- *
- * @return true if there is something selected and may be copied now.
- * @see #canCut()
- * @see #canCopyNoRoot()
- */
- public boolean canCopy() // END KGU#143 2016-01-21
- {
- boolean cond = (selected != null);
- if (cond) {
- // START KGU#177 2016-04-14: Enh. #158 - we want to allow to copy diagrams e.g. to an Arranger of a different JVM
- //cond = !selected.getClass().getSimpleName().equals("Root");
- // END KGU#177 2016-04-14
- // START KGU#87 2015-11-22: Allow to copy a non-empty Subqueue
- //cond = cond && !selected.getClass().getSimpleName().equals("Subqueue");
- cond = cond && (!selected.getClass().getSimpleName().equals("Subqueue") || ((Subqueue) selected).getSize() > 0);
- // END KGU#87 2015-11-22
- }
-
- return cond;
- }
-
- // START KGU#177 2016-07-06: Enh. #158 - accidently breakpoints had become enabled on Root
- /**
- * Restricted check wheher the selectd element(s) may be copied - will
- * return false if the selected element is a {@link Root}.
- *
- * @return true if there is something except a {@link Root} selected and may
- * be copied now.
- * @see #canCopy()
- * @see #canCut()
- */
- public boolean canCopyNoRoot() {
- return canCopy() && !(selected instanceof Root);
- }
- // END KGU#177 2016-07-06
-
- // START KGU#143 2016-11-17: Issue #114: Complex condition for editability
- /**
- * Checks whether the prerequisites to edit the selected element are
- * fulfilled.
- *
- * @return true if there is something selected and may be edited now.
- */
- public boolean canEdit() {
- return selected != null && !this.selectedIsMultiple()
- && (!selected.isExecuted(false) || selected instanceof Instruction && !selected.executed);
- }
- // END KGU#143 2016-11-17
-
- // START KGU#686 2019-03-17: Enh. #56
- public boolean canSetBreakpoint() {
- return canCopyNoRoot() && !(selected instanceof Forever || selected instanceof Try);
- }
- // END KGU#686 2019-03-17
-
- // START KGU#199 2016-07-06: Enh. #188: Element conversions
- public boolean canTransmute() {
- boolean isConvertible = false;
- // START KGU#911 2021-01-10: Enh. #910
- //if (selected != null && !selected.isExecuted())
- if (selected != null && !selected.isExecuted() && !selected.isImmutable()) // END KGU#911 2021-01-10
- {
- // START KGU#666 2019-02-26: Bugfix #688 - it should always be offered to convert Calls and Jumps (to Instructions)
- //if (selected instanceof Instruction)
- if (selected instanceof Call || selected instanceof Jump) {
- isConvertible = true;
- } else if (selected instanceof Instruction) // END KGU#666 2019-02-26
- {
- Instruction instr = (Instruction) selected;
- isConvertible = instr.getUnbrokenText().count() > 1
- || instr.isJump()
- || instr.isFunctionCall(false)
- || instr.isProcedureCall(false);
- } else if (selected instanceof IElementSequence && ((IElementSequence) selected).getSize() > 1) {
- isConvertible = true;
- for (int i = 0; isConvertible && i < ((IElementSequence) selected).getSize(); i++) {
- if (!(((IElementSequence) selected).getElement(i) instanceof Instruction)) {
- isConvertible = false;
- }
- }
- } // START KGU#229 2016-08-01: Enh. #213
- else if (selected instanceof For) {
- isConvertible = ((For) selected).style == For.ForLoopStyle.COUNTER;
- } // END KGU#229 2016-08-01
- // START KGU#267 2016-10-03: Enh. #257
- else if (selected instanceof Case) {
- isConvertible = true;
- } // END KGU#267 2016-10-03
- // START KGU#357 2017-03-10: Enh. #367
- else if (selected instanceof Alternative && ((Alternative) selected).qFalse.getSize() > 0) {
- isConvertible = true;
- }
- // END KGU#357 2017-03-10
- }
- return isConvertible;
- }
- // END KGU#199 2016-07-06
-
- // START KGU#373 2017-03-28: Enh. #387
- public boolean canSave(boolean any) {
- boolean cond = this.root.hasChanged();
- if (!cond && any && Arranger.hasInstance()) {
- Set roots = Arranger.getInstance().getAllRoots();
- for (Root aRoot : roots) {
- if (aRoot.hasChanged()) {
- cond = true;
- break;
- }
- }
- // START KGU#874 2020-10-18: Issue #875 We must also check groups!
- if (!cond) {
- for (Group group : Arranger.getSortedGroups()) {
- if (!group.isDefaultGroup() && group.hasChanged()) {
- cond = true;
- break;
- }
- }
- }
- // END KGU#874 2020-10-18
- }
- return cond;
- }
- // END KGU#373 2017-03-28
-
- /*========================================
+ /**
+ * Checks whether the prerequisites to paste elements are fulfilled.
+ *
+ * @return true if there is something to paste and pasting is allowed.
+ */
+ public boolean canPaste() {
+ boolean cond = (eCopy != null && selected != null);
+ if (cond) {
+ // START KGU#143 2016-01-21 Bugfix #114
+ // The first condition is for the case the copy is a referenced sequence
+ cond = !eCopy.isExecuted();
+ // We must not insert to a subqueue with an element currently executed or with pending execution
+ // (usually the exection index would then be on the stack!)
+ if (!(selected instanceof Subqueue) && selected.parent != null && selected.parent.isExecuted()) {
+ cond = false;
+ }
+ // END KGU#143 2016-01-21
+ cond = cond && !selected.getClass().getSimpleName().equals("Root");
+ }
+
+ return cond;
+ }
+
+ // START KGU#143 2016-01-21: Bugfix #114 - elements involved in execution must not be edited...
+ /**
+ * Checks whether the prerequisites to cut selected elements are fulfilled.
+ *
+ * @return true if there is something selected and may be cut now.
+ * @see #canCopy()
+ */
+ //public boolean canCutCopy()
+ public boolean canCut() {
+ // START KGU#177 2016-04-14: Enh. #158 - we want to allow to copy diagrams e.g. to an Arranger of a different JVM
+ //return canCopy() && !selected.executed && !selected.waited;
+ // START KGU#177 2016-07-06: Enh #158: mere re-formulation (equivalent)
+ //return canCopy() && !(selected instanceof Root) && !selected.executed && !selected.waited;
+ // START KGU#911 2021-01-10: Enh. #910
+ //return canCopyNoRoot() && !selected.isExecuted();
+ return canCopyNoRoot() && !selected.isExecuted() && !selected.isImmutable();
+ // END KGU#911 2021-01-10
+ // END KGU#177 2016-07-06
+ // END KGU#177 2016-04-14
+ }
+
+ // ... though breakpoints shall still be controllable
+ /**
+ * Checks whether the prerequisites to copy selected elements are fulfilled.
+ *
+ * @return true if there is something selected and may be copied now.
+ * @see #canCut()
+ * @see #canCopyNoRoot()
+ */
+ public boolean canCopy() // END KGU#143 2016-01-21
+ {
+ boolean cond = (selected != null);
+ if (cond) {
+ // START KGU#177 2016-04-14: Enh. #158 - we want to allow to copy diagrams e.g. to an Arranger of a different JVM
+ //cond = !selected.getClass().getSimpleName().equals("Root");
+ // END KGU#177 2016-04-14
+ // START KGU#87 2015-11-22: Allow to copy a non-empty Subqueue
+ //cond = cond && !selected.getClass().getSimpleName().equals("Subqueue");
+ cond = cond && (!selected.getClass().getSimpleName().equals("Subqueue") || ((Subqueue) selected).getSize() > 0);
+ // END KGU#87 2015-11-22
+ }
+
+ return cond;
+ }
+
+ // START KGU#177 2016-07-06: Enh. #158 - accidently breakpoints had become enabled on Root
+ /**
+ * Restricted check wheher the selectd element(s) may be copied - will
+ * return false if the selected element is a {@link Root}.
+ *
+ * @return true if there is something except a {@link Root} selected and may
+ * be copied now.
+ * @see #canCopy()
+ * @see #canCut()
+ */
+ public boolean canCopyNoRoot() {
+ return canCopy() && !(selected instanceof Root);
+ }
+ // END KGU#177 2016-07-06
+
+ // START KGU#143 2016-11-17: Issue #114: Complex condition for editability
+ /**
+ * Checks whether the prerequisites to edit the selected element are
+ * fulfilled.
+ *
+ * @return true if there is something selected and may be edited now.
+ */
+ public boolean canEdit() {
+ return selected != null && !this.selectedIsMultiple()
+ && (!selected.isExecuted(false) || selected instanceof Instruction && !selected.executed);
+ }
+ // END KGU#143 2016-11-17
+
+ // START KGU#686 2019-03-17: Enh. #56
+ public boolean canSetBreakpoint() {
+ return canCopyNoRoot() && !(selected instanceof Forever || selected instanceof Try);
+ }
+ // END KGU#686 2019-03-17
+
+ // START KGU#199 2016-07-06: Enh. #188: Element conversions
+ public boolean canTransmute() {
+ boolean isConvertible = false;
+ // START KGU#911 2021-01-10: Enh. #910
+ //if (selected != null && !selected.isExecuted())
+ if (selected != null && !selected.isExecuted() && !selected.isImmutable()) // END KGU#911 2021-01-10
+ {
+ // START KGU#666 2019-02-26: Bugfix #688 - it should always be offered to convert Calls and Jumps (to Instructions)
+ //if (selected instanceof Instruction)
+ if (selected instanceof Call || selected instanceof Jump) {
+ isConvertible = true;
+ } else if (selected instanceof Instruction)
+ // END KGU#666 2019-02-26
+ {
+ Instruction instr = (Instruction) selected;
+ isConvertible = instr.getUnbrokenText().count() > 1
+ || instr.isJump()
+ || instr.isFunctionCall(false)
+ || instr.isProcedureCall(false);
+ } else if (selected instanceof IElementSequence && ((IElementSequence) selected).getSize() > 1) {
+ isConvertible = true;
+ for (int i = 0; isConvertible && i < ((IElementSequence) selected).getSize(); i++) {
+ if (!(((IElementSequence) selected).getElement(i) instanceof Instruction)) {
+ isConvertible = false;
+ }
+ }
+ }
+ // START KGU#229 2016-08-01: Enh. #213
+ else if (selected instanceof For) {
+ isConvertible = ((For) selected).style == For.ForLoopStyle.COUNTER;
+ }
+ // END KGU#229 2016-08-01
+ // START KGU#267 2016-10-03: Enh. #257
+ else if (selected instanceof Case) {
+ isConvertible = true;
+ }
+ // END KGU#267 2016-10-03
+ // START KGU#357 2017-03-10: Enh. #367
+ else if (selected instanceof Alternative && ((Alternative) selected).qFalse.getSize() > 0) {
+ isConvertible = true;
+ }
+ // END KGU#357 2017-03-10
+ }
+ return isConvertible;
+ }
+ // END KGU#199 2016-07-06
+
+ // START KGU#373 2017-03-28: Enh. #387
+ public boolean canSave(boolean any) {
+ boolean cond = this.root.hasChanged();
+ if (!cond && any && Arranger.hasInstance()) {
+ Set roots = Arranger.getInstance().getAllRoots();
+ for (Root aRoot : roots) {
+ if (aRoot.hasChanged()) {
+ cond = true;
+ break;
+ }
+ }
+ // START KGU#874 2020-10-18: Issue #875 We must also check groups!
+ if (!cond) {
+ for (Group group : Arranger.getSortedGroups()) {
+ if (!group.isDefaultGroup() && group.hasChanged()) {
+ cond = true;
+ break;
+ }
+ }
+ }
+ // END KGU#874 2020-10-18
+ }
+ return cond;
+ }
+ // END KGU#373 2017-03-28
+
+ /*========================================
* setColor method
*========================================*/
- /**
- * Sets the background colour of the selected element(s) to {@code _color}
- * (undoable).
- *
- * @param _color - the colour to be applied.
- */
- public void setColor(Color _color) {
- // START KGU#911 2021-01-10: Enh. #910
- //if (getSelected() != null)
- if (selected != null && !selected.isImmutable()) // END KGU#911 2021-01-10
- {
- // START KGU#38 2016-01-11 Setting of colour wasn't undoable though recorded as change
- //root.addUndo();
- try {
- addUndoNSD(false);
- } catch (CancelledException e) {
- return;
- }
- // END KGU#38 2016-01-11
- selected.setColor(_color);
- //getSelected().setSelected(false);
- //selected=null;
- // START KGU#137 2016-01-11: Already prepared by addUndo()
- //root.hasChanged=true;
- // END KGU#137 2016-01-11
- redraw();
- }
- }
-
-
- /*========================================
+ /**
+ * Sets the background colour of the selected element(s) to {@code _color}
+ * (undoable).
+ *
+ * @param _color - the colour to be applied.
+ */
+ public void setColor(Color _color) {
+ // START KGU#911 2021-01-10: Enh. #910
+ //if (getSelected() != null)
+ if (selected != null && !selected.isImmutable())
+ // END KGU#911 2021-01-10
+ {
+ // START KGU#38 2016-01-11 Setting of colour wasn't undoable though recorded as change
+ //root.addUndo();
+ try {
+ addUndoNSD(false);
+ } catch (CancelledException e) {
+ return;
+ }
+ // END KGU#38 2016-01-11
+ selected.setColor(_color);
+ //getSelected().setSelected(false);
+ //selected=null;
+ // START KGU#137 2016-01-11: Already prepared by addUndo()
+ //root.hasChanged=true;
+ // END KGU#137 2016-01-11
+ redraw();
+ }
+ }
+
+
+ /*========================================
* Copy method
*========================================*/
- /**
- * Copies the selected element(s) either to the system clipboard (if a
- * {@link Root} is selected or to an internal cache (otherwise).
- *
- * @see #canCopy()
- * @see #cutNSD()
- * @see #pasteNSD()
- */
- public void copyNSD() {
- if (selected != null) {
- // START KGU#177 2016-04-14: Enh. #158 - Allow to copy a diagram via clipboard
- //eCopy = selected.copy();
- if (selected instanceof Root) {
- XmlGenerator xmlgen = new XmlGenerator();
- StringSelection toClip = new StringSelection(xmlgen.generateCode(root, "\t", false));
- Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
- clipboard.setContents(toClip, this);
- } else {
- eCopy = selected.copy();
- }
- // END KGU#177 2016-04-14
- }
- }
-
- /*========================================
+ /**
+ * Copies the selected element(s) either to the system clipboard (if a
+ * {@link Root} is selected or to an internal cache (otherwise).
+ *
+ * @see #canCopy()
+ * @see #cutNSD()
+ * @see #pasteNSD()
+ */
+ public void copyNSD() {
+ if (selected != null) {
+ // START KGU#177 2016-04-14: Enh. #158 - Allow to copy a diagram via clipboard
+ //eCopy = selected.copy();
+ if (selected instanceof Root) {
+ XmlGenerator xmlgen = new XmlGenerator();
+ StringSelection toClip = new StringSelection(xmlgen.generateCode(root, "\t", false));
+ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ clipboard.setContents(toClip, this);
+ } else {
+ eCopy = selected.copy();
+ }
+ // END KGU#177 2016-04-14
+ }
+ }
+
+ /*========================================
* cut method
*========================================*/
- /**
- * Copies the selected element(s) to an internal cache and then removes them
- * from the current diagram (undoable). Does nothing if {@link #root} is
- * selected.
- *
- * @see #canCut()
- * @see #copyNSD()
- * @see #pasteNSD()
- */
- public void cutNSD() {
- // START KGU#911 2021-01-10: Enh. #910
- //if (selected != null && selected != root)
- if (selected != null && selected != root && !selected.isImmutable()) // END KGU#911 2021-01-10
- {
- eCopy = selected.copy();
- // START KGU#182 2016-04-23: Issue #168 - pass the selection to the "next" element
- Element newSel = getSelectionHeir();
- // END KGU#182 2016-04-23
- eCopy.setSelected(false);
- //root.addUndo();
- try {
- addUndoNSD(false);
- } catch (CancelledException e) {
- return;
- }
- root.removeElement(selected);
- // START KGU#137 2016-01-11: Already prepared by addUndo()
- //root.hasChanged=true;
- // END KGU#137 2016-01-11
- redraw();
- // START KGU#182 2016-04-23: Issue #168 - pass the selection to the "next" element
- //selected=null;
- this.selected = newSel;
- if (newSel != null) {
- // START KGU#477 2017-12-06: Enh. #487 - consider hidden declaration sequences
- //newSel.setSelected(true);
- this.selected = newSel.setSelected(true);
- // END KGU#477 2017-12-06
- }
- // END KGU#182 2016-04-23
- analyse();
- // START KGU#444 2017-10-23: Issue #417 - reduce scrolling complexity
- adaptScrollUnits();
- // END KGU#444 2017-10-23
- // START KGU#705 2019-09-24: Enh. #738
- updateCodePreview();
- // END KGU#705 2019-09-24
- }
- }
-
- /*========================================
+ /**
+ * Copies the selected element(s) to an internal cache and then removes them
+ * from the current diagram (undoable). Does nothing if {@link #root} is
+ * selected.
+ *
+ * @see #canCut()
+ * @see #copyNSD()
+ * @see #pasteNSD()
+ */
+ public void cutNSD() {
+ // START KGU#911 2021-01-10: Enh. #910
+ //if (selected != null && selected != root)
+ if (selected != null && selected != root && !selected.isImmutable())
+ // END KGU#911 2021-01-10
+ {
+ eCopy = selected.copy();
+ // START KGU#182 2016-04-23: Issue #168 - pass the selection to the "next" element
+ Element newSel = getSelectionHeir();
+ // END KGU#182 2016-04-23
+ eCopy.setSelected(false);
+ //root.addUndo();
+ try {
+ addUndoNSD(false);
+ } catch (CancelledException e) {
+ return;
+ }
+ root.removeElement(selected);
+ // START KGU#137 2016-01-11: Already prepared by addUndo()
+ //root.hasChanged=true;
+ // END KGU#137 2016-01-11
+ redraw();
+ // START KGU#182 2016-04-23: Issue #168 - pass the selection to the "next" element
+ //selected=null;
+ this.selected = newSel;
+ if (newSel != null) {
+ // START KGU#477 2017-12-06: Enh. #487 - consider hidden declaration sequences
+ //newSel.setSelected(true);
+ this.selected = newSel.setSelected(true);
+ // END KGU#477 2017-12-06
+ }
+ // END KGU#182 2016-04-23
+ analyse();
+ // START KGU#444 2017-10-23: Issue #417 - reduce scrolling complexity
+ adaptScrollUnits();
+ // END KGU#444 2017-10-23
+ // START KGU#705 2019-09-24: Enh. #738
+ updateCodePreview();
+ // END KGU#705 2019-09-24
+ }
+ }
+
+ /*========================================
* paste method
*========================================*/
- /**
- * Pastes the elements from the internal copy cache to to the next position
- * after the currently selected element(s). Does nothing if the copy cache
- * is empty or nor target elements are selected.
- *
- * @see #canPaste()
- * @see #copyNSD()
- * @see #cutNSD()
- */
- public void pasteNSD() {
- if (selected != null && eCopy != null) {
- //root.addUndo();
- try {
- addUndoNSD(false);
- } catch (CancelledException e) {
- return;
- }
- // START KGU#477 2017-12-06: Enh, #487 - declaration stuff might be collapsed
- selected = selected.setSelected(true);
- // END KGU#477 2017-12-06
- selected.setSelected(false);
- Element nE = eCopy.copy();
- nE.setSelected(true); // FIXME (KGU#87): Looks fine but is misleading with a pasted Subqueue
- // START KGU#477 2017-12-06: Enh, #487 - declaration stuff might be collapsed
- //root.addAfter(selected, nE);
- root.addAfter(getLastSelected(), nE);
- // END KGU#477 2017-12-06
- // START KGU#137 2016-01-11: Already prepared by addUndo()
- //root.hasChanged=true;
- // END KGU#137 2016-01-11
- // START KGU#87 2015-11-22: In case of a copied Subqueue the copy shouldn't be selected!
- //selected=nE;
- if (nE instanceof Subqueue) {
- // If the target was a Subqueue then it had been empty and contains all nE had contained,
- // hence we may leave it selected, otherwise the minimum risk is to clear the selection
- if (!(selected instanceof Subqueue)) {
- selected = null;
- }
- ((Subqueue) nE).clear();
- } else {
- selected = nE;
- }
- // END KGU#87 2015-11-22
- redraw();
- analyse();
- // START KGU#444 2017-10-23: Issue #417 - reduce scrolling complexity
- adaptScrollUnits();
- // END KGU#444 2017-10-23
- // START KGU#705 2019-09-24: Enh. #738
- updateCodePreview();
- // END KGU#705 2019-09-24
- }
- }
-
- /*========================================
+ /**
+ * Pastes the elements from the internal copy cache to to the next position
+ * after the currently selected element(s). Does nothing if the copy cache
+ * is empty or nor target elements are selected.
+ *
+ * @see #canPaste()
+ * @see #copyNSD()
+ * @see #cutNSD()
+ */
+ public void pasteNSD() {
+ if (selected != null && eCopy != null) {
+ //root.addUndo();
+ try {
+ addUndoNSD(false);
+ } catch (CancelledException e) {
+ return;
+ }
+ // START KGU#477 2017-12-06: Enh, #487 - declaration stuff might be collapsed
+ selected = selected.setSelected(true);
+ // END KGU#477 2017-12-06
+ selected.setSelected(false);
+ Element nE = eCopy.copy();
+ nE.setSelected(true); // FIXME (KGU#87): Looks fine but is misleading with a pasted Subqueue
+ // START KGU#477 2017-12-06: Enh, #487 - declaration stuff might be collapsed
+ //root.addAfter(selected, nE);
+ root.addAfter(getLastSelected(), nE);
+ // END KGU#477 2017-12-06
+ // START KGU#137 2016-01-11: Already prepared by addUndo()
+ //root.hasChanged=true;
+ // END KGU#137 2016-01-11
+ // START KGU#87 2015-11-22: In case of a copied Subqueue the copy shouldn't be selected!
+ //selected=nE;
+ if (nE instanceof Subqueue) {
+ // If the target was a Subqueue then it had been empty and contains all nE had contained,
+ // hence we may leave it selected, otherwise the minimum risk is to clear the selection
+ if (!(selected instanceof Subqueue)) {
+ selected = null;
+ }
+ ((Subqueue) nE).clear();
+ } else {
+ selected = nE;
+ }
+ // END KGU#87 2015-11-22
+ redraw();
+ analyse();
+ // START KGU#444 2017-10-23: Issue #417 - reduce scrolling complexity
+ adaptScrollUnits();
+ // END KGU#444 2017-10-23
+ // START KGU#705 2019-09-24: Enh. #738
+ updateCodePreview();
+ // END KGU#705 2019-09-24
+ }
+ }
+
+ /*========================================
* edit method
*========================================*/
- /**
- * Opens the editor for the currently selected element and applies the
- * committed changes (undoable).
- *
- * @return true if the element was changed, false otherwise
- * @see #canEdit()
- */
- public boolean editNSD() {
- boolean modified = false;
- Element element = getSelected();
- if (element != null) {
- // START KGU#911 2021-01-11: Enh. #910 Avert changes on immutable diagrams
- boolean mayCommit = !element.isImmutable() && !element.isExecuted();
- // END KGU#911 2021-01-11
- if (element.getClass().getSimpleName().equals("Subqueue")) {
- // START KGU#911 2021-01-11: Enh. #910 Avert changes on immutable diagrams
- if (!mayCommit) {
- return modified;
- }
- // END KGU#911 2021-01-11
-
- EditData data = new EditData();
- data.title = "Add new instruction ...";
-
- // START KGU#42 2015-10-14: Enhancement for easier title localisation
- //showInputBox(data);
- showInputBox(data, "Instruction", true, true);
- // END KGU#42 2015-10-14
-
- if (data.result == true) {
- // START KGU#480 2018-01-21: Enh. #490 we have to replace DiagramController aliases by the original names
- //Element ele = new Instruction(data.text.getText());
- String text = Element.replaceControllerAliases(data.text.getText(), false, false);
- Element ele = new Instruction(text);
- // END KGU#480 2018-01-21
- ele.setComment(data.comment.getText());
- // START KGU#43 2015-10-17
- if (data.breakpoint) {
- ele.toggleBreakpoint();
- }
- // END KGU#43 2015-10-17
- // START KGU#277 2016-10-13: Enh. #270
- ele.setDisabled(data.disabled);
- // END KGU#277 2016-10-13
- // START KGU#213 2016-08-01: Enh. #215 (temporarily disabled again)
- //ele.setBreakTriggerCount(data.breakTriggerCount);
- // END KGU#213 2016-08-01
- //root.addUndo();
- try {
- addUndoNSD(false);
- } catch (CancelledException e) {
- return false;
- }
- // START KGU#137 2016-01-11: Already prepared by addUndo()
- //root.hasChanged=true;
- // END KGU#137 2016-01-11
- ((Subqueue) element).addElement(ele);
- // START KGU#136 2016-03-01: Bugfix #97
- element.resetDrawingInfoUp();
- // END KGU#136 2016-03-01
- selected = ele.setSelected(true);
- modified = true;
- redraw();
- }
- } else {
- EditData data = new EditData();
- data.title = "Edit element ...";
- // START KGU#480 2018-01-21: Enh. #490 we have to replace DiagramController aliases by the original names
- //data.text.setText(element.getText().getText());
- data.text.setText(element.getAliasText().getText());
- // END KGU#480 2018-01-21
- data.comment.setText(element.getComment().getText());
- // START KGU#43 2015-10-12
- data.breakpoint = element.isBreakpoint();
- // END KGU#43 2015-10-12
- // START KGU#213 2016-08-01: Enh. #215
- data.breakTriggerCount = element.getBreakTriggerCount();
- // END KGU#213 2016-08-01
- // START KGU#277 2016-10-13: Enh. #270
- data.disabled = element.isDisabled(true);
- // END KGU#277 2016-10-13
-
- // START KGU#3 2015-10-25: Allow more sophisticated For loop editing
- if (element instanceof For) {
- // START KGU#61 2016-03-21: Content of the branch outsourced
- preEditFor(data, (For) element);
- // END KGU#61 2016-03-21
- } // END KGU#3 2015-10-25
- // START KGU#363 2017-03-14: Enh. #372
- else if (element instanceof Root) {
-// data.authorName = ((Root)element).getAuthor();
-// data.licenseName = ((Root)element).licenseName;
-// data.licenseText = ((Root)element).licenseText;
- data.licInfo = new RootAttributes((Root) element);
- // START KGU#376 2017-07-01: Enh. #389
- data.diagramRefs = ((Root) element).includeList;
- // END KGU#376 2017-07-01
- } // END KGU#363 2017-03-14
- // START KGU#695 2021-01-22: Enh. #714
- else if (element instanceof Try) {
- data.showFinally = ((Try) element).isEmptyFinallyVisible();
- } // END KGU#695 2021-01-22
- // START KGU#927 2021-02-07: Enh. #915 Which branches contain elements?
- else if (element instanceof Case) {
- data.branchOrder = new int[((Case) element).qs.size()];
- for (int i = 0; i < data.branchOrder.length; i++) {
- if (((Case) element).qs.get(i).getSize() > 0) {
- data.branchOrder[i] = i + 1;
- } else {
- data.branchOrder[i] = 0;
- }
- }
- }
- // END KGU#927 2021-02-07
-
- // START KGU#42 2015-10-14: Enhancement for easier title localisation
- //showInputBox(data);
- // START KGU#946 2021-02-28: We could get wrong Root type information when induced from errorlist
- //showInputBox(data, element.getClass().getSimpleName(), false, mayCommit);
- String elemType = element.getClass().getSimpleName();
- if (element instanceof Root) {
- if (((Root) element).isSubroutine()) {
- elemType = "Function";
- } else if (((Root) element).isInclude()) {
- elemType = "Includable";
- }
- }
- showInputBox(data, elemType, false, mayCommit);
- // END KGU#946 2021-02-28
- // END KGU#42 2015-10-14
-
- if (data.result == true) {
- // START KGU#120 2016-01-02: Bugfix #85 - StringList changes of Root are to be undoable, too!
- //if (!element.getClass().getSimpleName().equals("Root"))
- // END KGU#120 2016-01-02
- // START KGU#363 2017-05-21: Enh. #372:
- // Also cache root attributes if the edited element is a Root
- //root.addUndo();
- // START KGU#684 2019-06-13: Bugfix #728 - we have to check more here
- //root.addUndo(element instanceof Root);
- try {
- this.addUndoNSD(element instanceof Root);
- } catch (CancelledException e) {
- return false;
- }
- // END KGU#684 2019-06-13
- // END KGU#363 2017-05-21
- // START KGU#916 2021-01-24: Enh. #915 We may preserve branch associations now
- // This must be done before the text is updated!
- if (element instanceof Case) {
- ((Case) element).reorderBranches(data.branchOrder);
- }
- // END KGU#916 2021-01-24
- if (!(element instanceof Forever)) {
- // START KGU#480 2018-01-21: Enh. #490 we have to replace DiagramController aliases by the original names
- //element.setText(data.text.getText());
- element.setAliasText(data.text.getText());
- // END KGU#480 2018-01-21
- }
- element.setComment(data.comment.getText());
- // START KGU#43 2015-10-12
- if (element.isBreakpoint() != data.breakpoint) {
- element.toggleBreakpoint();
- }
- // END KGU#43 2015-10-12
- // START KGU#213 2016-08-01: Enh. #215
- //element.setBreakTriggerCount(data.breakTriggerCount);
- // END KGU#213 2016-08-01
- // START KGU#277 2016-10-13: Enh. #270
- element.setDisabled(data.disabled);
- // END KGU#277 2016-10-13
- // START KGU#3 2015-10-25
- if (element instanceof For) {
- // START KGU#61 2016-03-21: Content of the branch outsourced
- postEditFor(data, (For) element);
- // END KGU#61 2016-03-21
- } // END KGU#3 2015-10-25
- // START KGU#363 2017-03-14: Enh. #372
- else if (element instanceof Root) {
- ((Root) element).adoptAttributes(data.licInfo);
- // START KGU#376 2017-07-01: Enh. #389
- ((Root) element).includeList = data.diagramRefs;
- // END KGU#376 2017-07-01
- } // END KGU#363 2017-03-14
- // START KGU#695 2021-01-22: Enh. #714
- else if (element instanceof Try) {
- ((Try) element).setEmptyFinallyVisible(data.showFinally);
- }
- // END KGU#695 2021-01-22
- // START KGU#137 2016-01-11: Already prepared by addUndo()
- //root.hasChanged=true;
- // END KGU#137 2016-01-11
- // START KGU#136 2016-03-01: Bugfix #97
- element.resetDrawingInfoUp();
- // END KGU#136 2016-03-01
- modified = true;
- redraw();
- }
- }
-
- analyse();
- // START KGU#444 2017-10-23: Issue #417 - reduce scrolling complexity
- adaptScrollUnits();
- // END KGU#444 2017-10-23
- // START KGU#705 2019-09-23: Enh. #738
- if (modified) {
- this.updateCodePreview();
- }
- // END KGU#705 2019-09-23
- }
- return modified;
- }
-
- private void preEditFor(EditData _data, For _for) {
- // Cache the style - we temporarily modify it to get all information
- For.ForLoopStyle style = _for.style;
- try {
- _for.style = For.ForLoopStyle.COUNTER;
- _data.forParts.add(_for.getCounterVar());
- // START KGU#480 2018-01-22: Enh. #490 - maybe aliases are to be put in
- //_data.forParts.add(_for.getStartValue());
- //_data.forParts.add(_for.getEndValue());
- _data.forParts.add(Element.replaceControllerAliases(_for.getStartValue(), true, false));
- _data.forParts.add(Element.replaceControllerAliases(_for.getEndValue(), true, false));
- // END KGU#480 2018-01-22
- _data.forParts.add(Integer.toString(_for.getStepConst()));
- } catch (Exception ex) {
- } finally {
- // Ensure the original style is restored
- _data.forLoopStyle = _for.style = style;
- }
- // Now try to get a value list in case it's a FOR-IN loop
- String valueList = _for.getValueList();
- if (valueList != null) {
- // START KGU#480 2018-01-22: Enh. #490 - maybe aliases are to be put in
- valueList = Element.replaceControllerAliases(valueList, true, false);
- // END KGU#480 2018-01-22
- _data.forParts.add(valueList);
- }
- }
-
- private void postEditFor(EditData _data, For _for) {
- _for.style = _data.forLoopStyle;
-
- _for.setCounterVar(_data.forParts.get(0));
- // START KGU#480 2018-01-22: Enh. #490 - maybe aliases are to be replaced
- //_for.setStartValue(_data.forParts.get(1));
- //_for.setEndValue(_data.forParts.get(2));
- _for.setStartValue(Element.replaceControllerAliases(_data.forParts.get(1), false, false));
- _for.setEndValue(Element.replaceControllerAliases(_data.forParts.get(2), false, false));
- // END KGU#480 2018-01-22
- _for.setStepConst(_data.forParts.get(3));
-
- // FOR-IN loop support
- if (_for.style == For.ForLoopStyle.TRAVERSAL) {
- // START KGU#61 2016-09-24: Seemed to be nonsense
- //_for.style = For.ForLoopStyle.FREETEXT;
- //_for.setValueList(_for.getValueList());
- //_for.style = For.ForLoopStyle.TRAVERSAL;
- // START KGU#480 2018-01-22: Enh. #490 - maybe aliases are to be replaced
- //_for.setValueList(_data.forParts.get(4));
- _for.setValueList(Element.replaceControllerAliases(_data.forParts.get(4), false, false));
- // END KGU#480 2018-01-22
- // END KGU#61 2016-09-24
- } // START KGU#61 2016-09-24
- else {
- _for.setValueList(null);
- }
- // END KGU#61 2016-09-24
- /*/ START KGU 2018-01-22: This code differed from that in addNewElement with respect to the
- * following statement missing here so far, which seemed to make sense in case of inconsistency,
- * though. So it was added as part of the unification - it forces FREETEXT flavour in due cases.
- */
- _for.style = _for.classifyStyle();
- // END KGU 2018-01-22
-
- }
-
- /*========================================
+ /**
+ * Opens the editor for the currently selected element and applies the
+ * committed changes (undoable).
+ *
+ * @return true if the element was changed, false otherwise
+ * @see #canEdit()
+ */
+ public boolean editNSD() {
+ boolean modified = false;
+ Element element = getSelected();
+ if (element != null) {
+ // START KGU#911 2021-01-11: Enh. #910 Avert changes on immutable diagrams
+ boolean mayCommit = !element.isImmutable() && !element.isExecuted();
+ // END KGU#911 2021-01-11
+ if (element.getClass().getSimpleName().equals("Subqueue")) {
+ // START KGU#911 2021-01-11: Enh. #910 Avert changes on immutable diagrams
+ if (!mayCommit) {
+ return modified;
+ }
+ // END KGU#911 2021-01-11
+
+ EditData data = new EditData();
+ data.title = "Add new instruction ...";
+
+ // START KGU#42 2015-10-14: Enhancement for easier title localisation
+ //showInputBox(data);
+ showInputBox(data, "Instruction", true, true);
+ // END KGU#42 2015-10-14
+
+ if (data.result == true) {
+ // START KGU#480 2018-01-21: Enh. #490 we have to replace DiagramController aliases by the original names
+ //Element ele = new Instruction(data.text.getText());
+ String text = Element.replaceControllerAliases(data.text.getText(), false, false);
+ Element ele = new Instruction(text);
+ // END KGU#480 2018-01-21
+ ele.setComment(data.comment.getText());
+ // START KGU#43 2015-10-17
+ if (data.breakpoint) {
+ ele.toggleBreakpoint();
+ }
+ // END KGU#43 2015-10-17
+ // START KGU#277 2016-10-13: Enh. #270
+ ele.setDisabled(data.disabled);
+ // END KGU#277 2016-10-13
+ // START KGU#213 2016-08-01: Enh. #215 (temporarily disabled again)
+ //ele.setBreakTriggerCount(data.breakTriggerCount);
+ // END KGU#213 2016-08-01
+ //root.addUndo();
+ try {
+ addUndoNSD(false);
+ } catch (CancelledException e) {
+ return false;
+ }
+ // START KGU#137 2016-01-11: Already prepared by addUndo()
+ //root.hasChanged=true;
+ // END KGU#137 2016-01-11
+ ((Subqueue) element).addElement(ele);
+ // START KGU#136 2016-03-01: Bugfix #97
+ element.resetDrawingInfoUp();
+ // END KGU#136 2016-03-01
+ selected = ele.setSelected(true);
+ modified = true;
+ redraw();
+ }
+ } else {
+ EditData data = new EditData();
+ data.title = "Edit element ...";
+ // START KGU#480 2018-01-21: Enh. #490 we have to replace DiagramController aliases by the original names
+ //data.text.setText(element.getText().getText());
+ data.text.setText(element.getAliasText().getText());
+ // END KGU#480 2018-01-21
+ data.comment.setText(element.getComment().getText());
+ // START KGU#43 2015-10-12
+ data.breakpoint = element.isBreakpoint();
+ // END KGU#43 2015-10-12
+ // START KGU#213 2016-08-01: Enh. #215
+ data.breakTriggerCount = element.getBreakTriggerCount();
+ // END KGU#213 2016-08-01
+ // START KGU#277 2016-10-13: Enh. #270
+ data.disabled = element.isDisabled(true);
+ // END KGU#277 2016-10-13
+
+ // START KGU#3 2015-10-25: Allow more sophisticated For loop editing
+ if (element instanceof For) {
+ // START KGU#61 2016-03-21: Content of the branch outsourced
+ preEditFor(data, (For) element);
+ // END KGU#61 2016-03-21
+ }
+ // END KGU#3 2015-10-25
+ // START KGU#363 2017-03-14: Enh. #372
+ else if (element instanceof Root) {
+ // data.authorName = ((Root)element).getAuthor();
+ // data.licenseName = ((Root)element).licenseName;
+ // data.licenseText = ((Root)element).licenseText;
+ data.licInfo = new RootAttributes((Root) element);
+ // START KGU#376 2017-07-01: Enh. #389
+ data.diagramRefs = ((Root) element).includeList;
+ // END KGU#376 2017-07-01
+ }
+ // END KGU#363 2017-03-14
+ // START KGU#695 2021-01-22: Enh. #714
+ else if (element instanceof Try) {
+ data.showFinally = ((Try) element).isEmptyFinallyVisible();
+ }
+ // END KGU#695 2021-01-22
+ // START KGU#927 2021-02-07: Enh. #915 Which branches contain elements?
+ else if (element instanceof Case) {
+ data.branchOrder = new int[((Case) element).qs.size()];
+ for (int i = 0; i < data.branchOrder.length; i++) {
+ if (((Case) element).qs.get(i).getSize() > 0) {
+ data.branchOrder[i] = i + 1;
+ } else {
+ data.branchOrder[i] = 0;
+ }
+ }
+ }
+ // END KGU#927 2021-02-07
+
+ // START KGU#42 2015-10-14: Enhancement for easier title localisation
+ //showInputBox(data);
+ // START KGU#946 2021-02-28: We could get wrong Root type information when induced from errorlist
+ //showInputBox(data, element.getClass().getSimpleName(), false, mayCommit);
+ String elemType = element.getClass().getSimpleName();
+ if (element instanceof Root) {
+ if (((Root) element).isSubroutine()) {
+ elemType = "Function";
+ } else if (((Root) element).isInclude()) {
+ elemType = "Includable";
+ }
+ }
+ showInputBox(data, elemType, false, mayCommit);
+ // END KGU#946 2021-02-28
+ // END KGU#42 2015-10-14
+
+ if (data.result == true) {
+ // START KGU#120 2016-01-02: Bugfix #85 - StringList changes of Root are to be undoable, too!
+ //if (!element.getClass().getSimpleName().equals("Root"))
+ // END KGU#120 2016-01-02
+ // START KGU#363 2017-05-21: Enh. #372:
+ // Also cache root attributes if the edited element is a Root
+ //root.addUndo();
+ // START KGU#684 2019-06-13: Bugfix #728 - we have to check more here
+ //root.addUndo(element instanceof Root);
+ try {
+ this.addUndoNSD(element instanceof Root);
+ } catch (CancelledException e) {
+ return false;
+ }
+ // END KGU#684 2019-06-13
+ // END KGU#363 2017-05-21
+ // START KGU#916 2021-01-24: Enh. #915 We may preserve branch associations now
+ // This must be done before the text is updated!
+ if (element instanceof Case) {
+ ((Case) element).reorderBranches(data.branchOrder);
+ }
+ // END KGU#916 2021-01-24
+ if (!(element instanceof Forever)) {
+ // START KGU#480 2018-01-21: Enh. #490 we have to replace DiagramController aliases by the original names
+ //element.setText(data.text.getText());
+ element.setAliasText(data.text.getText());
+ // END KGU#480 2018-01-21
+ }
+ element.setComment(data.comment.getText());
+ // START KGU#43 2015-10-12
+ if (element.isBreakpoint() != data.breakpoint) {
+ element.toggleBreakpoint();
+ }
+ // END KGU#43 2015-10-12
+ // START KGU#213 2016-08-01: Enh. #215
+ //element.setBreakTriggerCount(data.breakTriggerCount);
+ // END KGU#213 2016-08-01
+ // START KGU#277 2016-10-13: Enh. #270
+ element.setDisabled(data.disabled);
+ // END KGU#277 2016-10-13
+ // START KGU#3 2015-10-25
+ if (element instanceof For) {
+ // START KGU#61 2016-03-21: Content of the branch outsourced
+ postEditFor(data, (For) element);
+ // END KGU#61 2016-03-21
+ }
+ // END KGU#3 2015-10-25
+ // START KGU#363 2017-03-14: Enh. #372
+ else if (element instanceof Root) {
+ ((Root) element).adoptAttributes(data.licInfo);
+ // START KGU#376 2017-07-01: Enh. #389
+ ((Root) element).includeList = data.diagramRefs;
+ // END KGU#376 2017-07-01
+ }
+ // END KGU#363 2017-03-14
+ // START KGU#695 2021-01-22: Enh. #714
+ else if (element instanceof Try) {
+ ((Try) element).setEmptyFinallyVisible(data.showFinally);
+ }
+ // END KGU#695 2021-01-22
+ // START KGU#137 2016-01-11: Already prepared by addUndo()
+ //root.hasChanged=true;
+ // END KGU#137 2016-01-11
+ // START KGU#136 2016-03-01: Bugfix #97
+ element.resetDrawingInfoUp();
+ // END KGU#136 2016-03-01
+ modified = true;
+ redraw();
+ }
+ }
+
+ analyse();
+ // START KGU#444 2017-10-23: Issue #417 - reduce scrolling complexity
+ adaptScrollUnits();
+ // END KGU#444 2017-10-23
+ // START KGU#705 2019-09-23: Enh. #738
+ if (modified) {
+ this.updateCodePreview();
+ }
+ // END KGU#705 2019-09-23
+ }
+ return modified;
+ }
+
+ private void preEditFor(EditData _data, For _for) {
+ // Cache the style - we temporarily modify it to get all information
+ For.ForLoopStyle style = _for.style;
+ try {
+ _for.style = For.ForLoopStyle.COUNTER;
+ _data.forParts.add(_for.getCounterVar());
+ // START KGU#480 2018-01-22: Enh. #490 - maybe aliases are to be put in
+ //_data.forParts.add(_for.getStartValue());
+ //_data.forParts.add(_for.getEndValue());
+ _data.forParts.add(Element.replaceControllerAliases(_for.getStartValue(), true, false));
+ _data.forParts.add(Element.replaceControllerAliases(_for.getEndValue(), true, false));
+ // END KGU#480 2018-01-22
+ _data.forParts.add(Integer.toString(_for.getStepConst()));
+ } catch (Exception ex) {
+ } finally {
+ // Ensure the original style is restored
+ _data.forLoopStyle = _for.style = style;
+ }
+ // Now try to get a value list in case it's a FOR-IN loop
+ String valueList = _for.getValueList();
+ if (valueList != null) {
+ // START KGU#480 2018-01-22: Enh. #490 - maybe aliases are to be put in
+ valueList = Element.replaceControllerAliases(valueList, true, false);
+ // END KGU#480 2018-01-22
+ _data.forParts.add(valueList);
+ }
+ }
+
+ private void postEditFor(EditData _data, For _for) {
+ _for.style = _data.forLoopStyle;
+
+ _for.setCounterVar(_data.forParts.get(0));
+ // START KGU#480 2018-01-22: Enh. #490 - maybe aliases are to be replaced
+ //_for.setStartValue(_data.forParts.get(1));
+ //_for.setEndValue(_data.forParts.get(2));
+ _for.setStartValue(Element.replaceControllerAliases(_data.forParts.get(1), false, false));
+ _for.setEndValue(Element.replaceControllerAliases(_data.forParts.get(2), false, false));
+ // END KGU#480 2018-01-22
+ _for.setStepConst(_data.forParts.get(3));
+
+ // FOR-IN loop support
+ if (_for.style == For.ForLoopStyle.TRAVERSAL) {
+ // START KGU#61 2016-09-24: Seemed to be nonsense
+ //_for.style = For.ForLoopStyle.FREETEXT;
+ //_for.setValueList(_for.getValueList());
+ //_for.style = For.ForLoopStyle.TRAVERSAL;
+ // START KGU#480 2018-01-22: Enh. #490 - maybe aliases are to be replaced
+ //_for.setValueList(_data.forParts.get(4));
+ _for.setValueList(Element.replaceControllerAliases(_data.forParts.get(4), false, false));
+ // END KGU#480 2018-01-22
+ // END KGU#61 2016-09-24
+ }
+ // START KGU#61 2016-09-24
+ else {
+ _for.setValueList(null);
+ }
+ // END KGU#61 2016-09-24
+ /* START KGU 2018-01-22: This code differed from that in addNewElement
+ * with respect to the following statement missing here so far, which
+ * seemed to make sense in case of inconsistency, though. So it was added
+ * as part of the unification - it forces FREETEXT flavour in due cases.
+ */
+ _for.style = _for.classifyStyle();
+ /* END KGU 2018-01-22 */
+
+ }
+
+ /*========================================
* moveUp method
*========================================*/
- /**
- * Moves the selected element(s) one position up in the current diagram
- * (undoable).
- *
- * @see Element#canMoveUp()
- */
- public void moveUpNSD() {
- //root.addUndo();
- try {
- addUndoNSD(false);
- } catch (CancelledException e) {
- return;
- }
- root.moveUp(getSelected());
- redraw();
- analyse();
- // START KGU#705 2019-09-23: Enh. #738
- updateCodePreview();
- // END KGU#705 2019-09-23
- }
-
- /*========================================
+ /**
+ * Moves the selected element(s) one position up in the current diagram
+ * (undoable).
+ *
+ * @see Element#canMoveUp()
+ */
+ public void moveUpNSD() {
+ //root.addUndo();
+ try {
+ addUndoNSD(false);
+ } catch (CancelledException e) {
+ return;
+ }
+ root.moveUp(getSelected());
+ redraw();
+ analyse();
+ // START KGU#705 2019-09-23: Enh. #738
+ updateCodePreview();
+ // END KGU#705 2019-09-23
+ }
+
+ /*========================================
* moveDown method
*========================================*/
- /**
- * Moves the selected element(s) one position down in the current diagram
- * (undoable).
- *
- * @see Element#canMoveDown()
- */
- public void moveDownNSD() {
- //root.addUndo();
- try {
- addUndoNSD(false);
- } catch (CancelledException e) {
- return;
- }
- root.moveDown(getSelected());
- redraw();
- analyse();
- // START KGU#705 2019-09-23: Enh. #738
- updateCodePreview();
- // END KGU#705 2019-09-23
- }
-
- /*========================================
+ /**
+ * Moves the selected element(s) one position down in the current diagram
+ * (undoable).
+ *
+ * @see Element#canMoveDown()
+ */
+ public void moveDownNSD() {
+ //root.addUndo();
+ try {
+ addUndoNSD(false);
+ } catch (CancelledException e) {
+ return;
+ }
+ root.moveDown(getSelected());
+ redraw();
+ analyse();
+ // START KGU#705 2019-09-23: Enh. #738
+ updateCodePreview();
+ // END KGU#705 2019-09-23
+ }
+
+ /*========================================
* delete method
*========================================*/
- /**
- * Removes the selected element(s) fro the current diagram (undoable).
- *
- * @see #canCut()
- */
- public void deleteNSD() {
- //root.addUndo();
- try {
- addUndoNSD(false);
- } catch (CancelledException e) {
- return;
- }
- // START KGU#181 2016-04-19: Issue #164 - pass the selection to the "next" element
- Element newSel = getSelectionHeir();
- // END KGU#181 2016-04-19
- root.removeElement(getSelected());
- // START KGU#138 2016-01-11: Bugfix #102 - selection no longer valid
- // START KGU#181 2016-04-19: Issue #164 - pass the selection to the "next" element
- //this.selected = null;
- this.selected = newSel;
- if (newSel != null) {
- // START KGU#477 2017-12-06: Enh. #487 - consider hidden declaration sequences
- //newSel.setSelected(true);
- this.selected = newSel.setSelected(true);
- // END KGU#477 2017-12-06
- }
- // END KGU#181 2016-04-19
- // END KGU#138 2016-01-11
- redraw();
- analyse();
- // START KGU#138 2016-01-11: Bugfix#102 - disable element-based buttons
- this.NSDControl.doButtons();
- // END KGU#138 2016-01-11
- // START KGU#444 2017-10-23: Issue #417 - reduce scrolling complexity
- adaptScrollUnits();
- // END KGU#444 2017-10-23
- // START KGU#705 2019-09-23: Enh. #738
- this.updateCodePreview();
- // END KGU#705 2019-09-23
- }
-
- // START KGU#181 2016-04-19: Issue #164 - pass the selection to the "next" element
- /**
- * Returns the element "inheriting" the selection from the doomed currently
- * selected element This will be (if existent): 1. successor within
- * Subqueue, 2. predecessor within Subqueue Requires this.selected to be
- * neither Root nor an empty Subqueue.
- *
- * @return the element next the currently selected one, null if there is no
- * selection
- */
- private Element getSelectionHeir() {
- Element heir = null;
- if (selected != null && !(selected instanceof Root)) {
- Subqueue sq = (Subqueue) ((selected instanceof Subqueue) ? selected : selected.parent);
- int ixHeir = -1;
- if (selected instanceof SelectedSequence) {
- // Last element of the subsequence
- Element last = ((SelectedSequence) selected).getElement(((SelectedSequence) selected).getSize() - 1);
- Element frst = ((SelectedSequence) selected).getElement(0);
- int ixLast = sq.getIndexOf(last); // Actual index of the last element in the Subqueue
- int ixFrst = sq.getIndexOf(frst); // Actual index of the first element in the Subqueue
- if (ixLast < sq.getSize() - 1) {
- ixHeir = ixLast + 1;
- } else if (ixFrst > 0) {
- ixHeir = ixFrst - 1;
- }
- } else if (!(selected instanceof Subqueue)) {
- int ixEle = sq.getIndexOf(selected);
- if (ixEle < sq.getSize() - 1) {
- ixHeir = ixEle + 1;
- } else {
- ixHeir = ixEle - 1;
- }
- }
- if (ixHeir >= 0) {
- heir = sq.getElement(ixHeir);
- } else {
- // Empty Subqueue remnant will take over selection
- heir = sq;
- }
- }
- return heir;
- }
- // END KGU#181 2016-04-19
-
- // START KGU#123 2016-01-03: Issue #65, for new buttons and menu items
- /*========================================
+ /**
+ * Removes the selected element(s) fro the current diagram (undoable).
+ *
+ * @see #canCut()
+ */
+ public void deleteNSD() {
+ //root.addUndo();
+ try {
+ addUndoNSD(false);
+ } catch (CancelledException e) {
+ return;
+ }
+ // START KGU#181 2016-04-19: Issue #164 - pass the selection to the "next" element
+ Element newSel = getSelectionHeir();
+ // END KGU#181 2016-04-19
+ root.removeElement(getSelected());
+ // START KGU#138 2016-01-11: Bugfix #102 - selection no longer valid
+ // START KGU#181 2016-04-19: Issue #164 - pass the selection to the "next" element
+ //this.selected = null;
+ this.selected = newSel;
+ if (newSel != null) {
+ // START KGU#477 2017-12-06: Enh. #487 - consider hidden declaration sequences
+ //newSel.setSelected(true);
+ this.selected = newSel.setSelected(true);
+ // END KGU#477 2017-12-06
+ }
+ // END KGU#181 2016-04-19
+ // END KGU#138 2016-01-11
+ redraw();
+ analyse();
+ // START KGU#138 2016-01-11: Bugfix#102 - disable element-based buttons
+ this.NSDControl.doButtons();
+ // END KGU#138 2016-01-11
+ // START KGU#444 2017-10-23: Issue #417 - reduce scrolling complexity
+ adaptScrollUnits();
+ // END KGU#444 2017-10-23
+ // START KGU#705 2019-09-23: Enh. #738
+ this.updateCodePreview();
+ // END KGU#705 2019-09-23
+ }
+
+ // START KGU#181 2016-04-19: Issue #164 - pass the selection to the "next" element
+ /**
+ * Returns the element "inheriting" the selection from the doomed currently
+ * selected element This will be (if existent): 1. successor within
+ * Subqueue, 2. predecessor within Subqueue Requires this.selected to be
+ * neither Root nor an empty Subqueue.
+ *
+ * @return the element next the currently selected one, null if there is no
+ * selection
+ */
+ private Element getSelectionHeir() {
+ Element heir = null;
+ if (selected != null && !(selected instanceof Root)) {
+ Subqueue sq = (Subqueue) ((selected instanceof Subqueue) ? selected : selected.parent);
+ int ixHeir = -1;
+ if (selected instanceof SelectedSequence) {
+ // Last element of the subsequence
+ Element last = ((SelectedSequence) selected).getElement(((SelectedSequence) selected).getSize() - 1);
+ Element frst = ((SelectedSequence) selected).getElement(0);
+ int ixLast = sq.getIndexOf(last); // Actual index of the last element in the Subqueue
+ int ixFrst = sq.getIndexOf(frst); // Actual index of the first element in the Subqueue
+ if (ixLast < sq.getSize() - 1) {
+ ixHeir = ixLast + 1;
+ } else if (ixFrst > 0) {
+ ixHeir = ixFrst - 1;
+ }
+ } else if (!(selected instanceof Subqueue)) {
+ int ixEle = sq.getIndexOf(selected);
+ if (ixEle < sq.getSize() - 1) {
+ ixHeir = ixEle + 1;
+ } else {
+ ixHeir = ixEle - 1;
+ }
+ }
+ if (ixHeir >= 0) {
+ heir = sq.getElement(ixHeir);
+ } else {
+ // Empty Subqueue remnant will take over selection
+ heir = sq;
+ }
+ }
+ return heir;
+ }
+ // END KGU#181 2016-04-19
+
+ // START KGU#123 2016-01-03: Issue #65, for new buttons and menu items
+ /*========================================
* collapse method
*========================================*/
- /**
- * Marks the selected element(s) as collapsed such that they are represented
- * by a surrogate the size of a simple instruction on drawing.
- *
- * @see #expandNSD()
- */
- public void collapseNSD() {
- getSelected().setCollapsed(true);
- redraw();
- analyse();
- this.NSDControl.doButtons();
- // START KGU#444 2017-10-23: Issue #417 - reduce scrolling complexity
- adaptScrollUnits();
- // END KGU#444 2017-10-23
- }
-
- /*========================================
+ /**
+ * Marks the selected element(s) as collapsed such that they are represented
+ * by a surrogate the size of a simple instruction on drawing.
+ *
+ * @see #expandNSD()
+ */
+ public void collapseNSD() {
+ getSelected().setCollapsed(true);
+ redraw();
+ analyse();
+ this.NSDControl.doButtons();
+ // START KGU#444 2017-10-23: Issue #417 - reduce scrolling complexity
+ adaptScrollUnits();
+ // END KGU#444 2017-10-23
+ }
+
+ /*========================================
* expand method
*========================================*/
- /**
- * Removes the collapsed flag from the selected elements such that they get
- * represented in their usual shape again on drawing the diagram.
- *
- * @see #collapseNSD()
- */
- public void expandNSD() {
- getSelected().setCollapsed(false);
- redraw();
- analyse();
- this.NSDControl.doButtons();
- // START KGU#444 2017-10-23: Issue #417 - reduce scrolling complexity
- adaptScrollUnits();
- // END KGU#444 2017-10-23
- }
- // END KGU#123 2016-01-03
-
- // START KGU#277 2016-10-13: Enh. #270
- /*========================================
+ /**
+ * Removes the collapsed flag from the selected elements such that they get
+ * represented in their usual shape again on drawing the diagram.
+ *
+ * @see #collapseNSD()
+ */
+ public void expandNSD() {
+ getSelected().setCollapsed(false);
+ redraw();
+ analyse();
+ this.NSDControl.doButtons();
+ // START KGU#444 2017-10-23: Issue #417 - reduce scrolling complexity
+ adaptScrollUnits();
+ // END KGU#444 2017-10-23
+ }
+ // END KGU#123 2016-01-03
+
+ // START KGU#277 2016-10-13: Enh. #270
+ /*========================================
* disable method
*=======================================*/
- /**
- * Flips the disabled flag on the selected element(s). If several elements
- * are selected, some of which are disabled while others are not, then
- * disables all of them. To disable an element means that it gets handled
- * like a comment on execution and export (undoable).
- */
- public void disableNSD() {
- // START KGU#911 2021-01-10: Enh. 910
- if (selected != null && selected.isImmutable()) {
- return;
- }
- // END KGU#911 2021-01-10
- boolean allDisabled = true;
- //root.addUndo();
- try {
- addUndoNSD(false);
- } catch (CancelledException e) {
- return;
- }
- if (getSelected() instanceof IElementSequence) {
- IElementSequence elements = (IElementSequence) getSelected();
- for (int i = 0; allDisabled && i < elements.getSize(); i++) {
- allDisabled = elements.getElement(i).isDisabled(true);
- }
- elements.setDisabled(!allDisabled);
- } else {
- getSelected().setDisabled(!getSelected().isDisabled(true));
- }
-
- redraw();
- analyse();
- this.NSDControl.doButtons();
- // START KGU#705 2019-09-23: Enh. #738
- updateCodePreview();
- // END KGU#705 2019-09-23
- }
-
- // END KGU#277 2016-10-13
-
- /*========================================
+ /**
+ * Flips the disabled flag on the selected element(s). If several elements
+ * are selected, some of which are disabled while others are not, then
+ * disables all of them. To disable an element means that it gets handled
+ * like a comment on execution and export (undoable).
+ */
+ public void disableNSD() {
+ // START KGU#911 2021-01-10: Enh. 910
+ if (selected != null && selected.isImmutable()) {
+ return;
+ }
+ // END KGU#911 2021-01-10
+ boolean allDisabled = true;
+ //root.addUndo();
+ try {
+ addUndoNSD(false);
+ } catch (CancelledException e) {
+ return;
+ }
+ if (getSelected() instanceof IElementSequence) {
+ IElementSequence elements = (IElementSequence) getSelected();
+ for (int i = 0; allDisabled && i < elements.getSize(); i++) {
+ allDisabled = elements.getElement(i).isDisabled(true);
+ }
+ elements.setDisabled(!allDisabled);
+ } else {
+ getSelected().setDisabled(!getSelected().isDisabled(true));
+ }
+
+ redraw();
+ analyse();
+ this.NSDControl.doButtons();
+ // START KGU#705 2019-09-23: Enh. #738
+ updateCodePreview();
+ // END KGU#705 2019-09-23
+ }
+ // END KGU#277 2016-10-13
+
+ /*========================================
* add method
*========================================*/
- /**
- * Opens the element editor for the new given {@link Element} {@code _ele}
- * and inserts the edited element after (if {@code _after} is true) or
- * before (otherwise) the selected element(s) unless the user cancels the
- * action.
- *
- * @param _ele - the new {@link Element} to be processed
- * @param _title - proposed title for the editor (may be overridden by the
- * localisation mechanism
- * @param _pre - the default prefix text as configured in the Structure
- * Preferences
- * @param _after - whether {@code _ele} is to be inserted after (true) or
- * before (false) the selected element.
- */
- public void addNewElement(Element _ele, String _title, String _pre, boolean _after) {
- if (getSelected() != null) {
- EditData data = new EditData();
- data.title = _title;
- data.text.setText(_pre);
- // START KGU 2015-10-14: More information to ease title localisation
- //showInputBox(data);
- showInputBox(data, _ele.getClass().getSimpleName(), true, true);
- // END KGU 2015-10-14
- if (data.result == true) {
- if (!(_ele instanceof Forever)) {
- // START KGU#480 2018-01-21: Enh. #490 we have to replace DiagramController aliases by the original names
- //_ele.setText(data.text.getText());
- _ele.setAliasText(data.text.getText());
- // END KGU#480 2018-01-21
- }
- _ele.setComment(data.comment.getText());
- // START KGU 2015-10-17
- if (_ele.isBreakpoint() != data.breakpoint) {
- _ele.toggleBreakpoint();
- }
- // END KGU 2015-10-17
- // START KGU#277 2016-10-13: Enh. #270
- _ele.setDisabled(data.disabled);
- // END KGU#277 2016-10-13
- // START KGU#213 2016-08-01: Enh. #215
- //_ele.setBreakTriggerCount(data.breakTriggerCount);
- // END KGU#213 2016-08-01
- // START KGU#3 2015-10-25
- if (_ele instanceof For) {
- /*/ START KGU 2018-01-22: The only difference of this code to postEditorFor(_data, (For)_ele)
- * was the way the style information and the value list were set - it was difficult to say
- * which way was the better one.
- */
+ /**
+ * Opens the element editor for the new given {@link Element} {@code _ele}
+ * and inserts the edited element after (if {@code _after} is true) or
+ * before (otherwise) the selected element(s) unless the user cancels the
+ * action.
+ *
+ * @param _ele - the new {@link Element} to be processed
+ * @param _title - proposed title for the editor (may be overridden by the
+ * localisation mechanism
+ * @param _pre - the default prefix text as configured in the Structure
+ * Preferences
+ * @param _after - whether {@code _ele} is to be inserted after (true) or
+ * before (false) the selected element.
+ */
+ public void addNewElement(Element _ele, String _title, String _pre, boolean _after) {
+ if (getSelected() != null) {
+ EditData data = new EditData();
+ data.title = _title;
+ data.text.setText(_pre);
+ // START KGU 2015-10-14: More information to ease title localisation
+ //showInputBox(data);
+ showInputBox(data, _ele.getClass().getSimpleName(), true, true);
+ // END KGU 2015-10-14
+ if (data.result == true) {
+ if (!(_ele instanceof Forever)) {
+ // START KGU#480 2018-01-21: Enh. #490 we have to replace DiagramController aliases by the original names
+ //_ele.setText(data.text.getText());
+ _ele.setAliasText(data.text.getText());
+ // END KGU#480 2018-01-21
+ }
+ _ele.setComment(data.comment.getText());
+ // START KGU 2015-10-17
+ if (_ele.isBreakpoint() != data.breakpoint) {
+ _ele.toggleBreakpoint();
+ }
+ // END KGU 2015-10-17
+ // START KGU#277 2016-10-13: Enh. #270
+ _ele.setDisabled(data.disabled);
+ // END KGU#277 2016-10-13
+ // START KGU#213 2016-08-01: Enh. #215
+ //_ele.setBreakTriggerCount(data.breakTriggerCount);
+ // END KGU#213 2016-08-01
+ // START KGU#3 2015-10-25
+ if (_ele instanceof For) {
+/* START KGU 2018-01-22: The only difference of this code to postEditorFor(_data, (For)_ele)
+ * was the way the style information and the value list were set - it was difficult to say
+ * which way was the better one.
+ */
// ((For)_ele).setCounterVar(data.forParts.get(0));
// // START KGU#480 2018-01-22: Enh. #490 we have to replace DiagramController aliases by the original names
// //((For)_ele).setStartValue(data.forParts.get(1));
@@ -4431,3484 +4401,3375 @@ public void addNewElement(Element _ele, String _title, String _pre, boolean _aft
// // END KGU#480 2018-01-22
// ((For)_ele).style = ((For)_ele).classifyStyle();
// // END KGU#61 2016-03-21
- this.postEditFor(data, (For) _ele);
- // END KGU 2018-01-22
- } // END KGU#3 2015-10-25
- // START KGU#695 2021-01-22: Enh. #714
- else if (_ele instanceof Try) {
- ((Try) _ele).setEmptyFinallyVisible(data.showFinally);
- }
- // END KGU#695 2021-01-22
- //root.addUndo();
- try {
- addUndoNSD(false);
- } catch (CancelledException e) {
- return;
- }
- selected.setSelected(false);
- if (_after == true) {
- // START KGU#477 2017-12-06: Enh. #487
- //root.addAfter(getSelected(),_ele);
- root.addAfter(getLastSelected(), _ele);
- // END KGU#477 2017-12-06
- } else {
- // START KGU#477 2017-12-06: Enh. #487
- //root.addBefore(getSelected(),_ele);
- root.addBefore(getFirstSelected(), _ele);
- // END KGU#477 2017-12-06
- }
- selected = _ele.setSelected(true);
- // START KGU#272 2016-10-06: Bugfix #262
- selectedDown = selected;
- // END KGU#272 2016-10-06
- redraw();
- analyse();
- // START KGU#444 2017-10-23: Issue #417 - reduce scrolling complexity
- adaptScrollUnits();
- // END KGU#444 2017-10-23
- // START KGU#705 2019-09-23: Enh. #738
- updateCodePreview();
- // END KGU#705 2019-09-23
- }
- }
- }
-
- /*========================================
+ this.postEditFor(data, (For) _ele);
+/* END KGU 2018-01-22 */
+ }
+ // END KGU#3 2015-10-25
+ // START KGU#695 2021-01-22: Enh. #714
+ else if (_ele instanceof Try) {
+ ((Try) _ele).setEmptyFinallyVisible(data.showFinally);
+ }
+ // END KGU#695 2021-01-22
+ //root.addUndo();
+ try {
+ addUndoNSD(false);
+ } catch (CancelledException e) {
+ return;
+ }
+ selected.setSelected(false);
+ if (_after == true) {
+ // START KGU#477 2017-12-06: Enh. #487
+ //root.addAfter(getSelected(),_ele);
+ root.addAfter(getLastSelected(), _ele);
+ // END KGU#477 2017-12-06
+ } else {
+ // START KGU#477 2017-12-06: Enh. #487
+ //root.addBefore(getSelected(),_ele);
+ root.addBefore(getFirstSelected(), _ele);
+ // END KGU#477 2017-12-06
+ }
+ selected = _ele.setSelected(true);
+ // START KGU#272 2016-10-06: Bugfix #262
+ selectedDown = selected;
+ // END KGU#272 2016-10-06
+ redraw();
+ analyse();
+ // START KGU#444 2017-10-23: Issue #417 - reduce scrolling complexity
+ adaptScrollUnits();
+ // END KGU#444 2017-10-23
+ // START KGU#705 2019-09-23: Enh. #738
+ updateCodePreview();
+ // END KGU#705 2019-09-23
+ }
+ }
+ }
+
+ /*========================================
* subroutine derivation method(s)
*========================================*/
- // START KGU#365 2017-03-19: Enh. #380 - perform the possible conversion
- /**
- * Extracts the select element(s) from the diagram, moves them to an
- * interactively specified new subroutine diagram and replaces them by a
- * {@link Call} for the latter (undoable).
- */
- public void outsourceNSD() {
- if (this.selected != null) {
- IElementSequence elements = null;
- if (!this.selectedIsMultiple()) {
- elements = new SelectedSequence(this.selected, this.selected);
- } else {
- elements = (IElementSequence) this.selected;
- }
- // START KGU#365 2017-04-14: We must at least warn if return or unmatched leave instructions are contained
- List jumps = findUnsatisfiedJumps(elements);
- if (!jumps.isEmpty()) {
- String jumpTexts = "";
- for (Jump jmp : jumps) {
- String jumpLine = jmp.getUnbrokenText().getLongString().trim();
- if (jumpLine.isEmpty()) {
- jumpLine = "(" + CodeParser.getKeywordOrDefault("preLeave", "leave") + ")";
- }
- jumpTexts += "\n \u25CF " + jumpLine;
- }
- Element.troubleMakers.addAll(jumps);
- int answer = JOptionPane.YES_OPTION;
- try {
- redraw();
- String[] options = new String[]{Menu.lblContinue.getText(), Menu.lblCancel.getText()};
- answer = JOptionPane.showOptionDialog(this.getFrame(),
- Menu.msgJumpsOutwardsScope.getText().replace("%", jumpTexts),
- Menu.msgTitleWarning.getText(),
- JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
- null,
- options,
- options[1]
- );
- } finally {
- Element.troubleMakers.clear();
- redraw();
- }
- if (answer != JOptionPane.YES_OPTION) {
- return;
- }
- }
- // END KGU#365 2017-04-14
- String hint = Menu.msgMustBeIdentifier.getText();
- String prompt1 = Menu.msgSubroutineName.getText() + ": ";
- String prompt = prompt1;
- String subroutineName = null;
- do {
- subroutineName = JOptionPane.showInputDialog(prompt);
- prompt = hint + "\n" + prompt1;
- } while (subroutineName != null && !Function.testIdentifier(subroutineName, false, null));
- if (subroutineName != null) {
- try {
- addUndoNSD(false);
- } catch (CancelledException e) {
- return;
- }
- selected.setSelected(false);
- // START KGU#506 2018-03-14: issue #522 - we need to check for record types
- HashMap parentTypes = root.getTypeInfo();
- // END KGU#506 2018-03-14
- // START KGU#626 2019-01-06: Enh. #657
- // Detect all groups root is member of such that we can associate the subroutine to them
- Collection groups = null;
- if (Arranger.hasInstance()) {
- groups = Arranger.getInstance().getGroupsFromRoot(root, true);
- }
- // END KGU#626 2019-01-06
- // START KGU#638 2019-01-20: Issue #668 - If root is not member of a group then push it to Arranger
- String targetGroupName = null;
- if (groups == null || groups.isEmpty() && Arranger.getInstance().getGroupsFromRoot(root, false).isEmpty()) {
- // If the diagram is a program then create an exclusive group named after the main diagram
- if (root.isProgram()) {
- targetGroupName = root.getMethodName(true);
- Arranger.getInstance().addToPool(root, this.getFrame(), targetGroupName);
- groups = Arranger.getInstance().getGroupsFromRoot(root, true);
- } else {
- Arranger.getInstance().addToPool(root, this.getFrame());
- }
- } else if (Arranger.getInstance().getGroupsFromRoot(root, false).size() == groups.size()) {
- // Parent diagram is arranged but not member of the default group - then its children shouldn't be either
- targetGroupName = groups.iterator().next().getName();
- }
- // END KGU#638 2019-01-20
- // FIXME May we involve the user in argument and result value identification?
- Root sub = root.outsourceToSubroutine(elements, subroutineName, null);
- if (sub != null) {
- // adopt presentation properties from root
- //sub.highlightVars = Element.E_VARHIGHLIGHT;
- sub.isBoxed = root.isBoxed;
- // START KGU#506 2018-03-14: issue #522 - we need to check for record types
- //sub.getVarNames(); // just to prepare proper drawing.
- StringList subVars = sub.retrieveVarNames();
- prepareArgTypesForSub(parentTypes, groups, targetGroupName, sub, subVars);
- // END KGU#506 2018-03-14
- sub.setChanged(false); // The argument false does NOT mean to reset the changed flag!
- Arranger arr = Arranger.getInstance();
- // START KGU#638 2019-01-20: Issue #668 - Improved group association behaviour
- //arr.addToPool(sub, NSDControl.getFrame());
- arr.addToPool(sub, NSDControl.getFrame(), targetGroupName);
- // END KGU#638 3019-01-20
- // START KGU#626 2019-01-06: Enh. #657
- // Associate the subroutine to all groups root is member of
- if (groups != null) {
- for (Group group : groups) {
- Arranger.getInstance().attachRootToGroup(group, sub, null, this.getFrame());
- }
- }
- // END KGU#626 2019-01-06
- arr.setVisible(true);
- } else {
- // Something failed, so undo the temporary changes without redo option
- root.undo(false);
- }
- selected.setSelected(true);
- redraw();
- analyse();
- // START KGU#444 2017-10-23: Issue #417 - reduce scrolling complexity
- adaptScrollUnits();
- // END KGU#444 2017-10-23
- // START KGU#705 2019-09-23: Enh. #738
- updateCodePreview();
- // END KGU#705 2019-09-23
- }
- }
- }
-
- /**
- * Retrieves the types for subroutine variables {@code subVars} from the
- * type map {@code parentTypes} of the calling routine and adopts or
- * implants required includables.
- *
- * @param parentTypes - type map of the calling routine
- * @param groups - Arranger groups of the calling routine (for Includable
- * implantation)
- * @param targetGroupName - name of the target group for the routine
- * @param sub - the subroutine (its includeList may be modified)
- * @param subVars - the interesting variables of the routine
- * @return a StringList of type names in order of {@code subVars}.
- */
- private StringList prepareArgTypesForSub(HashMap parentTypes, Collection groups,
- String targetGroupName, Root sub, StringList subVars) {
- // START KGU#921 2021-01-30: Bugfix #921 we must ensure topological ordering
- //HashMap sharedTypesMap = new HashMap();
- HashMap sharedTypesMap = new LinkedHashMap();
- // END KGU#921 2021-01-30
- StringList typeNames = new StringList();
- for (int i = 0; i < subVars.count(); i++) {
- String typeName = "";
- TypeMapEntry varType = null;
- String varName = subVars.get(i);
- if (Function.testIdentifier(varName, false, "")) {
- varType = parentTypes.get(varName);
- if (varType != null) {
- typeName = varType.getCanonicalType(true, true);
- } // START KGU#864 2020-04-28: Bugfix #865
- else if (varName.equals("true") || varName.contentEquals("false")) {
- typeName = "boolean";
- }
- // END KGU#864 2020-04-28
- } else {
- typeName = Element.identifyExprType(parentTypes, varName, true);
- if (!typeName.isEmpty()) {
- varType = parentTypes.get(":" + typeName);
- }
- }
- // START KGU#921 2021-01-30: Bugfix #921 Had to be recursive!
- //if (varType != null && varType.isRecord()) {
- // Element defining = varType.getDeclaringElement();
- // if (defining != null) {
- // Root typeSource = Element.getRoot(defining);
- // if (typeSource == root) {
- // sharedTypesMap.putIfAbsent(varType.typeName, defining);
- // }
- // else if (typeSource != null) {
- // sub.addToIncludeList(typeSource);
- // }
- // }
- //}
- gatherSharedTypes(sub, sharedTypesMap, varType, parentTypes);
- // END KGU#921 2021-01-30
- typeNames.add(typeName);
- }
- if (!sharedTypesMap.isEmpty()) {
- // FIXME: We might also offer a combo box containing the already included diagrams of root
- String hint = Menu.msgMustBeIdentifier.getText() + "\n";
- String prompt1 = Menu.msgIncludableName.getText() + ": ";
- String prompt = prompt1;
- String includableName = null;
- do {
- includableName = JOptionPane.showInputDialog(prompt);
- prompt = hint + prompt1;
- } while (includableName == null || !Function.testIdentifier(includableName, false, null));
- Root incl = null;
- if (Arranger.hasInstance()) {
- Vector includes = Arranger.getInstance().findIncludesByName(includableName, root, false);
- if (!includes.isEmpty()) {
- incl = includes.firstElement();
- incl.addUndo();
- }
- }
- boolean isNewIncl = incl == null;
- if (isNewIncl) {
- incl = new Root();
- incl.setText(includableName);
- incl.setInclude(true);
- // adopt presentation properties from root
- //incl.highlightVars = Element.E_VARHIGHLIGHT;
- incl.isBoxed = root.isBoxed;
- }
- for (Element source : sharedTypesMap.values()) {
- ((Subqueue) source.parent).removeElement(source);
- incl.children.addElement(source);
- }
- incl.setChanged(false); // The argument false does NOT mean to reset the changed flag!
- if (isNewIncl) {
- // START KGU#638 2019-01-20: Issue #668 - Improved group association behaviour
- //Arranger.getInstance().addToPool(incl, NSDControl.getFrame());
- Arranger.getInstance().addToPool(incl, NSDControl.getFrame(), targetGroupName);
- // END KGU#638 3019-01-20
- }
- // START KGU#626 2019-01-06: Enh. #657
- // Associate the includable to all groups root is member of
- if (groups != null) {
- for (Group group : groups) {
- Arranger.getInstance().attachRootToGroup(group, incl, null, this.getFrame());
- }
- }
- // END KGU#626 2019-01-06
- root.addToIncludeList(includableName);
- sub.addToIncludeList(includableName);
- }
- return typeNames;
- }
- // END KGU#365 2017-03-19
-
- // START KGU#921 2021-01-30: Bugfix #921
- /**
- * Recursively gathers the underlying complex (i.e. definition-mandatory)
- * types the subroutine {@code sub} depends on together with their defining
- * elements if retrievable.
- *
- * @param sub - a new subroutine diagram
- * @param sharedTypesMap - the map of types assumed necessarily to be
- * shared, may be enhanced here
- * @param varType - a definitely referred type
- * @param parentTypeMap - the type map of the calling diagram,
- */
- private void gatherSharedTypes(Root sub, HashMap sharedTypesMap, TypeMapEntry varType, HashMap parentTypeMap) {
- if (varType != null) {
- if (varType.isRecord() || varType.isEnum()) {
- // Ensure a topological order of types by post-order traversal
- if (varType.isRecord()) {
- for (TypeMapEntry subType : varType.getComponentInfo(true).values()) {
- gatherSharedTypes(sub, sharedTypesMap, subType, parentTypeMap);
- }
- }
- Element defining = varType.getDeclaringElement();
- if (defining != null) {
- Root typeSource = Element.getRoot(defining);
- if (typeSource == root) {
- sharedTypesMap.putIfAbsent(varType.typeName, defining);
- } else if (typeSource != null) {
- sub.addToIncludeList(typeSource);
- }
- }
- } else if (varType.isArray()) {
- // Try to fetch the element type
- String typeDescr = varType.getCanonicalType(true, false);
- int i = 0;
- while (i < typeDescr.length() && typeDescr.charAt(i) == '@') {
- i++;
- }
- typeDescr = typeDescr.substring(i);
- if (Function.testIdentifier(typeDescr, false, null)
- && (varType = parentTypeMap.get(":" + typeDescr)) != null) {
- gatherSharedTypes(sub, sharedTypesMap, varType, parentTypeMap);
- }
- }
- }
- }
- // END KGU#921 2021-01-30
-
- // START KGU#365 2017-04-14: Enh. #380
- /**
- * Retrieves all {@link Jump} elements within the span of {@code elements}
- * trying to leave outside the span.
- */
- private List findUnsatisfiedJumps(IElementSequence elements) {
- final class JumpFinder implements IElementVisitor {
-
- private Subqueue scope = null;
- private List foundJumps = new LinkedList();
-
- public JumpFinder(Subqueue scope) {
- this.scope = scope;
- }
-
- public List getJumps() {
- return foundJumps;
- }
-
- @Override
- public boolean visitPreOrder(Element _ele) {
- if (_ele instanceof Jump) {
- Jump jmp = (Jump) _ele;
- if (jmp.isReturn() || jmp.isLeave() && jmp.getLeftLoop(scope) == null) {
- this.foundJumps.add(jmp);
- }
- }
- return true;
- }
-
- @Override
- public boolean visitPostOrder(Element _ele) {
- return true;
- }
-
- }
-
- Subqueue scope = elements.getSubqueue();
- JumpFinder finder = new JumpFinder(scope);
- scope.traverse(finder);
- return finder.getJumps();
-
- }
- // END KGU#65 2017-04-14
-
- // START KGU#667 2019-02-26: Enh. #689
- /**
- * @return true if the selected element is a {@link Call} and a called
- * routine signature can be extracted or if the selected element is a
- * {@link Root} and its include list is not empty.
- * @see #editSubNSD()
- */
- public boolean canEditSub() {
- boolean canEdit = false;
- if (selected != null && selected instanceof Call) {
- Function called = ((Call) selected).getCalledRoutine();
- // We don't want to open an editor in case of a recursive call.
- canEdit = (called != null && !(called.getSignatureString().equals(root.getSignatureString(false, false))));
- } // START KGU#770 2021-01-27: Enh. #917 Also support Includables
- else if (selected != null && selected instanceof Root) {
- canEdit = ((Root) selected).includeList != null
- && !((Root) selected).includeList.isEmpty();
- }
- // END KGU#770 2021-01-27
- return canEdit;
- }
-
- /**
- * Summons the called subroutine of the selected {@link Call} into a
- * {@link Mainfom} instance, possibly opens a new one. May instead offer a
- * choice list of Includable names if the selected element is {@link Root}
- * with non-empty include list an then summon the selected Includable in the
- * same way.
- *
- * @see #canEditSub()
- */
- public void editSubNSD() {
- // START KGU#770 2021-01-27: Enh. #917
- Root referredRoot = null;
- String targetGroupName = null; // This will be relevant for a new diagram
- Collection myGroups = null;
- // END KGU#770 2021-01-27
- if (selected instanceof Call && this.canEditSub()) {
- Call call = (Call) selected;
- Function called = call.getCalledRoutine();
- // START KGU#770 2021-01-27: Enh. #917
- //Root referredRoot = null;
- // END KGU#770 2021-01-27
- // Try to find the subroutine in Arranger
- if (Arranger.hasInstance()) {
- Vector candidates = Arranger.getInstance()
- .findRoutinesBySignature(called.getName(), called.paramCount(), root, false);
- // Open a choice list if the group approach alone wasn't successful
- referredRoot = chooseReferredRoot(candidates, Menu.msgChooseSubroutine.getText());
- }
- // START KGU#770 2021-01-27: Enh. #917
- //String targetGroupName = null; // This will be relevant for a new subroutine
- // END KGU#770 2021-01-27
- // Create new subroutine root if we haven't been able to select an existing one
- if (referredRoot == null) {
- if (JOptionPane.showConfirmDialog(getFrame(),
- Menu.msgCreateSubroutine.getText().replace("%", called.getSignatureString()),
- Menu.msgTitleQuestion.getText(),
- JOptionPane.OK_CANCEL_OPTION) != JOptionPane.OK_OPTION) {
- return;
- }
- referredRoot = new Root();
- myGroups = Arranger.getInstance().getGroupsFromRoot(root, true);
- StringList params = new StringList();
- for (int i = 0; i < called.paramCount(); i++) {
- String param = called.getParam(i);
- params.add(param);
- }
- // START KGU#744 2019-10-05: Issue #758 - retrieve argument types and care for shared types
- StringList argTypes = this.prepareArgTypesForSub(root.getTypeInfo(), myGroups, targetGroupName, referredRoot, params);
- String paramSeparator = ", ";
- for (int i = 0; i < params.count(); i++) {
- String typeName = argTypes.get(i).replace("@", "array of ");
- // START KGU#864 2020-04-28: Bugfix #865
- //if (!Function.testIdentifier(params.get(i), "")) {
- String param = params.get(i);
- if (!Function.testIdentifier(param, false, "") || param.equals("true") || param.equals("false")) {
- // END KGU#864 2020-04-28
- params.set(i, param = ("param" + (i + 1)));
- }
- if (!typeName.isEmpty() && !typeName.equals("???")) {
- params.set(i, param + ": " + typeName);
- paramSeparator = "; ";
- }
- }
- // END KGU#744 2019-10-05
- String result = "";
- if (((Call) selected).isFunctionCall(false)) {
- StringList lineTokens = Element.splitLexically(call.getUnbrokenText().get(0), true);
- lineTokens.removeAll(" ");
- String var = Call.getAssignedVarname(lineTokens, true);
- if (Function.testIdentifier(var, false, null)) {
- TypeMapEntry typeEntry = root.getTypeInfo().get(var);
- result = typeEntry.getCanonicalType(true, true).replace("@", "array of ");
- if (result == null) {
- result = "";
- }
- }
- if (!result.trim().isEmpty()) {
- result = ": " + result.trim();
- } else {
- result = ": ???";
- }
- }
- referredRoot.setText(called.getName() + "(" + params.concatenate(paramSeparator) + ")" + result);
- referredRoot.setProgram(false);
- }
- // START KGU#770 2021-01-27: Enh. #917
- } else if (selected instanceof Root && this.canEditSub()) {
- StringList includeNames = ((Root) selected).includeList;
- if (root.isInclude() && includeNames.contains(root.getMethodName())) {
- root.addUndo();
- includeNames.removeAll(root.getMethodName());
- if (includeNames.isEmpty()) {
- JOptionPane.showMessageDialog(getFrame(),
- Menu.msgCyclicInclusion.getText(),
- Menu.msgTitleWarning.getText(),
- JOptionPane.WARNING_MESSAGE);
- return;
- }
- }
- String inclName = null;
- if (includeNames.count() > 1) {
- inclName = (String) JOptionPane.showInputDialog(getFrame(),
- Menu.msgChooseIncludable.getText(),
- Menu.msgTitleQuestion.getText(),
- JOptionPane.QUESTION_MESSAGE, null, // Use default icon
- includeNames.toArray(), // Array of choices
- includeNames.get(0)); // Initial choice
- if (inclName == null) {
- return;
- }
- } else {
- inclName = includeNames.get(0);
- }
- // Try to find the Includable in Arranger
- Vector candidates = Arranger.getInstance()
- .findIncludesByName(inclName, (Root) selected, false);
- // Prevent cyclic inclusion
- candidates.remove(root);
- // Open a choice list if the group approach alone wasn't successful
- referredRoot = chooseReferredRoot(candidates, Menu.msgChooseIncludable.getText());
- // Create new subroutine root if we haven't been able to select an existing one
- if (referredRoot == null) {
- if (JOptionPane.showConfirmDialog(getFrame(),
- Menu.msgCreateIncludable.getText().replace("%", inclName),
- Menu.msgTitleQuestion.getText(),
- JOptionPane.OK_CANCEL_OPTION) != JOptionPane.OK_OPTION) {
- return;
- }
- referredRoot = new Root();
- referredRoot.setText(inclName);
- referredRoot.setInclude();
- }
- }
- myGroups = Arranger.getInstance().getGroupsFromRoot(root, true);
- if (referredRoot != null) {
- referredRoot.setChanged(false);
- // Now care for the group context. If the parent diagram hadn't been in Arranger then put it there now
- if (myGroups.isEmpty() && Arranger.getInstance().getGroupsFromRoot(root, false).isEmpty()) {
- // If the diagram is a program then create an exclusive group named after the main diagram
- if (root.isProgram()) {
- targetGroupName = root.getMethodName(true);
- Arranger.getInstance().addToPool(root, this.getFrame(), targetGroupName);
- myGroups = Arranger.getInstance().getGroupsFromRoot(root, true);
- } else {
- Arranger.getInstance().addToPool(root, this.getFrame());
- }
- } else if (Arranger.getInstance().getGroupsFromRoot(root, false).size() == myGroups.size()) {
- // Parent diagram is arranged but not member of the default group - then its children shouldn't be either
- targetGroupName = myGroups.iterator().next().getName();
- }
- // END KGU#770 2021-01-27
- // START KGU#744 2019-10-05: Issue #758 - In case the connected subForm already handles the subroutine don't force to save it
- //if (subForm == null || subForm.diagram == null || !subForm.diagram.saveNSD(true) || !subForm.setRoot(subroutine)) {
- if (subForm == null
- || subForm.diagram == null
- || subForm.diagram.getRoot() != referredRoot
- && (!subForm.diagram.saveNSD(true) || !subForm.setRoot(referredRoot))) {
- // END KGU#744 2019-10-05
- subForm = new Mainform(false);
- subForm.addWindowListener(new WindowListener() {
- @Override
- public void windowOpened(WindowEvent e) {
- }
-
- @Override
- public void windowClosing(WindowEvent e) {
- // A dead Mainform causes enormous trouble if we try to work with it.
- if (subForm == e.getSource()) {
- subForm = null;
- }
- }
-
- @Override
- public void windowClosed(WindowEvent e) {
- ((Mainform) (e.getSource())).removeWindowListener(this);
- // START KGU#744 2019-10-05: Bugfix #758 We are not always informed on windowClosing
- if (subForm == e.getSource()) {
- subForm = null;
- }
- // END KGU#744 2019-10-05
- }
-
- @Override
- public void windowIconified(WindowEvent e) {
- }
-
- @Override
- public void windowDeiconified(WindowEvent e) {
- }
-
- @Override
- public void windowActivated(WindowEvent e) {
- }
-
- @Override
- public void windowDeactivated(WindowEvent e) {
- }
-
- });
- }
- if (subForm.diagram.getRoot() != referredRoot) {
- subForm.setRoot(referredRoot);
- }
- // If it is a new root then add it to Arranger
- if (targetGroupName != null) {
- Arranger.getInstance().addToPool(referredRoot, subForm, targetGroupName);
- } // START KGU#744 2019-10-05: Bugfix #758 - The subroutine has always to be added to Arranger
- else {
- Arranger.getInstance().addToPool(referredRoot, subForm);
- }
- Arranger.getInstance().setVisible(true);
- // END KGU#744 2019-10-05
- if (!subForm.isVisible()) {
- subForm.setVisible(true);
- }
- // START KGU#744 2019-10-05: Bugfix #758
- int state = subForm.getExtendedState();
- if ((state & Frame.ICONIFIED) != 0) {
- subForm.setExtendedState(state & ~Frame.ICONIFIED);
- }
- // END KGU#744 2019-10-05
- Point loc = NSDControl.getFrame().getLocation();
- Point locSub = subForm.getLocation();
- if (loc.equals(locSub)) {
- subForm.setLocation(loc.x + 20, loc.y + 20);
- }
- // START KGU#770 2021-01-27: Enh. #689, #917
- // We must of course give the focus to the opened editor
- subForm.requestFocus();
- // END KGU#770 2021-01-27
- }
- }
-
- /**
- * Disambiguates the referenced {@link Root} among the {@code candidates}
- * with user assistance if necessary.
- *
- * @param candidates - the vector of candidate {@link Root}s
- * @param rootType - localised name of the rout type
- * @return either the selected {@link Root} or {@code null}
- */
- private Root chooseReferredRoot(Vector candidates, String rootType) {
- Root referredRoot = null;
- // If the finding is unambiguous, get it
- if (candidates.size() == 1) {
- referredRoot = candidates.get(0);
- } else if (candidates.size() > 1) {
- // Open a choice list with full paths and let the user decide
- String[] choices = new String[candidates.size()];
- int i = 0;
- for (Root cand : candidates) {
- choices[i++] = cand.getSignatureString(true, false);
- }
- String input = (String) JOptionPane.showInputDialog(getFrame(),
- Menu.msgChooseSubroutine.getText().replace("%", rootType),
- Menu.msgTitleQuestion.getText(),
- JOptionPane.QUESTION_MESSAGE, null, // Use default icon
- choices, // Array of choices
- choices[0]); // Initial choice
- if (input != null && !input.trim().isEmpty()) {
- for (i = 0; i < choices.length && referredRoot != null; i++) {
- if (input.equals(choices[i])) {
- referredRoot = candidates.get(i);
- }
- }
- }
- }
- return referredRoot;
- }
- // END KGU#667 2019-02-26
-
- /*========================================
- * transmute method(s)
- *========================================*/
- // START KGU#199 2016-07-06: Enh. #188 - perform the possible conversion
- /**
- * Converts the selected element(s) into some substitute according to the
- * specified transmutation rules (undoable).
- *
- * @see #canTransmute()
- */
- public void transmuteNSD() {
- Subqueue parent = (Subqueue) selected.parent;
- if (selected instanceof Instruction) {
- //root.addUndo();
- try {
- addUndoNSD(false);
- } catch (CancelledException e) {
- return;
- }
- if (selected.getUnbrokenText().count() > 1) {
- transmuteToSequence(parent);
- } else {
- transmuteToSpecialInstr(parent);
- }
- } else if (selected instanceof IElementSequence) {
- root.addUndo();
- transmuteToCompoundInstr(parent);
- } // START KGU#229 2016-08-01: Enh. #213 - FOR loop decomposition
- else if (selected instanceof For && ((For) selected).style == For.ForLoopStyle.COUNTER) {
- root.addUndo();
- decomposeForLoop(parent);
- } // END KGU#229 2016-08-01
- // START KGU#267 2016-10-03: Enh. #257 - CASE decomposition
- else if (selected instanceof Case) {
- root.addUndo();
- decomposeCase(parent);
- } // END KGU#267 2016-10-03
- // START KGU#357 2017-03-10: Enh. #367: swapping of sides
- else if (selected instanceof Alternative && ((Alternative) selected).qFalse.getSize() > 0) {
- root.addUndo();
- swapBranches((Alternative) selected);
- }
- // END KGU#357 2017-03-10
- this.doButtons();
- redraw();
- analyse();
- // START KGU#444 2017-10-23: Issue #417 - reduce scrolling complexity
- adaptScrollUnits();
- // END KGU#444 2017-10-23
- // START KGU#705 2019-09-23: Enh. #738
- updateCodePreview();
- // END KGU#705 2019-09-23
- }
-
- // START KGU#357 2017-03-10: Enh. #367
- /**
- * Helper method of {@link #transmuteNSD()}
- */
- private void swapBranches(Alternative _alt) {
- String condition = _alt.getText().getText();
- String negCondition = Element.negateCondition(condition);
- _alt.setText(negCondition);
- Subqueue temp = _alt.qFalse;
- _alt.qFalse = _alt.qTrue;
- _alt.qTrue = temp;
- // The width of the condition is likely to have changed
- _alt.resetDrawingInfoUp(); // KGU#590 2018-10-01: Corrected Down -> Up
- redraw();
- analyse();
- }
- // END KGU#357 2017-03-10
-
- /**
- * Helper method of {@link #transmuteNSD()}
- */
- private void transmuteToSequence(Subqueue parent) {
- // Comment will be split as follows:
- // If the number of strings of the comment equals the number of instruction
- // lines then the strings are assigned one by one to he resulting instructions
- // (thereby splitting multi-line strings into StringLists),
- // otherwise the first instruction will get all comment.
- int index = parent.getIndexOf(selected);
- StringList comment = selected.getComment();
- StringList text = selected.getBrokenText();
- int count = text.count();
- boolean distributeComment = (count == comment.count());
- for (int i = 0; i < count; i++) {
- Instruction instr = (Instruction) selected.copy();
- instr.setText(StringList.explode(text.get(i), "\n"));
- if (distributeComment) {
- instr.setComment(StringList.explode(comment.get(i), "\n"));
- } else if (i != 0) {
- instr.comment.clear();
- }
- parent.insertElementAt(instr, index + i + 1);
- }
- parent.removeElement(index);
- selected = new SelectedSequence(parent, index, index + count - 1);
- selectedDown = null;
- selected.setSelected(true);
- }
-
- /**
- * Helper method of {@link #transmuteNSD()}
- */
- private void transmuteToSpecialInstr(Subqueue parent) {
- Instruction instr = (Instruction) selected;
- Element elem = instr;
- if (instr instanceof Call || instr instanceof Jump) {
- elem = new Instruction(instr);
- } else if (instr.isProcedureCall(false) || instr.isFunctionCall(false)) {
- elem = new Call(instr);
- } else if (instr.isJump()) {
- elem = new Jump(instr);
- }
- int index = parent.getIndexOf(instr);
- parent.insertElementAt(elem, index + 1);
- parent.removeElement(index);
- this.selected = elem;
- this.selectedDown = this.selected;
- }
-
- /**
- * Helper subroutine of {@link #transmuteNSD()}
- */
- private void transmuteToCompoundInstr(Subqueue parent) {
- // Comments will be composed as follows:
- // If none of the selected elements had a non-empty comment then the resulting
- // comment will be empty. Otherwise the resulting comment will contain as many
- // strings as elements. Each of them will be the respective element comment,
- // possibly containing several newlines if it was a multi-line comment.
- Instruction instr = (Instruction) ((IElementSequence) selected).getElement(0);
- StringList composedComment = StringList.getNew(instr.getComment().getText().trim());
- int nElements = ((IElementSequence) selected).getSize();
- int index = parent.getIndexOf(instr);
- boolean brkpt = instr.isBreakpoint();
- // START KGU#213 2016-08-01: Enh. #215
- int brkCount = instr.getBreakTriggerCount();
- // END KGU#213 2016-08-01
- // Find out whether all elements are of the same kind
- boolean sameKind = true;
- for (int i = 1; sameKind && i < nElements; i++) {
- if (((IElementSequence) selected).getElement(i).getClass() != instr.getClass()) {
- sameKind = false;
- }
- }
- // If so...
- if (sameKind) {
- // ... then clone the first element of the sequence as same class
- instr = (Instruction) instr.copy();
- } else {
- // ... else clone the first element of the sequence as simple instruction
- instr = new Instruction(instr);
- }
- ((IElementSequence) selected).removeElement(0);
- nElements--;
- // And now append the contents of the remaining elements, removing them from the selection
- for (int i = 0; i < nElements; i++) {
- Element ele = ((IElementSequence) selected).getElement(0);
- instr.getText().add(ele.getText());
- composedComment.add(ele.getComment().getText().trim());
- if (ele.isBreakpoint()) {
- brkpt = true;
- }
- // START KGU#213 2016-08-01: Enh. #215
- // Use the earliest breakTriggerCount
- int brkCnt = ele.getBreakTriggerCount();
- if (brkCnt > 0 && brkCnt < brkCount) {
- brkCount = brkCnt;
- }
- // END KGU#213 2016-08-01
- ((IElementSequence) selected).removeElement(0);
- }
- // If there was no substantial comment then we must not create one, otherwise
- // the cmment is to consist of as many strings as instruction lines - where
- // each of them may contain newlines for reversibility
- if (!composedComment.concatenate().trim().isEmpty()) {
- instr.setComment(composedComment);
- } else {
- instr.getComment().clear();
- }
- // If any of the implicated instructions had a breakpoint then set it here, too
- if (brkpt && !instr.isBreakpoint()) {
- instr.toggleBreakpoint();
- }
- // START KGU#213 2016-08-01: Enh. #215
- // Use the earliest breakTriggerCount
- instr.setBreakTriggerCount(brkCount);
- // END KGU#213 2016-08-01
-
- instr.setSelected(true);
- parent.insertElementAt(instr, index);
- this.selected = instr;
- this.selectedDown = this.selected;
- }
- // END KGU#199 2016-07-06
-
- // START KGU#229 2016-08-01: Enh. #213 - FOR loop decomposition
- /**
- * Helper method of {@link #transmuteNSD()}
- */
- private void decomposeForLoop(Subqueue parent) {
- // Comment will be tranferred to the While loop.
- For forLoop = (For) selected;
- String asgmtOpr = " <- ";
- if (forLoop.getText().get(0).contains(":=")) {
- asgmtOpr = " := ";
- }
- int step = forLoop.getStepConst();
- Element[] elements = new Element[3];
- elements[0] = new Instruction(forLoop.getCounterVar() + asgmtOpr + forLoop.getStartValue());
- // START KGU#229 2016-09-09: Take care of the configured prefix and postfix
- //While whileLoop = new While(forLoop.getCounterVar() + (step < 0 ? " >= " : " <= ") + forLoop.getEndValue());
- String prefix = "", postfix = "";
- if (!CodeParser.getKeyword("preWhile").trim().isEmpty()) {
- prefix = CodeParser.getKeyword("preWhile");
- if (!prefix.endsWith(" ")) {
- prefix += " ";
- }
- }
- if (!CodeParser.getKeyword("postWhile").trim().isEmpty()) {
- postfix = CodeParser.getKeyword("postWhile");
- if (!postfix.startsWith(" ")) {
- postfix = " " + postfix;
- }
- }
- While whileLoop = new While(prefix + forLoop.getCounterVar() + (step < 0 ? " >= " : " <= ") + forLoop.getEndValue() + postfix);
- // END KGU#229 2016-09-09
- elements[1] = whileLoop;
- elements[2] = new Instruction(forLoop.getCounterVar() + asgmtOpr + forLoop.getCounterVar() + (step < 0 ? " - " : " + ") + Math.abs(forLoop.getStepConst()));
-
- whileLoop.setComment(forLoop.getComment());
- if (forLoop.isBreakpoint()) {
- whileLoop.toggleBreakpoint();
- }
- whileLoop.setBreakTriggerCount(forLoop.getBreakTriggerCount());
- whileLoop.q = forLoop.getBody();
- whileLoop.q.parent = whileLoop;
- whileLoop.q.addElement(elements[2]);
- whileLoop.setCollapsed(forLoop.isCollapsed(true));
- for (int i = 0; i < elements.length; i++) {
- Element elem = elements[i];
- elem.setColor(forLoop.getColor());
- elem.deeplyCovered = forLoop.deeplyCovered;
- elem.simplyCovered = forLoop.simplyCovered;
- }
- int index = parent.getIndexOf(forLoop);
- for (int i = 0; i < 2; i++) {
- parent.insertElementAt(elements[1 - i], index + 1);
- }
- parent.removeElement(index);
- this.selected = new SelectedSequence(parent, index, index + 1);
- // START KGU#229 2016-09-11: selection must be made visible!
- this.selected.setSelected(true);
- // END KGU#229 2016-09-11
- this.selectedDown = this.selected;
- }
- // END KGU#229 2016-08-01
-
- // START KGU#267 2016-10-03: Enh. #257 - CASE structure decomposition
- /**
- * Helper method of {@link #transmuteNSD()}
- */
- private void decomposeCase(Subqueue parent) {
- // Comment will be transferred to the first replacing element
- // (discriminator variable assignment or outermost Alternative).
- Case caseElem = (Case) selected;
- // List of replacing nested alternatives
- List alternatives = new LinkedList();
- // Possibly preceding assignment of the selection expression value
- Instruction asgnmt = null;
- // tokenized selection expression
- StringList selTokens = Element.splitLexically(caseElem.getText().get(0), true);
- // Eliminate parser preference keywords
- String[] redundantKeywords = {CodeParser.getKeyword("preCase"), CodeParser.getKeyword("postCase")};
- for (String keyword : redundantKeywords) {
- if (!keyword.trim().isEmpty()) {
- StringList tokenizedKey = Element.splitLexically(keyword, false);
- int pos = -1;
- while ((pos = selTokens.indexOf(tokenizedKey, pos + 1, !CodeParser.ignoreCase)) >= 0) {
- for (int i = 0; i < tokenizedKey.count(); i++) {
- selTokens.delete(pos);
- }
- }
- }
- }
- String discriminator = selTokens.concatenate().trim();
- // If the discriminating expression isn't just a variable then assign its value to an
- // artificial variable first and use this as discriminator further on.
- if (!Function.testIdentifier(discriminator, false, "")) {
- String discrVar = "discr" + caseElem.hashCode();
- asgnmt = new Instruction(discrVar + " <- " + discriminator);
- discriminator = discrVar;
- asgnmt.setColor(caseElem.getColor());
- }
-
- // Take care of the configured prefix and postfix
- String prefix = "", postfix = "";
- if (!CodeParser.getKeyword("preAlt").trim().isEmpty()) {
- prefix = CodeParser.getKeyword("preAlt");
- if (!prefix.endsWith(" ")) {
- prefix += " ";
- }
- }
- if (!CodeParser.getKeyword("postAlt").trim().isEmpty()) {
- postfix = CodeParser.getKeyword("postAlt");
- if (!postfix.startsWith(" ")) {
- postfix = " " + postfix;
- }
- }
-
- int nAlts = 0; // number of alternatives created so far
- for (int lineNo = 1; lineNo < caseElem.getText().count(); lineNo++) {
- String line = caseElem.getText().get(lineNo);
- // Specific handling of the last branch
- if (lineNo == caseElem.getText().count() - 1) {
- // In case it's a "%", nothing is to be added, otherwise the last
- // branch is to be the else path of the innermost alternative
- if (!line.equals("%")) {
- // This should not happen before the first alternative has been created!
- alternatives.get(nAlts - 1).qFalse = caseElem.qs.get(lineNo - 1);
- alternatives.get(nAlts - 1).qFalse.parent = alternatives.get(nAlts - 1);
- }
- } else {
- String[] selectors = line.split(",");
- String cond = "";
- for (String selConst : selectors) {
- cond += " || (" + discriminator + " = " + selConst.trim() + ")";
- }
- // START KGU#288 2016-11-06: Issue #279
- //cond = cond.substring(4).replace("||", CodeParser.getKeywordOrDefault("oprOr", "or"));
- cond = cond.substring(4).replace("||", CodeParser.getKeywordOrDefault("oprOr", "or"));
- // END KGU#288 2016-11-06
- Alternative newAlt = new Alternative(prefix + cond + postfix);
- newAlt.qTrue = caseElem.qs.get(lineNo - 1);
- newAlt.qTrue.parent = newAlt;
- alternatives.add(newAlt);
- if (nAlts > 0) {
- alternatives.get(nAlts - 1).qFalse.addElement(newAlt);
- }
- nAlts++;
- }
- }
-
- Element firstSubstitutor = (asgnmt != null) ? asgnmt : alternatives.get(0);
- firstSubstitutor.setComment(caseElem.getComment());
- if (caseElem.isBreakpoint()) {
- firstSubstitutor.toggleBreakpoint();
- }
- firstSubstitutor.setBreakTriggerCount(caseElem.getBreakTriggerCount());
- for (Alternative alt : alternatives) {
- alt.setColor(caseElem.getColor());
- alt.deeplyCovered = caseElem.deeplyCovered;
- alt.simplyCovered = caseElem.simplyCovered;
- }
- alternatives.get(0).setCollapsed(caseElem.isCollapsed(true));
-
- int index = parent.getIndexOf(caseElem);
- parent.removeElement(index);
- parent.insertElementAt(alternatives.get(0), index);
- if (asgnmt != null) {
- parent.insertElementAt(asgnmt, index);
- this.selected = new SelectedSequence(parent, index, index + 1);
- } else {
- this.selected = parent.getElement(index);
- }
- this.selected.setSelected(true);
- this.selectedDown = this.selected;
- }
- // END KGU#267 2016-10-03
-
- // START KGU#282 2016-10-16: Issue #272 (draft)
- /*=======================================*
- * Turtleizer precision methods
- *=======================================*/
- /**
- * Replaces all Turtleizer {@code fd} and {@code bk} procedure calls by the
- * more precise {@code forward} and {@code backward} instructions
- * ({@code precisionUp} = true) or the other way round ({@code precisionUp}
- * = false) in the selected elements
- *
- * @param precisionUp - whether to convert to the more precise or to the
- * less precise versions
- */
- public void replaceTurtleizerAPI(boolean precisionUp) {
- final class TurtleizerSwitcher implements IElementVisitor {
-
- private int from;
- // START #272 2016-10-17 (KGU): detect changes (to get rid of void undo entry
- private boolean act = false;
- private int nChanges = 0;
- // END #272 2016-10-17
- private final String[][] functionPairs = {{"fd", "forward"}, {"bk", "backward"}};
-
- public TurtleizerSwitcher(boolean upgrade) {
- this.from = upgrade ? 0 : 1;
- }
-
- public boolean visitPreOrder(Element _ele) {
- if (_ele.getClass().getSimpleName().equals("Instruction")) {
- for (int i = 0; i < _ele.getText().count(); i++) {
- String line = _ele.getText().get(i);
- if (Instruction.isTurtleizerMove(line)) {
- Function fct = new Function(line);
- for (int j = 0; j < functionPairs.length; j++) {
- String oldName = functionPairs[j][from];
- if (fct.getName().equals(oldName)) {
- // START #272 2016-10-17
- //_ele.getText().set(i, functionPairs[j][1 - from] + line.trim().substring(oldName.length()));
- if (this.act) {
- _ele.getText().set(i, functionPairs[j][1 - from] + line.trim().substring(oldName.length()));
- }
- nChanges++;
- // END #272 2016-10-17
- }
- }
- }
- }
- }
- return true;
- }
-
- public boolean visitPostOrder(Element _ele) {
- return true;
- }
-
- // START #272 2016-10-17 (KGU)
- public void activate() {
- this.nChanges = 0;
- this.act = true;
- }
-
- public int getNumberOfReplacements() {
- return nChanges;
- }
- // END #272 2016-10-17
-
- }
-
- // START #272 2016-10-17 (KGU): Inform the user and get rid of void undo entry
- //root.addUndo();
- //selected.traverse(new TurtleizerSwitcher(precisionUp));
- // First mere count run
- TurtleizerSwitcher switcher = new TurtleizerSwitcher(precisionUp);
- selected.traverse(switcher);
- int nReplaced = switcher.getNumberOfReplacements();
- if (nReplaced > 0) {
- // There will be substitutions, so get dangerous.
- //root.addUndo();
- try {
- addUndoNSD(false);
- } catch (CancelledException e) {
- return;
- }
- switcher.activate();
- selected.traverse(switcher);
- }
- JOptionPane.showMessageDialog(this.getFrame(),
- Menu.msgReplacementsDone.getText().replace("%", Integer.toString(nReplaced)));
- // END #272 2016-10-17
- // START KGU#705 2019-09-23: Enh. #738
- updateCodePreview();
- // END KGU#705 2019-09-23
- }
- // END KGU#282 2016-10-16
-
- // START KGU#602 2018-10-26: Enh. #419
- /**
- * Adjusts line breaking for the selected element(s). Requests the details
- * interactively from the user.
- */
- public void rebreakLines() {
- if (this.selected != null) {
- // The current maximum line lengths of the selected element(s)
- Element selectedEls = this.selected;
- int flatMax = selectedEls.getMaxLineLength(false);
- int deepMax = selectedEls.getMaxLineLength(true);
- int lastLineLimit = this.lastWordWrapLimit <= 0 ? deepMax : this.lastWordWrapLimit;
- JPanel pnl = new JPanel();
- JLabel lblMaxLenSel = new JLabel(Menu.msgMaxLineLengthSelected.getText().
- replace("%", Integer.toString(flatMax)));
- JLabel lblMaxLenSub = new JLabel(Menu.msgMaxLineLengthSubstructure.getText().
- replace("%", Integer.toString(deepMax)));
- JLabel lblNewLen = new JLabel(Menu.lblNewMaxLineLength.getText());
- JSpinner spnNewLen = new JSpinner();
- SpinnerModel spnModelLen = new SpinnerNumberModel(0, 0, 255, 5);
- spnNewLen.setModel(spnModelLen);
- spnNewLen.setValue(lastLineLimit);
- JCheckBox cbRecursive = new JCheckBox(Menu.lblInvolveSubtree.getText());
- JCheckBox cbPreserve = new JCheckBox(Menu.lblPreserveContinuators.getText());
- cbRecursive.setSelected(!(selectedEls instanceof Instruction));
- cbPreserve.setSelected(lastLineLimit < (cbRecursive.isSelected() ? deepMax : flatMax));
-
- GridBagConstraints gbcLimits = new GridBagConstraints();
- gbcLimits.insets = new Insets(0, 5, 5, 5);
- gbcLimits.weightx = 1.0;
- gbcLimits.anchor = GridBagConstraints.LINE_START;
-
- pnl.setLayout(new GridBagLayout());
-
- gbcLimits.gridx = 0;
- gbcLimits.gridy = 0;
- gbcLimits.gridwidth = GridBagConstraints.REMAINDER;
- pnl.add(lblMaxLenSel, gbcLimits);
-
- gbcLimits.gridy++;
- pnl.add(lblMaxLenSub, gbcLimits);
-
- gbcLimits.gridy++;
- gbcLimits.gridwidth = 1;
- pnl.add(lblNewLen, gbcLimits);
-
- gbcLimits.gridx++;
- gbcLimits.gridwidth = GridBagConstraints.REMAINDER;
- gbcLimits.fill = GridBagConstraints.HORIZONTAL;
- pnl.add(spnNewLen, gbcLimits);
-
- gbcLimits.gridx = 0;
- gbcLimits.gridy++;
- gbcLimits.fill = GridBagConstraints.NONE;
- pnl.add(cbRecursive, gbcLimits);
- gbcLimits.gridy++;
- pnl.add(cbPreserve, gbcLimits);
-
- ChangeListener changeListener = new ChangeListener() {
-
- private final JSpinner spnLen = spnNewLen;
- private final JCheckBox chkRec = cbRecursive, chkPres = cbPreserve;
- private final int flatLen = flatMax, deepLen = deepMax;
-
- @Override
- public void stateChanged(ChangeEvent e) {
- int limit = (int) spnLen.getValue();
- if (chkRec.isSelected() && limit > deepLen || !chkRec.isSelected() && limit > flatLen) {
- chkPres.setSelected(false);
- }
- }
-
- };
-
- // Without this hack, directly entering a number in the spinner's text field wouldn't fire the ChangeEvent
- DefaultFormatter formatter = (DefaultFormatter) ((JSpinner.DefaultEditor) spnNewLen.getEditor()).getTextField().getFormatter();
- formatter.setCommitsOnValidEdit(true);
-
- spnNewLen.addChangeListener(changeListener);
- cbRecursive.addChangeListener(changeListener);
-
- int answer = JOptionPane.showConfirmDialog(
- this.getFrame(), pnl,
- Menu.ttlBreakTextLines.getText(),
- JOptionPane.OK_CANCEL_OPTION);
-
- if (answer == JOptionPane.OK_OPTION) {
- root.addUndo();
- boolean recursive = cbRecursive.isSelected();
- boolean preserve = cbPreserve.isSelected();
- this.lastWordWrapLimit = (short) (int) spnNewLen.getValue();
- boolean changed = false;
- if (selectedEls instanceof Root) {
- changed = selectedEls.breakTextLines(this.lastWordWrapLimit, !preserve);
- if (recursive && ((Root) selectedEls).breakElementTextLines(this.lastWordWrapLimit, !preserve)) {
- changed = true;
- }
- } else if (!recursive && !(selectedEls instanceof IElementSequence)) {
- changed = selectedEls.breakTextLines(this.lastWordWrapLimit, !preserve);
- } else {
- if (!(selectedEls instanceof IElementSequence)) {
- selectedEls = new SelectedSequence(selectedEls, selectedEls);
- }
- IElementSequence.Iterator iter = ((IElementSequence) selectedEls).iterator(recursive);
- while (iter.hasNext()) {
- if (iter.next().breakTextLines(this.lastWordWrapLimit, !preserve)) {
- changed = true;
- }
- }
- }
- if (!changed) {
- root.undo(false);
- }
- // START KGU#940 2021-02-24: Bugfix #419 - Drawing update had been missing
- redraw();
- // END KGU#940 2021-02-24
- // START KGU#705 2019-09-23: Enh. #738
- updateCodePreview();
- // END KGU#705 2019-09-23
- }
- }
- }
- // END KGU#602 2016-10-26
-
- // START KGU#43 2015-10-12
- /*========================================
- * breakpoint methods
- *========================================*/
- /**
- * Enables or disables the breakpoint on the selected element(s) depending
- * on the previous state. Does not affect a possibly configured break
- * trigger.
- *
- * @see Element#toggleBreakpoint()
- * @see #editBreakTrigger()
- * @see #clearBreakpoints()
- */
- public void toggleBreakpoint() {
- Element ele = getSelected();
- if (ele != null) {
- ele.toggleBreakpoint();
- redraw();
- }
- }
-
- // START KGU#213 2016-08-02: Enh. #215
- /**
- * Opens a dialog that allows to set the break trigger value (i.e. the
- * execution count value that triggers a breakpoint if enabled.
- *
- * @see #toggleBreakpoint()
- * @see #clearBreakpoints()
- */
- public void editBreakTrigger() {
- // TODO Auto-generated method stub
- Element ele = getSelected();
- if (ele != null) {
- int trigger = ele.getBreakTriggerCount();
- // FIXME: Replace this quick-and-dirty approach by something more functional
- String str = JOptionPane.showInputDialog(this.getFrame(),
- Menu.msgBreakTriggerPrompt.getText(),
- Integer.toString(trigger));
- if (str != null) {
- // START KGU#252 2016-09-21: Issue 248 - Linux (Java 1.7) workaround
- boolean isDone = false;
- // END KGU#252 2016-09-21
- try {
- // START KGU#252 2016-09-21: Issue 248 - Linux (Java 1.7) workaround
- //ele.setBreakTriggerCount(Integer.parseUnsignedInt(str));
- isDone = ele.setBreakTriggerCount(Integer.parseInt(str));
- // END KGU#252 2016-09-21
- // We assume the intention to activate the breakpoint with the configuration
- if (!ele.isBreakpoint()) {
- // FIXME This might not work properly with recursive algorithms (i.e. on stack unwinding)
- ele.toggleBreakpoint();
- }
- redraw();
- } catch (NumberFormatException ex) {
- // START KGU#252 2016-09-21: Issue 248 - Linux (Java 1.7) workaround
- //JOptionPane.showMessageDialog(this,
- // Menu.msgBreakTriggerIgnored.getText(),
- // Menu.msgTitleWrongInput.getText(),
- // JOptionPane.ERROR_MESSAGE);
- // END KGU#252 2016-09-21
- }
- // START KGU#252 2016-09-21: Issue 248 - Linux (Java 1.7) workaround
- if (!isDone) {
- JOptionPane.showMessageDialog(this.getFrame(),
- Menu.msgBreakTriggerIgnored.getText(),
- Menu.msgTitleWrongInput.getText(),
- JOptionPane.ERROR_MESSAGE);
- }
- // END KGU#252 2016-09-21
- }
- }
- }
- // END KGU#213 2016-08-02
-
- /**
- * Unsets all enabled breakpoints throughout the current diagram.
- *
- * @see #toggleBreakpoint()
- * @see #editBreakTrigger()
- */
- public void clearBreakpoints() {
- // FIXME (Issue #954): All clones in the Executor call stack must also be cleared!
- root.clearBreakpoints();
- redraw();
- }
-
- // START KGU#952 2021-03-03: Issue #954
- /**
- * Disables (or enables) the supervision of Breakpoints by {@link Executor}
- *
- * @param disable - if {@code true} then all breakpoints in all diagrams
- * will be disabled, otherwise they will be activated again.
- */
- public void disableBreakpoints(boolean disable) {
- Element.E_BREAKPOINTS_ENABLED = !disable;
- if (disable) {
- Element.E_BREAKPOINTCOLOR = Element.E_COMMENTCOLOR;
- } else {
- Element.E_BREAKPOINTCOLOR = Color.RED;
- }
- redraw();
- doButtons();
- }
-
- /**
- * Clears all execution flags and counts throughout the entire diagram held
- * as {@link #root}.
- */
- public void clearExecutionStatus() {
- root.clearExecutionStatus();
- redraw();
- }
- // END KGU#43 2015-10-12
-
- /*========================================
- * print method
- *========================================*/
- /**
- * Opens the print preview for the current {@link #root} from which it can
- * be printed.
- *
- * @see #exportPDF()
- */
- public void printNSD() {
- /*
- // printing support
- //--- Create a printerJob object
- PrinterJob printJob = PrinterJob.getPrinterJob ();
- //--- Set the printable class to this one since we
- //--- are implementing the Printable interface
- printJob.setPrintable (this);
- //--- Show a print dialog to the user. If the user
- //--- clicks the print button, then print, otherwise
- //--- cancel the print job
- if (printJob.printDialog())
- {
- try
- {
- printJob.print();
+ // START KGU#365 2017-03-19: Enh. #380 - perform the possible conversion
+ /**
+ * Extracts the select element(s) from the diagram, moves them to an
+ * interactively specified new subroutine diagram and replaces them by a
+ * {@link Call} for the latter (undoable).
+ */
+ public void outsourceNSD() {
+ if (this.selected != null) {
+ IElementSequence elements = null;
+ if (!this.selectedIsMultiple()) {
+ elements = new SelectedSequence(this.selected, this.selected);
+ } else {
+ elements = (IElementSequence) this.selected;
}
- catch (Exception PrintException)
- {
- PrintException.printStackTrace();
+ // START KGU#365 2017-04-14: We must at least warn if return or unmatched leave instructions are contained
+ List jumps = findUnsatisfiedJumps(elements);
+ if (!jumps.isEmpty()) {
+ String jumpTexts = "";
+ for (Jump jmp : jumps) {
+ String jumpLine = jmp.getUnbrokenText().getLongString().trim();
+ if (jumpLine.isEmpty()) {
+ jumpLine = "(" + CodeParser.getKeywordOrDefault("preLeave", "leave") + ")";
+ }
+ jumpTexts += "\n \u25CF " + jumpLine;
+ }
+ Element.troubleMakers.addAll(jumps);
+ int answer = JOptionPane.YES_OPTION;
+ try {
+ redraw();
+ String[] options = new String[]{Menu.lblContinue.getText(), Menu.lblCancel.getText()};
+ answer = JOptionPane.showOptionDialog(this.getFrame(),
+ Menu.msgJumpsOutwardsScope.getText().replace("%", jumpTexts),
+ Menu.msgTitleWarning.getText(),
+ JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
+ null,
+ options,
+ options[1]
+ );
+ } finally {
+ Element.troubleMakers.clear();
+ redraw();
+ }
+ if (answer != JOptionPane.YES_OPTION) {
+ return;
+ }
+ }
+ // END KGU#365 2017-04-14
+ String hint = Menu.msgMustBeIdentifier.getText();
+ String prompt1 = Menu.msgSubroutineName.getText() + ": ";
+ String prompt = prompt1;
+ String subroutineName = null;
+ do {
+ subroutineName = JOptionPane.showInputDialog(prompt);
+ prompt = hint + "\n" + prompt1;
+ } while (subroutineName != null && !Function.testIdentifier(subroutineName, false, null));
+ if (subroutineName != null) {
+ try {
+ addUndoNSD(false);
+ } catch (CancelledException e) {
+ return;
+ }
+ selected.setSelected(false);
+ // START KGU#506 2018-03-14: issue #522 - we need to check for record types
+ HashMap parentTypes = root.getTypeInfo();
+ // END KGU#506 2018-03-14
+ // START KGU#626 2019-01-06: Enh. #657
+ // Detect all groups root is member of such that we can associate the subroutine to them
+ Collection groups = null;
+ if (Arranger.hasInstance()) {
+ groups = Arranger.getInstance().getGroupsFromRoot(root, true);
+ }
+ // END KGU#626 2019-01-06
+ // START KGU#638 2019-01-20: Issue #668 - If root is not member of a group then push it to Arranger
+ String targetGroupName = null;
+ if (groups == null || groups.isEmpty() && Arranger.getInstance().getGroupsFromRoot(root, false).isEmpty()) {
+ // If the diagram is a program then create an exclusive group named after the main diagram
+ if (root.isProgram()) {
+ targetGroupName = root.getMethodName(true);
+ Arranger.getInstance().addToPool(root, this.getFrame(), targetGroupName);
+ groups = Arranger.getInstance().getGroupsFromRoot(root, true);
+ } else {
+ Arranger.getInstance().addToPool(root, this.getFrame());
+ }
+ } else if (Arranger.getInstance().getGroupsFromRoot(root, false).size() == groups.size()) {
+ // Parent diagram is arranged but not member of the default group - then its children shouldn't be either
+ targetGroupName = groups.iterator().next().getName();
+ }
+ // END KGU#638 2019-01-20
+ // FIXME May we involve the user in argument and result value identification?
+ Root sub = root.outsourceToSubroutine(elements, subroutineName, null);
+ if (sub != null) {
+ // adopt presentation properties from root
+ //sub.highlightVars = Element.E_VARHIGHLIGHT;
+ sub.isBoxed = root.isBoxed;
+ // START KGU#506 2018-03-14: issue #522 - we need to check for record types
+ //sub.getVarNames(); // just to prepare proper drawing.
+ StringList subVars = sub.retrieveVarNames();
+ prepareArgTypesForSub(parentTypes, groups, targetGroupName, sub, subVars);
+ // END KGU#506 2018-03-14
+ sub.setChanged(false); // The argument false does NOT mean to reset the changed flag!
+ Arranger arr = Arranger.getInstance();
+ // START KGU#638 2019-01-20: Issue #668 - Improved group association behaviour
+ //arr.addToPool(sub, NSDControl.getFrame());
+ arr.addToPool(sub, NSDControl.getFrame(), targetGroupName);
+ // END KGU#638 3019-01-20
+ // START KGU#626 2019-01-06: Enh. #657
+ // Associate the subroutine to all groups root is member of
+ if (groups != null) {
+ for (Group group : groups) {
+ Arranger.getInstance().attachRootToGroup(group, sub, null, this.getFrame());
+ }
+ }
+ // END KGU#626 2019-01-06
+ arr.setVisible(true);
+ } else {
+ // Something failed, so undo the temporary changes without redo option
+ root.undo(false);
+ }
+ selected.setSelected(true);
+ redraw();
+ analyse();
+ // START KGU#444 2017-10-23: Issue #417 - reduce scrolling complexity
+ adaptScrollUnits();
+ // END KGU#444 2017-10-23
+ // START KGU#705 2019-09-23: Enh. #738
+ updateCodePreview();
+ // END KGU#705 2019-09-23
}
}
- */
- //PrintPreview.print(this);
- /*
- PrintPreview pp = new PrintPreview(this,"Print Previwe");
- Point p = getLocationOnScreen();
- pp.setLocation(Math.round(p.x+(getVisibleRect().width-pp.getWidth())/2), Math.round(p.y)+(getVisibleRect().height-pp.getHeight())/2);
- pp.setVisible(true);
- */
- // START KGU#170 2018-06-11: Issue #143 - on opening the print preview a comment popup should vanish
- hideComments();
- // END KGU#170 2018-06-11
- PrintPreview pp = new PrintPreview(NSDControl.getFrame(), this);
- Point p = getLocationOnScreen();
- pp.setLocation(Math.round(p.x + (getVisibleRect().width - pp.getWidth()) / 2 + this.getVisibleRect().x),
- Math.round(p.y) + (getVisibleRect().height - pp.getHeight()) / 2 + this.getVisibleRect().y);
- pp.setVisible(true);
- }
-
- // START KGU #2 2015-11-19
- /*========================================
- * arrange method
- *========================================*/
- /**
- * Push the current root to the Arranger and pin it there. If Arranger
- * wasn't visible then it will be (re-)opened.
- */
- public void arrangeNSD() // START KGU#626 2018-12-28: Enh. #657
- {
- arrangeNSD(null);
- }
-
- /**
- * Push the current root to the Arranger and pin it there. If Arranger
- * wasn't visible then it will be (re-)opened.
- *
- * @param sourceFilename - the base name of a code file the diagram was
- * imported from if so, null otherwise
- */
- public void arrangeNSD(String sourceFilename) // END KGU#626 2018-12-28
- {
- //System.out.println("Arranger button pressed!");
- Arranger arr = Arranger.getInstance();
- arr.addToPool(root, NSDControl.getFrame(), sourceFilename);
- arr.setVisible(true);
- // KGU#280 2016-10-11: Obsolete now
- //isArrangerOpen = true; // Gives the Executor a hint where to find a subroutine pool
- }
- // END KGU#2 2015-11-19
-
- // START KGU#125 2016-01-06: Possibility to adopt a diagram if it's orphaned
- public void adoptArrangedOrphanNSD(Root root) {
- if (isArrangerOpen()) {
- Arranger arr = Arranger.getInstance();
- // START KGU#742 2019-10-04: This caused ConcurrentModificationExceptions
- //arr.addToPool(root, frame);
- arr.adoptRootIfOrphaned(root, (Mainform) NSDControl.getFrame());
- //END KGU#741 2019-10-04
- }
- }
- // END KGU#125 2016-01-06
-
- /*========================================
- * about method
- *========================================*/
- /**
- * Opens the About window with version info, authors tab, license text,
- * change log tab, and paths tab.
- */
- public void aboutNSD() {
- About about = new About(NSDControl.getFrame());
- Point p = getLocationOnScreen();
- about.setLocation(Math.round(p.x + (getVisibleRect().width - about.getWidth()) / 2 + this.getVisibleRect().x),
- Math.round(p.y) + (getVisibleRect().height - about.getHeight()) / 2 + this.getVisibleRect().y);
- // START KGU#300 2016-12-02: Enh. #300 - Add info about newer version if enabled
- String newVersion = this.getLatestVersionIfNewer();
- if (newVersion != null) {
- about.lblVersion.setText(about.lblVersion.getText() + " (" + Menu.msgNewerVersionAvail.getText().replace("%", newVersion) + ")");
- }
- // END KGU#300 2016-12-02
- about.setVisible(true);
- }
-
- /*========================================
- * export picture method
- *========================================*/
- /**
- * Opens a dialog for the configuration of a multi-tile PNG export and a
- * {@link FileChooser} and performs the respective image export.
- *
- * @see #exportPNG()
- * @see #exportSVG()
- * @see #exportEMF()
- * @see #exportPDF()
- * @see #exportSWF()
- */
- public void exportPNGmulti() {
- // START KGU#183 2016-04-24: Issue #169 - retain old selection
- Element wasSelected = selected;
- // END KGU#183 2016-04-24
-
- // START KGU#41 2015-10-11
- //root.selectElementByCoord(-1,-1); // Unselect all elements
- //redraw();
- unselectAll(true);
- // END KGU#41 2015-10-11
-
- JFileChooser dlgSave = new JFileChooser("Export diagram as Multi-PNG ...");
- // START KGU#287 2017-01-09: Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
- GUIScaler.rescaleComponents(dlgSave);
- // END KGU#287 2017-01-09
- // set directory
- if (lastExportDir != null) {
- dlgSave.setCurrentDirectory(lastExportDir);
- } else if (root.getFile() != null) {
- dlgSave.setCurrentDirectory(root.getFile());
- } else {
- dlgSave.setCurrentDirectory(currentDirectory);
- }
- // propose name
- // START KGU 2015-10-16: There is already a suitable method on root
-// String nsdName = root.getText().get(0);
-// nsdName.replace(':', '_');
-// if(nsdName.indexOf(" (")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf(" ("));}
-// if(nsdName.indexOf("(")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf("("));}
- String nsdName = root.proposeFileName();
- // END KGU 2015-10-16
- dlgSave.setSelectedFile(new File(nsdName));
-
- // START KGU#170 2016-04-01: Enh. #110 - select the provided filter
- //dlgSave.addChoosableFileFilter(new lu.fisch.structorizer.io.PNGFilter());
- PNGFilter filter = new PNGFilter();
- dlgSave.addChoosableFileFilter(filter);
- dlgSave.setFileFilter(filter);
- hideComments(); // Issue #143: Hide the current comment popup if visible
- // END KGU#170 2016-04-01
- int result = dlgSave.showSaveDialog(NSDControl.getFrame());
- if (result == JFileChooser.APPROVE_OPTION) {
- lastExportDir = dlgSave.getSelectedFile().getParentFile();
- String filename = dlgSave.getSelectedFile().getAbsoluteFile().toString();
- if (!filename.substring(filename.length() - 4, filename.length()).toLowerCase().equals(".png")) {
- filename += ".png";
- }
-
- // START KGU#224 2016-07-28: Issue #209 Test was nonsense since the actual file names will be different
- //File file = new File(filename);
- File file = new File(filename.replace(".png", "-00-00.png"));
- // END KGU#224 2016-07-28
- boolean writeDown = true;
-
- if (file.exists()) {
- int response = JOptionPane.showConfirmDialog(this.getFrame(),
- Menu.msgOverwriteFiles.getText(),
- Menu.btnConfirmOverwrite.getText(),
- JOptionPane.YES_NO_OPTION,
- JOptionPane.QUESTION_MESSAGE);
- if (response == JOptionPane.NO_OPTION) {
- writeDown = false;
- }
- }
- if (writeDown == true) {
- // START KGU#218 2016-07-28: Issue #206 Localization efforts
- //int cols = Integer.valueOf(JOptionPane.showInputDialog(null, "Into how many columns do you want to split the output?", "1"));
- //int rows = Integer.valueOf(JOptionPane.showInputDialog(null, "Into how many rows do you want to split the output?", "3"));
- int cols = Integer.valueOf(JOptionPane.showInputDialog(null, Menu.msgDialogExpCols.getText(), "1"));
- int rows = Integer.valueOf(JOptionPane.showInputDialog(null, Menu.msgDialogExpRows.getText(), "3"));
- // END KGU#218 2016-07-28
-
- BufferedImage image = new BufferedImage(root.width + 1, root.height + 1, BufferedImage.TYPE_4BYTE_ABGR);
- // START KGU#221 2016-07-28: Issue #208 Need to achieve transparent background
- //printAll(image.getGraphics());
- // START KGU#906 2021-01-06: Enh. #905
- //redraw(image.createGraphics());
- redraw(image.createGraphics(), DrawingContext.DC_IMAGE_EXPORT);
- // END KGU#906 2021-01-06
- // END KGU#221 2016-07-28
- // source: http://answers.yahoo.com/question/index?qid=20110821001157AAcdXVk
- // source: http://kalanir.blogspot.com/2010/02/how-to-split-image-into-chunks-java.html
- try {
- // 1. Load image file into memory
- //File file = new File("mario.png"); // mario.png in the same working directory
- //FileInputStream fis = new FileInputStream(file);
- //BufferedImage image = ImageIO.read(fis);
-
- // 2. Decide the number of pieces, and calculate the size of each chunk
- //int rows = 4;
- //int cols = 6;
- int chunks = rows * cols;
-
- int chunkWidth = image.getWidth() / cols;
- int chunkHeight = image.getHeight() / rows;
- // START KGU#223 2016-07-28: Bugfix #209 - identify the integer division defects
- int widthDefect = image.getWidth() % cols;
- int heightDefect = image.getHeight() % rows;
- // END KGU#223 2016-07-28
-
- // 3. Define an Image array to hold image chunks
- int count = 0;
- BufferedImage imgs[] = new BufferedImage[chunks];
-
- // 4. Fill the Image array with split image parts
- for (int x = 0; x < rows; x++) {
- for (int y = 0; y < cols; y++) {
- //Initialize the image array with image chunks
- // START KGU#223 2016-07-28: Bugfix #209
- // We must compensate the rounding defects lest the right and lower borders should be cut
- //imgs[count] = new BufferedImage(chunkWidth, chunkHeight, image.getType());
- int tileWidth = chunkWidth + (y < cols - 1 ? 0 : widthDefect);
- int tileHeight = chunkHeight + (x < rows - 1 ? 0 : heightDefect);
- imgs[count] = new BufferedImage(tileWidth, tileHeight, image.getType());
- // END KGU#223 2016-07-28
-
- // draws the image chunk
- Graphics2D gr = imgs[count++].createGraphics();
- // START KGU#223 2016-07-28: Bugfix #209
- //gr.drawImage(image, 0, 0, chunkWidth, chunkHeight, chunkWidth * y, chunkHeight * x, chunkWidth * y + chunkWidth, chunkHeight * x + chunkHeight, null);
- // We need to achieve transparent background
- gr.drawImage(image, 0, 0, tileWidth, tileHeight, chunkWidth * y, chunkHeight * x, chunkWidth * y + tileWidth, chunkHeight * x + tileHeight, null);
- // END KGU#223 2016-07-28
- gr.dispose();
- }
- }
-
- // 5. Save mini images into image files
- // START KGU#224 2016-07-28: Issue #209 - provide the original base name
- file = new File(filename);
- filename = file.getAbsolutePath();
- // END KGU#224 2016-07-28
- for (int i = 0; i < imgs.length; i++) {
- // START KGU#224 2016-07-28: Issue #209 - Better file name coding
- //File f = new File(file.getAbsolutePath().replace(".png", "-"+i+".png"));
- File f = new File(filename.replace(".png", String.format("-%1$02d-%2$02d.png", i / cols, i % cols)));
- // END KGU#224 2016-07-28
- ImageIO.write(imgs[i], "png", f);
- }
- } catch (Exception e) {
- JOptionPane.showMessageDialog(this.getFrame(),
- Menu.msgErrorImageSave.getText(),
- Menu.msgTitleError.getText(),
- JOptionPane.ERROR_MESSAGE);
- }
- }
- }
- // START KGU#183 2016-04-24: Issue #169 - restore old selection
- selected = wasSelected;
- if (selected != null) {
- selected.setSelected(true);
- }
- redraw();
- // END KGU#183 2016-04-24
- // START KGU#456 2017-11-05: Enh. #452
- if (root.advanceTutorialState(26, root)) {
- analyse();
- }
- // END KGU#456 2017-11-05
- }
-
- /**
- * Opens a {@link FileChooser} and performs the image export as PNG file.
- *
- * @see #exportPNGmulti()
- * @see #exportSVG()
- * @see #exportEMF()
- * @see #exportPDF()
- * @see #exportSWF()
- */
- public void exportPNG() {
- // START KGU#183 2016-04-24: Issue #169 - retain old selection
- Element wasSelected = selected;
- // END KGU#183 2016-04-24
-
- // START KGU#41 2015-10-11
- //root.selectElementByCoord(-1,-1); // Unselect all elements
- //redraw();
- unselectAll(true);
- // END KGU#41 2015-10-11
-
- JFileChooser dlgSave = new JFileChooser("Export diagram as PNG ...");
- // START KGU#287 2017-01-09: Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
- GUIScaler.rescaleComponents(dlgSave);
- // END KGU#287 2017-01-09
- // set directory
- if (lastExportDir != null) {
- dlgSave.setCurrentDirectory(lastExportDir);
- } else if (root.getFile() != null) {
- dlgSave.setCurrentDirectory(root.getFile());
- } else {
- dlgSave.setCurrentDirectory(currentDirectory);
- }
- // propose name
- // START KGU 2015-10-16: There is already a suitable method
-// String nsdName = root.getText().get(0);
-// nsdName.replace(':', '_');
-// if(nsdName.indexOf(" (")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf(" ("));}
-// if(nsdName.indexOf("(")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf("("));}
- String nsdName = root.proposeFileName();
- // END KGU 2015-10-16
- dlgSave.setSelectedFile(new File(nsdName));
-
- // START KGU 2016-04-01: Enh. #110 - select the provided filter
- //dlgSave.addChoosableFileFilter(new lu.fisch.structorizer.io.PNGFilter());
- PNGFilter filter = new PNGFilter();
- dlgSave.addChoosableFileFilter(filter);
- dlgSave.setFileFilter(filter);
- hideComments(); // Issue #143: Hide the current comment popup if visible
- // END KGU 2016-04-01
- int result = dlgSave.showSaveDialog(NSDControl.getFrame());
- if (result == JFileChooser.APPROVE_OPTION) {
- lastExportDir = dlgSave.getSelectedFile().getParentFile();
- String filename = dlgSave.getSelectedFile().getAbsoluteFile().toString();
- if (!filename.substring(filename.length() - 4, filename.length()).toLowerCase().equals(".png")) {
- filename += ".png";
- }
-
- File file = new File(filename);
- if (checkOverwrite(file, false) == 0) {
- BufferedImage bi = new BufferedImage(root.width + 1, root.height + 1, BufferedImage.TYPE_4BYTE_ABGR);
- // START KGU#221 2016-07-28: Issue #208 Need to achieve transparent background
- //printAll(bi.getGraphics());
- // START KGU#906 2021-01-06: Enh. #905
- //redraw(bi.createGraphics());
- redraw(bi.createGraphics(), DrawingContext.DC_IMAGE_EXPORT);
- // END KGU#906 2021-01-06
- // END KGU#221 2016-07-28
- try {
- ImageIO.write(bi, "png", file);
- } catch (Exception e) {
- JOptionPane.showMessageDialog(this.getFrame(),
- Menu.msgErrorImageSave.getText(),
- Menu.msgTitleError.getText(),
- JOptionPane.ERROR_MESSAGE);
- }
- }
- }
- // START KGU#183 2016-04-24: Issue #169 - restore old selection
- selected = wasSelected;
- if (selected != null) {
- selected.setSelected(true);
- }
- redraw();
- // END KGU#183 2016-04-24
- // START KGU#456 2017-11-05: Enh. #452
- if (root.advanceTutorialState(26, root)) {
- analyse();
- }
- // END KGU#456 2017-11-05
- }
-
- /**
- * Opens a {@link FileChooser} and performs the image export as EMF file.
- *
- * @see #exportPNG()
- * @see #exportPNGmulti()
- * @see #exportSVG()
- * @see #exportPDF()
- * @see #exportSWF()
- */
- public void exportEMF() {
- // START KGU#183 2016-04-24: Issue #169 - retain old selection
- Element wasSelected = selected;
- // END KGU#183 2016-04-24
-
- // START KGU#41 2015-10-11
- //root.selectElementByCoord(-1,-1); // Unselect all elements
- //redraw();
- unselectAll(true);
- // END KGU#41 2015-10-11
-
- JFileChooser dlgSave = new JFileChooser("Export diagram as EMF ...");
- // START KGU#287 2017-01-09: Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
- GUIScaler.rescaleComponents(dlgSave);
- // END KGU#287 2017-01-09
- // set directory
- if (lastExportDir != null) {
- dlgSave.setCurrentDirectory(lastExportDir);
- } else if (root.getFile() != null) {
- dlgSave.setCurrentDirectory(root.getFile());
- } else {
- dlgSave.setCurrentDirectory(currentDirectory);
- }
- // propose name
- // START KGU 2015-10-16: D.R.Y. - There is already a suitable method
- // String nsdName = root.getText().get(0);
- // nsdName.replace(':', '_');
- // if(nsdName.indexOf(" (")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf(" ("));}
- // if(nsdName.indexOf("(")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf("("));}
- String nsdName = root.proposeFileName();
- // END KGU 2015-10-16
- dlgSave.setSelectedFile(new File(nsdName));
-
- // START KGU 2016-04-01: Enh. #110 - select the provided filter
- //dlgSave.addChoosableFileFilter(new lu.fisch.structorizer.io.EMFFilter());
- EMFFilter filter = new EMFFilter();
- dlgSave.addChoosableFileFilter(filter);
- dlgSave.setFileFilter(filter);
- hideComments(); // Issue #143: Hide the current comment popup if visible
- // END KGU 2016-04-01
- int result = dlgSave.showSaveDialog(NSDControl.getFrame());
- if (result == JFileChooser.APPROVE_OPTION) {
- lastExportDir = dlgSave.getSelectedFile().getParentFile();
- String filename = dlgSave.getSelectedFile().getAbsoluteFile().toString();
- if (!filename.substring(filename.length() - 4, filename.length()).toLowerCase().equals(".emf")) {
- filename += ".emf";
- }
-
- File file = new File(filename);
- if (checkOverwrite(file, false) == 0) {
- try {
- EMFGraphics2D emf = new EMFGraphics2D(new FileOutputStream(filename),
- new Dimension(root.width + 12, root.height + 12));
-
- emf.startExport();
- lu.fisch.graphics.Canvas c = new lu.fisch.graphics.Canvas(emf);
- lu.fisch.graphics.Rect myrect = root.prepareDraw(c);
- myrect.left += 6;
- myrect.top += 6;
- root.draw(c, myrect, null, false);
- emf.endExport();
- } catch (Exception e) {
- // START KGU#484 2018-04-05: Issue #463
- //e.printStackTrace();
- logger.log(Level.WARNING, "Trouble exporting as image.", e);
- // END KGU#484 2018-04-05
- }
- }
- }
- // START KGU#183 2016-04-24: Issue #169 - restor old selection
- selected = wasSelected;
- if (selected != null) {
- selected.setSelected(true);
- }
- redraw();
- // END KGU#183 2016-04-24
- // START KGU#456 2017-11-05: Enh. #452
- if (root.advanceTutorialState(26, root)) {
- analyse();
- }
- // END KGU#456 2017-11-05
- }
-
- /**
- * Opens a {@link FileChooser} and performs the image export as SVG file.
- *
- * @see #exportPNG()
- * @see #exportPNGmulti()
- * @see #exportEMF()
- * @see #exportPDF()
- * @see #exportSWF()
- */
- public void exportSVG() // does not work!!
- {
- // START KGU#183 2016-04-24: Issue #169 - retain old selection
- Element wasSelected = selected;
- // END KGU#183 2016-04-24
-
- // START KGU#41 2015-10-11
- //root.selectElementByCoord(-1,-1); // Unselect all elements
- //redraw();
- unselectAll(true);
- // END KGU#41 2015-10-11
-
- JFileChooser dlgSave = new JFileChooser("Export diagram as SVG ...");
- // START KGU#287 2017-01-09: Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
- GUIScaler.rescaleComponents(dlgSave);
- // END KGU#287 2017-01-09
- // set directory
- if (lastExportDir != null) {
- dlgSave.setCurrentDirectory(lastExportDir);
- } else if (root.getFile() != null) {
- dlgSave.setCurrentDirectory(root.getFile());
- } else {
- dlgSave.setCurrentDirectory(currentDirectory);
- }
- // propose name
- // START KGU 2015-10-16: D.R.Y. - there is already a suitable method
-// String nsdName = root.getText().get(0);
-// nsdName.replace(':', '_');
-// if(nsdName.indexOf(" (")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf(" ("));}
-// if(nsdName.indexOf("(")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf("("));}
- String nsdName = root.proposeFileName();
- // END KGU 2015-10-16
- dlgSave.setSelectedFile(new File(nsdName));
-
- // START KGU 2016-04-01: Enh. #110 - select the provided filter
- //dlgSave.addChoosableFileFilter(new lu.fisch.structorizer.io.SVGFilter());
- SVGFilter filter = new SVGFilter();
- dlgSave.addChoosableFileFilter(filter);
- dlgSave.setFileFilter(filter);
- hideComments(); // Issue #143: Hide the current comment popup if visible
- // END KGU 2016-04-01
- int result = dlgSave.showSaveDialog(NSDControl.getFrame());
- if (result == JFileChooser.APPROVE_OPTION) {
- lastExportDir = dlgSave.getSelectedFile().getParentFile();
- String filename = dlgSave.getSelectedFile().getAbsoluteFile().toString();
- if (!filename.substring(filename.length() - 4, filename.length()).toLowerCase().equals(".svg")) {
- filename += ".svg";
- }
-
- File file = new File(filename);
- if (checkOverwrite(file, false) == 0) {
- try {
- SVGGraphics2D svg = new SVGGraphics2D(new FileOutputStream(filename), new Dimension(root.width + 12, root.height + 12));
- svg.startExport();
- lu.fisch.graphics.Canvas c = new lu.fisch.graphics.Canvas(svg);
- lu.fisch.graphics.Rect myrect = root.prepareDraw(c);
- myrect.left += 6;
- myrect.top += 6;
- root.draw(c, myrect, null, false);
- svg.endExport();
-
- // re-read the file ...
- StringBuffer buffer = new StringBuffer();
- InputStreamReader isr = new InputStreamReader(new FileInputStream(filename));
- Reader in = new BufferedReader(isr);
- int ch;
- while ((ch = in.read()) > -1) {
- buffer.append((char) ch);
- }
- // START KGU 2015-12-04
- in.close();
- // END KGU 2015-12-04
-
- // ... and encode it UTF-8
- FileOutputStream fos = new FileOutputStream(filename);
- Writer out = new OutputStreamWriter(fos, "UTF-8");
- out.write(buffer.toString());
- out.close();
-
- } catch (Exception e) {
- // START KGU#484 2018-04-05: Issue #463
- //e.printStackTrace();
- logger.log(Level.WARNING, "Trouble exporting as image.", e);
- // END KGU#484 2018-04-05
- }
- }
- }
-
- // START KGU#183 2016-04-24: Issue #169 - restore old selection
- //unselectAll();
- selected = wasSelected;
- if (selected != null) {
- selected.setSelected(true);
- }
- redraw();
- // END KGU#183 2016-04-24
- // START KGU#456 2017-11-05: Enh. #452
- if (root.advanceTutorialState(26, root)) {
- analyse();
- }
- // END KGU#456 2017-11-05
- }
-
- /**
- * Opens a {@link FileChooser} and performs the image export as SWF file.
- *
- * @see #exportPNG()
- * @see #exportPNGmulti()
- * @see #exportSVG()
- * @see #exportPDF()
- * @see #exportEMF()
- */
- public void exportSWF() {
- // START KGU#183 2016-04-24: Issue #169 - retain old selection
- Element wasSelected = selected;
- // END KGU#183 2016-04-24
-
- // START KGU 2015-10-11
- //root.selectElementByCoord(-1,-1); // Unselect all elements
- //redraw();
- unselectAll(true);
- // END KGU 2015-10-11
-
- JFileChooser dlgSave = new JFileChooser("Export diagram as SWF ...");
- // START KGU#287 2017-01-09: Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
- GUIScaler.rescaleComponents(dlgSave);
- // END KGU#287 2017-01-09
- // set directory
- if (lastExportDir != null) {
- dlgSave.setCurrentDirectory(lastExportDir);
- } else if (root.getFile() != null) {
- dlgSave.setCurrentDirectory(root.getFile());
- } else {
- dlgSave.setCurrentDirectory(currentDirectory);
- }
- // propose name
- // START KGU 2015-10-16: D.R.Y. - there is already a suitable method
-// String nsdName = root.getText().get(0);
-// nsdName.replace(':', '_');
-// if(nsdName.indexOf(" (")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf(" ("));}
-// if(nsdName.indexOf("(")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf("("));}
- String nsdName = root.proposeFileName();
- // END KGU 2015-10-16
- dlgSave.setSelectedFile(new File(nsdName));
-
- // START KGU 2016-04-01: Enh. #110 - select the provided filter
- //dlgSave.addChoosableFileFilter(new lu.fisch.structorizer.io.SWFFilter());
- SWFFilter filter = new SWFFilter();
- dlgSave.addChoosableFileFilter(filter);
- dlgSave.setFileFilter(filter);
- hideComments(); // Issue #143: Hide the current comment popup if visible
- // END KGU 2016-04-01
- int result = dlgSave.showSaveDialog(NSDControl.getFrame());
- if (result == JFileChooser.APPROVE_OPTION) {
- lastExportDir = dlgSave.getSelectedFile().getParentFile();
- String filename = dlgSave.getSelectedFile().getAbsoluteFile().toString();
- if (!filename.substring(filename.length() - 4, filename.length()).toLowerCase().equals(".swf")) {
- filename += ".swf";
- }
-
- File file = new File(filename);
- if (checkOverwrite(file, false) == 0) {
- try {
- SWFGraphics2D svg = new SWFGraphics2D(new FileOutputStream(filename), new Dimension(root.width + 12, root.height + 12));
-
- svg.startExport();
- lu.fisch.graphics.Canvas c = new lu.fisch.graphics.Canvas(svg);
- lu.fisch.graphics.Rect myrect = root.prepareDraw(c);
- myrect.left += 6;
- myrect.top += 6;
- root.draw(c, myrect, null, false);
- svg.endExport();
- } catch (Exception e) {
- // START KGU#484 2018-04-05: Issue #463
- //e.printStackTrace();
- logger.log(Level.WARNING, "Trouble exporting as image.", e);
- // END KGU#484 2018-04-05
- }
- }
- }
- // START KGU#183 2016-04-24: Issue #169 - restore old selection
- selected = wasSelected;
- if (selected != null) {
- selected.setSelected(true);
- }
- redraw();
- // END KGU#183 2016-04-24
- // START KGU#456 2017-11-05: Enh. #452
- if (root.advanceTutorialState(26, root)) {
- analyse();
- }
- // END KGU#456 2017-11-05
- }
-
- /**
- * Opens a {@link FileChooser} and performs the image export as PDF file.
- *
- * @see #exportPNG()
- * @see #exportPNGmulti()
- * @see #exportSVG()
- * @see #exportEMF()
- * @see #exportSWF()
- * @see #printNSD()
- */
- public void exportPDF() {
- // START KGU#183 2016-04-24: Issue #169 - retain old selection
- Element wasSelected = selected;
- // END KGU#183 2016-04-24
-
- // START KGU 2015-10-11
- //root.selectElementByCoord(-1,-1); // Unselect all elements
- //redraw();
- unselectAll(true);
- // END KGU 2015-10-11
-
- JFileChooser dlgSave = new JFileChooser("Export diagram as PDF ...");
- // START KGU#287 2017-01-09: Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
- GUIScaler.rescaleComponents(dlgSave);
- // END KGU#287 2017-01-09
- // set directory
- if (lastExportDir != null) {
- dlgSave.setCurrentDirectory(lastExportDir);
- } else if (root.getFile() != null) {
- dlgSave.setCurrentDirectory(root.getFile());
- } else {
- dlgSave.setCurrentDirectory(currentDirectory);
- }
- // propose name
- // START KGU 2015-10-16: D.R.Y. - there is already a suitable method
-// String nsdName = root.getText().get(0);
-// nsdName.replace(':', '_');
-// if(nsdName.indexOf(" (")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf(" ("));}
-// if(nsdName.indexOf("(")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf("("));}
- String nsdName = root.proposeFileName();
- // END KGU 2015-10-16
- dlgSave.setSelectedFile(new File(nsdName));
-
- // START KGU 2016-04-01: Enh. #110 - select the provided filter
- //dlgSave.addChoosableFileFilter(new lu.fisch.structorizer.io.PDFFilter());
- PDFFilter filter = new PDFFilter();
- dlgSave.addChoosableFileFilter(filter);
- dlgSave.setFileFilter(filter);
- hideComments(); // Issue #143: Hide the current comment popup if visible
- // END KGU 2016-04-01
- int result = dlgSave.showSaveDialog(NSDControl.getFrame());
- if (result == JFileChooser.APPROVE_OPTION) {
- lastExportDir = dlgSave.getSelectedFile().getParentFile();
- String filename = dlgSave.getSelectedFile().getAbsoluteFile().toString();
- if (!filename.substring(filename.length() - 4, filename.length()).toLowerCase().equals(".pdf")) {
- filename += ".pdf";
- }
-
- File file = new File(filename);
- if (checkOverwrite(file, false) == 0) {
- try {
- PDFGraphics2D pdf = new PDFGraphics2D(new FileOutputStream(filename), new Dimension(root.width + 12, root.height + 12));
-
- pdf.startExport();
- lu.fisch.graphics.Canvas c = new lu.fisch.graphics.Canvas(pdf);
- lu.fisch.graphics.Rect myrect = root.prepareDraw(c);
- myrect.left += 6;
- myrect.top += 6;
- root.draw(c, myrect, null, false);
- pdf.endExport();
- } catch (Exception e) {
- // START KGU#484 2018-04-05: Issue #463
- //e.printStackTrace();
- logger.log(Level.WARNING, "Trouble exporting as image.", e);
- // END KGU#484 2018-04-05
- }
- }
- }
- // START KGU#183 2016-04-24: Issue #169 - restore old selection
- selected = wasSelected;
- if (selected != null) {
- selected.setSelected(true);
- }
- redraw();
- // END KGU#183 2016-04-24
- // START KGU#456 2017-11-05: Enh. #452
- if (root.advanceTutorialState(26, root)) {
- analyse();
- }
- // END KGU#456 2017-11-05
- }
-
- // START KGU#396 2020-03-03: Enh. #440 Specific export interface for PapDesigner
- /**
- * Exports the current diagram (possibly with all referenced subdiagrams) as
- * PAP flowcharts compatible with PapDesigner.
- *
- * @param din66001_1982 - whether the newer DIN 66001 (from 1982) is to be
- * applied (otherwise the obsolete standard version from 1966 will be
- * adhered to)
- * @see #exportPap(Root, boolean)
- */
- public void exportPap(boolean din66001_1982) {
- exportPap(root, din66001_1982);
- }
-
- /**
- * Exports the given diagram {@code _root} (possibly with all referenced
- * subdiagrams) as PAP flowchart compatible with PapDesigner
- *
- * @param _root - the top level {@link Root} to be exported
- * @param din66001_1982 - whether the newer DIN 66001 (from 1982) is to be
- * applied (otherwise the obsolete standard version from 1966 will be
- * adhered to) #see {@link #exportPap(boolean)}
- */
- public void exportPap(Root _root, boolean din66001_1982) {
- try {
- Generator gen = new PapGenerator();
- gen.setPluginOption("din66001_1982", din66001_1982);
- hideComments(); // Hide the current comment popup if visible
- File exportDir
- = gen.exportCode(_root,
- (lastCodeExportDir != null ? lastCodeExportDir : currentDirectory),
- NSDControl.getFrame(),
- (Arranger.hasInstance() ? Arranger.getInstance() : null));
- if (exportDir != null) {
- this.lastCodeExportDir = exportDir;
- }
- // END KGU#654 2019-02-15/16
- } catch (Exception ex) {
- String message = ex.getLocalizedMessage();
- if (message == null) {
- message = ex.getMessage();
- }
- if (message == null || message.isEmpty()) {
- message = ex.toString();
- }
- JOptionPane.showMessageDialog(this.getFrame(),
- Menu.msgErrorUsingGenerator.getText().replace("%", PapGenerator.class.getSimpleName()) + "\n" + message,
- Menu.msgTitleError.getText(),
- JOptionPane.ERROR_MESSAGE);
- }
- }
- // END KGU#396 2020-03-03
-
-
- /*========================================
- * Import method for foreign diagrams
- *========================================*/
- // START KGU#386 2017-04-25: version 3.26-06 - new import sources
- /**
- * Imports diagrams from alien file formats (e.g. from Struktogrammeditor)
- *
- * @param _className - Name of the appropriate importer class (to be
- * configured via plugins)
- * @param _specificOptions - importer-specific key-value pairs
- */
- public void importNSD(String _className, Vector> _specificOptions) {
- // only save if something has been changed
- saveNSD(true);
-
- if (!this.checkRunning()) {
- return; // Don't proceed if the root is being executed
- }
- // open an existing file
- // create dialog
- JFileChooser dlgOpen = new JFileChooser();
- // Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
- GUIScaler.rescaleComponents(dlgOpen);
- INSDImporter parser = null;
- try {
- // FIXME: For future Java versions we may need a factory here
- Class> impClass = Class.forName(_className);
- parser = (INSDImporter) impClass.getDeclaredConstructor().newInstance();
-
- dlgOpen.setDialogTitle(Menu.msgTitleNSDImport.getText().replace("%", parser.getDialogTitle()));
- // set directory
- dlgOpen.setCurrentDirectory(currentDirectory);
- // config dialogue
- FileFilter filter = parser.getFileFilter();
- dlgOpen.addChoosableFileFilter(filter);
- dlgOpen.setFileFilter(filter);
- // show & get result
- int result = dlgOpen.showOpenDialog(this);
- // react to result
- if (result == JFileChooser.APPROVE_OPTION) {
- //boolean hil = root.highlightVars;
- // FIXME: Replace this with a generalized version of openNSD(String)
- root = parser.parse(dlgOpen.getSelectedFile().toURI().toString());
- //root.highlightVars = hil;
- if (Element.E_VARHIGHLIGHT) {
- root.retrieveVarNames(); // Initialise the variable table, otherwise the highlighting won't work
- }
- currentDirectory = dlgOpen.getSelectedFile();
- redraw();
- }
- } catch (Exception ex) {
- String message = ex.getLocalizedMessage();
- if (message == null) {
- message = ex.getMessage();
- }
- if (message == null || message.isEmpty()) {
- message = ex.toString();
- }
- JOptionPane.showMessageDialog(this.getFrame(), message,
- Menu.msgTitleError.getText(), JOptionPane.ERROR_MESSAGE);
- // START KGU#484 2018-04-05: Issue #463
- //ex.printStackTrace();
- logger.log(Level.WARNING, "Using parser " + _className + " failed.", ex);
- // END KGU#484 2018-04-05
- }
- // START KGU#444/KGU#618 2018-12-18: Issue #417, #649
- this.adaptScrollUnits();
- // END KGU#444/KGU#618 2018-12-18
- }
- // END KGU#386 2017-04-25
-
- /*========================================
- * import methods for code
- *========================================*/
- // START KGU#354 2017-03-04: Enh. #354
-// public void importPAS()
-// {
-// // only save if something has been changed
-// saveNSD(true);
-//
-// String filename = "";
-//
-// JFileChooser dlgOpen = new JFileChooser();
-// // START KGU#287 2017-01-09: Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
-// GUIScaler.rescaleComponents(dlgOpen);
-// // END KGU#287 2017-01-09
-// dlgOpen.setDialogTitle(Menu.msgTitleImport.getText().replace("%", "Pascal"));
-// // set directory
-// if(root.getFile()!=null)
-// {
-// dlgOpen.setCurrentDirectory(root.getFile());
-// }
-// else
-// {
-// dlgOpen.setCurrentDirectory(currentDirectory);
-// }
-//
-// // START KGU 2016-04-01: Enh. #110 - select the provided filter
-// //dlgOPen.addChoosableFileFilter(new PascalFilter());
-// PascalFilter filter = new PascalFilter();
-// dlgOpen.addChoosableFileFilter(filter);
-// dlgOpen.setFileFilter(filter);
-// hideComments(); // Issue #143: Hide the current comment popup if visible
-// // END KGU 2016-04-01
-// int result = dlgOpen.showOpenDialog(NSDControl.getFrame());
-// filename=dlgOpen.getSelectedFile().getAbsoluteFile().toString();
-//
-// if (result == JFileChooser.APPROVE_OPTION)
-// {
-// // load and parse source-code
-// D7Parser d7 = new D7Parser("D7Grammar.cgt");
-// // START KGU#194 2016-05-08: Bugfix #185 - mechanism for multiple roots per file
-// //Root rootNew = d7.parse(filename);
-// // START KGU#265 2016-09-28: Enh. #253 brought the Charset configuration. So make use of it.
-// //List newRoots = d7.parse(filename, "ISO-8859-1");
-// Ini ini = Ini.getInstance();
-// List newRoots = d7.parse(filename, ini.getProperty("impImportCharset", "ISO-8859-1"));
-// // END KGU#265 2016-09-28
-// // END KGU#194 2016-05-08
-// if (d7.error.equals(""))
-// {
-// boolean hil = root.hightlightVars;
-// // START KGU#194 2016-05-08: Bugfix #185 - there may be multiple routines
-// Root firstRoot = null;
-// //root = rootNew;
-// Iterator iter = newRoots.iterator();
-// if (iter.hasNext()){
-// firstRoot = iter.next();
-// }
-// while (iter.hasNext())
-// {
-// root = iter.next();
-// root.hightlightVars = hil;
-// // The Root must be marked for saving
-// root.setChanged();
-// // ... and be added to the Arranger
-// this.arrangeNSD();
-// }
-// if (firstRoot != null)
-// {
-// root = firstRoot;
-// // END KGU#194 2016-05-08
-// root.hightlightVars = hil;
-// // START KGU#183 2016-04-24: Enh. #169
-// selected = root;
-// selected.setSelected(true);
-// // END KGU#183 2016-04-24
-// // START KGU#192 2016-05-02: #184 - The Root must be marked for saving
-// root.setChanged();
-// // END KGU#192 2016-05-02
-// // START KGU#194 2016-05-08: Bugfix #185 - multiple routines per file
-// }
-// // END KGU#194 2016-05-08
-// }
-// else
-// {
-// // show error
-// // START KGU 2016-01-11: Yes and No buttons somewhat strange...
-// //JOptionPane.showOptionDialog(null,d7.error,
-// // "Parser Error",
-// // JOptionPane.OK_OPTION,JOptionPane.ERROR_MESSAGE,null,null,null);
-// JOptionPane.showMessageDialog(null, d7.error,
-// Menu.msgTitleParserError.getText(),
-// JOptionPane.ERROR_MESSAGE, null);
-// // END KGU 2016-01-11
-// }
-//
-// redraw();
-// analyse();
-// }
-// }
- // START KGU#537 2018-06-29: Enh. #553
- /**
- * Internal helper class for the background parsing of code to be imported.
- *
- * @author Kay Gürtzig
- */
- private class ImportWorker extends SwingWorker, Integer> {
-
- private CodeParser parser;
- private File file;
- private Ini ini;
- private String logPath;
-
- public ImportWorker(CodeParser _parser, File _file, Ini _ini, String _logPath) {
- this.parser = _parser;
- this.file = _file;
- this.ini = _ini;
- this.logPath = _logPath;
- }
-
- @Override
- protected List doInBackground() throws Exception {
- //System.out.println("*** " + this.getClass().getSimpleName()+" going to work!");
- this.parser.setSwingWorker(this);
- List roots = null;
- roots = parser.parse(file.getAbsolutePath(),
- ini.getProperty("impImportCharset", "ISO-8859-1"),
- // START KGU#354 2017-04-27: Enh. #354
- logPath
- // END KGU#354 2017-04-27
- );
- return roots;
- }
-
- }
- // END KGU#537 2018-06-30
-
- /**
- * Gets an instance of the given parser class, interactively selects a
- * source file for the chosen language parses the file and tries to build a
- * structogram from it in a background thread.
- *
- * @param options
- */
- public void importCode(/*String _parserClassName,*/) {
- // only save if something has been changed
- saveNSD(true);
-
- CodeParser parser = null;
-
- // START KGU#354 2017-03-14: Enh. #354
- this.retrieveParsers();
- // END KGU#354 2017-03-14
-
- JFileChooser dlgOpen = new JFileChooser();
- // START KGU#287 2017-01-09: Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
- GUIScaler.rescaleComponents(dlgOpen);
- // END KGU#287 2017-01-09
- dlgOpen.setDialogTitle(Menu.msgTitleImport.getText());
- // set directory
- // START KGU#354 2017-04-26: Enh. #354
- //if(root.getFile()!=null)
- //{
- // dlgOpen.setCurrentDirectory(root.getFile());
- //}
- File importDir = this.lastCodeImportDir;
- if (importDir != null || (importDir = root.getFile()) != null) {
- dlgOpen.setCurrentDirectory(importDir);
- } // END KGU#354 2017-04-26
- else {
- dlgOpen.setCurrentDirectory(currentDirectory);
- }
-
- for (CodeParser psr : parsers) {
- dlgOpen.addChoosableFileFilter(psr);
- // START KGU#354 2017-04-26: Enh. #354 GUI improvement
- if (psr.getDialogTitle().equals(this.lastImportFilter)) {
- dlgOpen.setFileFilter(psr);
- }
- }
- //dlgOpen.setFileFilter(parser);
-
- hideComments(); // Issue #143: Hide the current comment popup if visible
- int result = dlgOpen.showOpenDialog(NSDControl.getFrame());
-
- if (result == JFileChooser.APPROVE_OPTION) {
- File file = dlgOpen.getSelectedFile().getAbsoluteFile();
-
- if (!file.canRead()) {
- JOptionPane.showMessageDialog(this.getFrame(),
- Menu.msgImportFileReadError.getText().replace("%", file.getPath()));
- return;
- }
-
- // Identify a suited or the selected parser
- javax.swing.filechooser.FileFilter filter = dlgOpen.getFileFilter();
-
- parser = identifyParser(file, filter);
-
- if (parser == null) {
- JOptionPane.showMessageDialog(this.getFrame(),
- Menu.msgImportCancelled.getText().replace("%", file.getPath()));
- return;
- }
-
- // START KGU#354 2017-04-26: Enh. #354
- this.lastImportFilter = parser.getDialogTitle();
- this.lastCodeImportDir = file.getParentFile();
- // END KGU#354 2017-04-26
-
- Cursor origCursor = getCursor();
- try {
- setCursor(new Cursor(Cursor.WAIT_CURSOR));
-
- // load and parse source-code
- //CParser cp = new CParser("C-ANSI.cgt");
- // START KGU#194 2016-05-08: Bugfix #185 - mechanism for multiple roots per file
- //Root rootNew = d7.parse(filename);
- // START KGU#265 2016-09-28: Enh. #253 brought the Charset configuration. So make use of it.
- //List newRoots = d7.parse(filename, "ISO-8859-1");
- Ini ini = Ini.getInstance();
- // START KGU#354 2017-04-27: Enh. #354
- boolean isVerbose = ini.getProperty("impLogToDir", "false").equals("true");
- String logPath = null;
- if (isVerbose) {
- logPath = ini.getProperty("impLogDir", "");
- if (logPath.isEmpty()) {
- logPath = file.getParent();
- } else if (logPath.equals(".")) {
- if (currentDirectory != null) {
- if (!currentDirectory.isDirectory()) {
- logPath = currentDirectory.getParent();
- } else {
- logPath = currentDirectory.getPath();
- }
- }
- }
- }
- // END KGU#354 2017-04-27
- // START KGU#354 2017-05-11: Enh. #354 - we better use a new instance instead of statically sharing it
- parser = parser.getClass().getDeclaredConstructor().newInstance();
- // END KGU#354 2017-05-11
- // START KGU#395 2017-07-02: Enh. #357
- String parserClassName = parser.getClass().getSimpleName();
- for (int i = 0; i < parserPlugins.size(); i++) {
- GENPlugin plug = parserPlugins.get(i);
- if (plug.getKey().equals(parserClassName)) {
- this.setPluginSpecificOptions(parser, parserClassName, plug.options);
- }
- }
- // END KGU#395 2017-07-02
- // START KGU#537 2018-06-30: Enh. #553
-// List newRoots = parser.parse(file.getAbsolutePath(),
-// ini.getProperty("impImportCharset", "ISO-8859-1"),
-// // START KGU#354 2017-04-27: Enh. #354
-// logPath
-// // END KGU#354 2017-04-27
-// );
- ImportWorker worker = new ImportWorker(parser, file, ini, logPath);
- // Pop up the progress monitor (it will be closed via the OK buttons).
- new CodeImportMonitor(this.getFrame(), worker, parser.getDialogTitle());
- List newRoots = worker.get();
- // END KGU#537 2018-06-30
- // END KGU#265 2016-09-28
- // END KGU#194 2016-05-08
- if (parser.error.equals("") && !worker.isCancelled()) {
- //boolean hil = root.highlightVars;
- // START KGU#194 2016-05-08: Bugfix #185 - there may be multiple routines
- Root firstRoot = null;
- //root = rootNew;
- Iterator iter = newRoots.iterator();
- if (iter.hasNext()) {
- firstRoot = iter.next();
- }
- // START KGU#553 2018-07-10: In case of too many diagrams Structorizer would go zombie
- int nRoots = newRoots.size();
- int maxRoots = Integer.parseInt(ini.getProperty("impMaxRootsForDisplay", "20"));
- if (nRoots > maxRoots) {
- String[] options = {Menu.lblContinue.getText(), Menu.lblCancel.getText()};
- int chosen = JOptionPane.showOptionDialog(this.getFrame(),
- Menu.msgTooManyDiagrams.getText().replace("%", Integer.toString(maxRoots)),
- Menu.ttlCodeImport.getText(),
- JOptionPane.YES_NO_OPTION,
- JOptionPane.WARNING_MESSAGE, null,
- options, 0);
- if (chosen != JOptionPane.OK_OPTION) {
- newRoots.clear();
- iter = newRoots.iterator();
- }
- startSerialMode();
- try {
- while (iter.hasNext() && getSerialDecision(SerialDecisionAspect.SERIAL_SAVE) != SerialDecisionStatus.NO_TO_ALL) {
- Root nextRoot = iter.next();
- //nextRoot.highlightVars = hil;
- nextRoot.setChanged(false);
- // If the saving attempt fails, ask whether the saving loop is to be cancelled
- if (!this.saveNSD(nextRoot, false)) {
- if (JOptionPane.showConfirmDialog(
- this.getFrame(),
- Menu.msgCancelAll.getText(),
- Menu.ttlCodeImport.getText(),
- JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
- // User decided not to save further diagrams.
- setSerialDecision(SerialDecisionAspect.SERIAL_SAVE, false);
- }
- // Saving failed, but no abort, so go on with next file (don't change status)
- }
- }
- } finally {
- endSerialMode();
- newRoots.clear();
- iter = newRoots.iterator();
- nRoots = 1;
- }
- }
- // END KGU#553 2018-07-10
- while (iter.hasNext()) {
- root = iter.next();
- //root.highlightVars = hil;
- if (Element.E_VARHIGHLIGHT) {
- root.retrieveVarNames(); // Initialise the variable table, otherwise the highlighting won't work
- }
- // The Root must be marked for saving
- root.setChanged(false);
- // ... and be added to the Arranger
- // START KGU#626 2018-12-28 Enh. #657 - group management introduced
- //this.arrangeNSD();
- this.arrangeNSD(file.getName());
- // END KGU#626 2018-12-28
- Arranger.getInstance().enableNotification(false);
- }
- if (firstRoot != null) {
- root = firstRoot;
- // END KGU#194 2016-05-08
- //root.highlightVars = hil;
- if (Element.E_VARHIGHLIGHT) {
- root.retrieveVarNames(); // Initialise the variable table, otherwise the highlighting won't work
- }
- // START KGU#183 2016-04-24: Enh. #169
- selected = root;
- selected.setSelected(true);
- // END KGU#183 2016-04-24
- // START KGU#192 2016-05-02: #184 - The Root must be marked for saving
- root.setChanged(false);
- // END KGU#192 2016-05-02
- // START KGU#354 2017-05-23: Enh.#354 - with many roots it's better to push the principal root to the Arranger, too
- // START KGU#626 2018-12-28: Enh. #657 - with groups, push the main diagram, too, also in case of a program
- //if (nRoots > 2 || !root.isProgram()) {
- // this.arrangeNSD();
- //}
- if (nRoots > 2) {
- this.arrangeNSD(file.getName());
- }
- // END KGU#626 2018-12-28
- // END KGU#354 2017-05-23
- // START KGU#194 2016-05-08: Bugfix #185 - multiple routines per file
- }
- // END KGU#194 2016-05-08
- } else {
- // show error
- // START KGU 2016-01-11: Yes and No buttons somewhat strange...
- //JOptionPane.showOptionDialog(null,d7.error,
- // "Parser Error",
- // JOptionPane.OK_OPTION,JOptionPane.ERROR_MESSAGE,null,null,null);
- // START KGU#364 2017-12-12: Issue #471 - Allow to copy the content
- //JOptionPane.showMessageDialog(this.NSDControl.getFrame(),
- // parser.error,
- // Menu.msgTitleParserError.getText(),
- // JOptionPane.ERROR_MESSAGE, null);
- String[] options = {Menu.lblOk.getText(), Menu.lblCopyToClipBoard.getText()};
- int chosen = JOptionPane.showOptionDialog(this.getFrame(),
- parser.error,
- Menu.msgTitleParserError.getText(),
- JOptionPane.YES_NO_OPTION,
- JOptionPane.ERROR_MESSAGE, null,
- options, 0);
- if (chosen == 1) {
- Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
- // START KGU#604 2018-10-29: Enh. #627 - Append a stacktrace if available
- //StringSelection toClip = new StringSelection(parser.error);
- String errorString = parser.error;
- if (parser.exception != null) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- parser.exception.printStackTrace(new PrintStream(baos));
- errorString += "\n\nSTACK TRACE\n(A more detailed trace will be in the structorizer log file):\n\n" + baos.toString();
- }
- StringSelection toClip = new StringSelection(errorString);
- // END KGU#604 2018-10-29
- clipboard.setContents(toClip, null);
- }
- // END KGU#364 2017-12-12
- // END KGU 2016-01-11
- }
- } catch (java.util.concurrent.CancellationException ex) {
- JOptionPane.showMessageDialog(this.getFrame(),
- Menu.msgImportCancelled.getText().replace("%", file.getPath()));
- } catch (Exception ex) {
- String message = ex.getLocalizedMessage();
- if (message == null) {
- message = ex.getMessage();
- // START KGU#484 2018-04-05: Issue #463
- //ex.printStackTrace();
- logger.log(Level.WARNING, "", ex);
- // END KGU#484 2018-04-05
- }
- if (message == null || message.isEmpty()) {
- message = ex.toString();
- }
- JOptionPane.showMessageDialog(this.getFrame(),
- Menu.msgErrorUsingParser.getText().replace("%", parser.getDialogTitle()) + "\n" + message,
- Menu.msgTitleError.getText(),
- JOptionPane.ERROR_MESSAGE);
- } finally {
- doButtons();
- redraw();
- analyse();
- // START KGU#444/KGU#618 2018-12-18: Issue #417, #649 - We may have obtained huge diagrams...
- this.adaptScrollUnits();
- // END KGU#444/KGU#618 2018-12-18
- // START KGU#705 2019-09-24: Enh. #738
- updateCodePreview();
- // END KGU#705 2019-09-24
- setCursor(origCursor);
- if (Arranger.hasInstance()) {
- // KGU#947 2021-03-01 Bugfix #950 Bad implementation caused permanent loss of notifications
- Arranger.getInstance().enableNotification(true);
- }
- }
- }
- }
-
- // START KGU#354 2017-03-15: Enh. #354 - auxiliary methods
- // Tries to disambiguate the parser for the given file
- private CodeParser identifyParser(File file, FileFilter usedFilter) {
- CodeParser parser = null;
-
- Vector candidates = new Vector();
- String[] choice = new String[parsers.size()];
- Vector candStrings = new Vector();
- // We are better prepared for the ambiguous case...
- int nr0 = 1, nr = 1;
- final String format = "%2d: %s";
- for (CodeParser psr : parsers) {
- String descr = psr.getDescription();
- choice[nr0 - 1] = String.format(format, nr0, descr);
- nr0++;
- if (usedFilter == psr) {
- // The user had explicitly chosen this filter, so we are ready
- parser = psr;
- break;
- } else if (psr.accept(file)) {
- candidates.add(psr);
- candStrings.add(String.format(format, nr++, descr));
- }
- }
-
- if (parser == null) {
- if (candidates.size() == 1) {
- parser = candidates.get(0);
- } else {
- if (!candidates.isEmpty()) {
- choice = candStrings.toArray(new String[candStrings.size()]);
- } else {
- candidates = parsers;
- }
- JComboBox cbParsers = new JComboBox(choice);
- String prompt = Menu.msgSelectParser.getText().replace("%", file.getName());
- int resp = JOptionPane.showConfirmDialog(null,
- new Object[]{prompt, cbParsers},
- Menu.ttlCodeImport.getText(),
- JOptionPane.OK_CANCEL_OPTION);
- if (resp == JOptionPane.OK_OPTION) {
- int index = cbParsers.getSelectedIndex();
- // Well this test is of course mere paranoia...
- if (index >= 0 && index < candidates.size()) {
- parser = candidates.get(index);
- }
- }
- }
- }
- return parser;
- }
-
- /**
- * Lazy initialization method for static field {@link #parsers}
- */
- private void retrieveParsers() {
- if (parsers != null) {
- return;
- }
- parsers = new Vector();
- String errors = "";
- try ( BufferedInputStream buff = new BufferedInputStream(getClass().getResourceAsStream("parsers.xml"))) {
- GENParser genp = new GENParser();
- parserPlugins = genp.parse(buff);
- } catch (IOException e) {
- // START KGU#484 2018-04-05: Issue #463
- //e.printStackTrace();
- logger.log(Level.WARNING, "Couldn't close parser plugin definition file.", e);
- // END KGU#484 2018-04-05
- }
- for (int i = 0; parserPlugins != null && i < parserPlugins.size(); i++) {
- GENPlugin plugin = parserPlugins.get(i);
- final String className = plugin.className;
- try {
- Class> genClass = Class.forName(className);
- parsers.add((CodeParser) genClass.getDeclaredConstructor().newInstance());
- } catch (Exception ex) {
- errors += "\n" + plugin.title + ": " + ex.getLocalizedMessage();
- }
- }
- if (!errors.isEmpty()) {
- errors = Menu.msgTitleLoadingError.getText() + errors;
- JOptionPane.showMessageDialog(this.getFrame(), errors,
- Menu.msgTitleParserError.getText(), JOptionPane.ERROR_MESSAGE);
- }
- }
- // END KGU#354 2017-03-15
-
- /*========================================
- * export code methods
- *========================================*/
- /**
- * Export the current diagram to the programming language associated to the
- * generator {@code _generatorClassName}
- *
- * @param _generatorClassName - class name of he generator to be used
- * @param _specificOptions - generator-specific options
- */
- public void export(String _generatorClassName, Vector> _specificOptions) {
- // START KGU#815 2020-02-20: Enh. 828 - We offer not only the export of groups but also of diagrams
- // (Code moved to export(Root, String, Vector))
- export(root, _generatorClassName, _specificOptions);
- // END KGU#815 2020-02-20
- }
-
- // START KGU#815 2020-03-16: Enh. #828
- /**
- * Export the given diagram {@code _root} to the programming language
- * associated to the generator {@code _generatorClassName}.
- *
- * @param _generatorClassName - class name of he generator to be used
- * @param _specificOptions - generator-specific options
- */
- public void export(Root _root, String _generatorClassName, Vector> _specificOptions) {
- // START KGU#901 2020-12-29: Issue #901 apply WAIT_CURSOR during time-consuming actions
- Cursor origCursor = getCursor();
- // END KGU#901 2020-12-29
- try {
- Class> genClass = Class.forName(_generatorClassName);
- Generator gen = (Generator) genClass.getDeclaredConstructor().newInstance();
- // START KGU#170 2016-04-01: Issue #143
- hideComments(); // Hide the current comment popup if visible
- // END KGU#170 2016-04-01
- // START KGU#815 2020-03-30: Enh. #828 If called from ArrangerIndex, options will be null
- if (_specificOptions == null) {
- for (GENPlugin plugin : Menu.generatorPlugins) {
- if (plugin.className.equals(_generatorClassName)) {
- _specificOptions = plugin.options;
- break;
- }
- }
- if (_specificOptions == null) {
- _specificOptions = new Vector>();
- }
- }
- // END KGU#815 2020-03-20
- // START KGU#395 2017-05-11: Enh. #357
- this.setPluginSpecificOptions(gen, _generatorClassName, _specificOptions);
- // END KGU#395 2017-05-11
- // START KGU#901 2020-12-29: Issue #901 applay WAIT_CURSOR for time-consuming actions
- setCursor(new Cursor(Cursor.WAIT_CURSOR));
- // END KGU#901 2020-12-29
- // START KGU 2017-04-26: Remember the export directory
- //gen.exportCode(root, currentDirectory, NSDControl.getFrame());
- // START KGU#654 2019-02-16: Enh. #681 Don't overwrite the last export dir in case the export failed or was cancelled
- //this.lastCodeExportDir =
- File exportDir
- = // END KGU#654 2019-02-16
- gen.exportCode(_root,
- (lastCodeExportDir != null ? lastCodeExportDir : currentDirectory),
- // START KGU#676/KGU#679 2019-03-13: Enh. #696,#698 Specify the routine pool expicitly
- //NSDControl.getFrame());
- NSDControl.getFrame(),
- (Arranger.hasInstance() ? Arranger.getInstance() : null));
- // END KGU#676 2019-03-13
- // START KGU#654 2019-02-16: Enh. #681
- // START KGU#456 2017-11-05: Enh. #452
- if (_root == root && root.advanceTutorialState(26, root)) {
- analyse();
- }
- // END KGU#456 2017-11-05
- // START KGU#654 2019-02-15/16: Enh. #681 - count the successful exports to the target language
- if (exportDir != null) {
- this.lastCodeExportDir = exportDir;
-
- String prefGenName = this.getPreferredGeneratorName();
- String thisGenName = null;
- for (GENPlugin plugin : Menu.generatorPlugins) {
- if (plugin.className.equals(_generatorClassName)) {
- thisGenName = plugin.title;
- break;
- }
- }
- if (thisGenName.equals(this.lastGeneratorName)) {
- if (++this.generatorUseCount == this.generatorProposalTrigger && this.generatorProposalTrigger > 0
- && !prefGenName.equals(this.lastGeneratorName)) {
- // START KGU#901 2020-12-29: Issue #901 applay WAIT_CURSOR for time-consuming actions
- setCursor(origCursor);
- // END KGU#901 2020-12-29
- if (JOptionPane.showConfirmDialog(this.getFrame(),
- Menu.msgSetAsPreferredGenerator.getText().replace("%1", thisGenName).replaceAll("%2", Integer.toString(this.generatorUseCount)),
- Menu.lbFileExportCodeFavorite.getText().replace("%", thisGenName),
- JOptionPane.YES_NO_OPTION,
- JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
- this.prefGeneratorName = thisGenName;
- Ini.getInstance().setProperty("genExportPreferred", thisGenName);
- Ini.getInstance().save();
- // START KGU#705 2019-09-23: Enh. #738
- this.updateCodePreview();
- // END KGU#705 2019-09-23
- // doButtons() is assumed to be performed after his method had been called, anyway
- }
- }
- } else {
- this.lastGeneratorName = thisGenName;
- this.generatorUseCount = 1;
- }
- }
- // END KGU#654 2019-02-15/16
- } catch (Exception ex) {
- // START KGU#901 2020-12-29: Issue #901 applay WAIT_CURSOR for time-consuming actions
- setCursor(new Cursor(Cursor.WAIT_CURSOR));
- // END KGU#901 2020-12-29
- String message = ex.getLocalizedMessage();
- if (message == null) {
- message = ex.getMessage();
- }
- if (message == null || message.isEmpty()) {
- message = ex.toString();
- }
- JOptionPane.showMessageDialog(this.getFrame(),
- Menu.msgErrorUsingGenerator.getText().replace("%", _generatorClassName) + "\n" + message,
- Menu.msgTitleError.getText(),
- JOptionPane.ERROR_MESSAGE);
- } // START KGU#901 2020-12-29: Issue #901 apply WAIT_CURSOR during time-consuming actions
- finally {
- setCursor(origCursor);
- }
- // END KGU#901 2020-12-29
- }
-
- /**
- * Export the group represented by the programming language associated to
- * the generator {@code _generatorClassName}
- *
- * @param group - The {@link Group} to be exported
- * @param generatorName - class name of the generator to be used
- * @param extraOptions - a possible extra option map (handled like plugin
- * options) or null
- */
- public void exportGroup(Group group, String generatorName, Map extraOptions) {
- hideComments(); // Hide the current comment popup if visible (issue #143)
- File groupFile = group.getFile();
- File targetDir = lastCodeExportDir;
- // START KGU#935 2021-02-12: Bugfix #936
- //if ((targetDir == null || Ini.getInstance().getProperty("", "true").equals("true")) && groupFile.exists()) {
- if ((targetDir == null || Ini.getInstance().getProperty("", "true").equals("true"))
- && groupFile != null && groupFile.exists()) {
- // END KGU#935 2021-02-12
- targetDir = groupFile.getParentFile();
- }
- if (targetDir == null || !targetDir.exists()) {
- targetDir = currentDirectory;
- }
- String groupName = group.proposeFileName().replace(".", "_");
-
- // START KGU#901 2020-12-29: Issue #901 applay WAIT_CURSOR for time-consuming actions
- Cursor origCursor = getCursor();
- // END KGU#901 2020-12-29
- try {
- Class> genClass = Class.forName(generatorName);
- Generator gen = (Generator) genClass.getDeclaredConstructor().newInstance();
- Vector> options = null;
- for (GENPlugin plugin : Menu.generatorPlugins) {
- if (plugin.className.equals(generatorName)) {
- options = plugin.options;
- break;
- }
- }
- if (options == null) {
- options = new Vector>();
- }
- this.setPluginSpecificOptions(gen, generatorName, options);
- // START KGU#396 2020-04-01: Temporary extra mechanism for #440
- if (extraOptions != null) {
- for (Map.Entry option : extraOptions.entrySet()) {
- gen.setPluginOption(option.getKey(), option.getValue());
- }
- }
- // END KGU#396 2020-04-01
-
- // START KGU#901 2020-12-29: Issue #901 applay WAIT_CURSOR for time-consuming actions
- setCursor(new Cursor(Cursor.WAIT_CURSOR));
- // END KGU#901 2020-12-29
- File exportDir = gen.exportCode(group.getSortedRoots(), groupName,
- targetDir,
- NSDControl.getFrame(),
- (Arranger.hasInstance() ? Arranger.getInstance() : null));
-
- if (exportDir != null) {
- this.lastCodeExportDir = exportDir;
- }
- } catch (Exception ex) {
- // START KGU#901 2020-12-29: Issue #901 applay WAIT_CURSOR for time-consuming actions
- setCursor(origCursor);
- // END KGU#901 2020-12-29
- String message = ex.getLocalizedMessage();
- if (message == null) {
- message = ex.getMessage();
- }
- if (message == null || message.isEmpty()) {
- message = ex.toString();
- }
- JOptionPane.showMessageDialog(this.getFrame(),
- Menu.msgErrorUsingGenerator.getText().replace("%", generatorName) + "\n" + message,
- Menu.msgTitleError.getText(),
- JOptionPane.ERROR_MESSAGE);
- } // START KGU#901 2020-12-29: Issue #901 applay WAIT_CURSOR for time-consuming actions
- finally {
- setCursor(origCursor);
- }
- // END KGU#901 2020-12-29
- }
- // END KGU#815 2020-03-16
-
- // START KGU#705 2019-09-23: Enh. #738: Code preview support
- /**
- * Place a code preview for the current diagram to the currrent favourite
- * programming language. Also fills the {@link #codePreviewMap} with
- * associations between {@link Element}s and line intervals.
- *
- * @param _specificOptions - generator-specific options
- */
- public void updateCodePreview() {
- if (this.show_CODE_PREVIEW && this.codePreview != null) {
- String generatorName = this.getPreferredGeneratorName();
- try {
- codePreviewMap = new HashMap();
- Generator gen = null;
- Arranger arranger = null;
- if (Arranger.hasInstance()) {
- arranger = Arranger.getInstance();
- }
- for (GENPlugin plugin : Menu.generatorPlugins) {
- if (plugin.title.equals(generatorName)) {
- Class> genClass = Class.forName(plugin.className);
- gen = (Generator) genClass.getDeclaredConstructor().newInstance();
- fetchPluginSpecificExportOptions(gen);
- String code = gen.deriveCode(root,
- NSDControl.getFrame(),
- arranger,
- codePreviewMap);
- codePreview.setText(code);
- break;
- }
- }
- setCodePreviewTooltip();
- } catch (Exception ex) {
- String message = ex.getLocalizedMessage();
- if (message == null) {
- message = ex.getMessage();
- }
- if (message == null || message.isEmpty()) {
- message = ex.toString();
- }
- JOptionPane.showMessageDialog(this.getFrame(),
- Menu.msgErrorUsingGenerator.getText().replace("%", generatorName) + "\n" + message,
- Menu.msgTitleError.getText(),
- JOptionPane.ERROR_MESSAGE);
- }
- }
- SwingUtilities.invokeLater(new Runnable() {
- @Override
- public void run() {
- // TODO Auto-generated method stub
- highlightCodeForSelection();
- }
- });
- //highlightCodeForSelection();
- }
-
- private void fetchPluginSpecificExportOptions(Generator _generator) {
- for (GENPlugin plugin : Menu.generatorPlugins) {
- if (plugin.className.equals(_generator.getClass().getName())) {
- // FIXME: Improve performance here! Avoid repetitive retrieval but ensure sensitiveness to changes
- setPluginSpecificOptions(_generator, plugin.className, plugin.options);
- break;
- }
- }
- }
- // END KGU#705 2019-09-23
-
- // START KGU#395 2017-05-11: Enh. #357 / Revised KGU#416 2017-06-20
- private void setPluginSpecificOptions(IPluginClass _gen, String _generatorClassName,
- Vector> _specificOptions) {
- Ini ini = Ini.getInstance();
- for (HashMap optionSpec : _specificOptions) {
- String optionKey = optionSpec.get("name");
- String valueStr = ini.getProperty(_generatorClassName + "." + optionKey, "");
- Object value = null;
- String type = optionSpec.get("type");
- String items = optionSpec.get("items");
- // Now convert the option into the specified type
- if (!valueStr.isEmpty() && type != null || items != null) {
- // Better we fail with just a single option than with the entire method
- try {
- if (items != null) {
- value = valueStr;
- } else if (type.equalsIgnoreCase("character")) {
- value = valueStr.charAt(0);
- } else if (type.equalsIgnoreCase("boolean")) {
- value = Boolean.parseBoolean(valueStr);
- } else if (type.equalsIgnoreCase("int") || type.equalsIgnoreCase("integer")) {
- value = Integer.parseInt(valueStr);
- } else if (type.equalsIgnoreCase("unsigned")) {
- value = Integer.parseUnsignedInt(valueStr);
- } else if (type.equalsIgnoreCase("double") || type.equalsIgnoreCase("float")) {
- value = Double.parseDouble(valueStr);
- } else if (type.equalsIgnoreCase("string")) {
- value = valueStr;
- }
- } catch (NumberFormatException ex) {
- String message = ex.getMessage();
- if (message == null || message.isEmpty()) {
- message = ex.toString();
- }
- logger.log(Level.SEVERE, "{0}: {1} on converting \"{2}\" to {3} for {4}",
- new Object[]{
- _gen.getClass().getSimpleName(),
- message,
- valueStr,
- type,
- optionKey});
- }
- }
- if (value != null) {
- _gen.setPluginOption(optionKey, value);
- }
- }
- }
- // END KGU#395 2017-05-11
-
- // START KGU#208 2016-07-22: Enh. #199
- /*========================================
- * help method
- *========================================*/
- /**
- * Tries to open the online User Guide in the browser
- */
- public void helpNSD() {
- // START KGU#250 2016-09-17: Issue #245 (defective Linux integration workaround)
-// try {
-// Desktop.getDesktop().browse(new URI("http://help.structorizer.fisch.lu/index.php"));
-// }
-// catch(Exception ex)
-// {
-// ex.printStackTrace();
-// // We may get here if there is no standard browser or no standard application for web links
-// // configured (as issue #245 proved) - in case of missing network access the browser will
-// // rather show a message itself, though.
-// String message = ex.getLocalizedMessage();
-// if (message == null) message = ex.getMessage();
-// JOptionPane.showMessageDialog(null,
-// message,
-// Menu.msgTitleURLError.getText(),
-// JOptionPane.ERROR_MESSAGE);
-// }
- // START KGU#563 2018-07-26: Issue #566
- //String help = "http://help.structorizer.fisch.lu/index.php";
- String help = Element.E_HELP_PAGE;
- // END KGU#563 2018-07-26
- boolean isLaunched = false;
- try {
- isLaunched = lu.fisch.utils.Desktop.browse(new URI(help));
- } catch (URISyntaxException ex) {
- // START KGU#484 2018-04-05: Issue #463
- //ex.printStackTrace();
- logger.log(Level.WARNING, "Can't browse help URL.", ex);
- // END KGU#484 2018-04-05
- }
- // START KGU 2018-12-24
- // The isLaunched mechanism above does not signal an unavailable help page.
- // With the following code we can find out whether the help page was available...
- // TODO In this case we might offer to download the PDF for offline use,
- // otherwise we could try to open a possibly previously downloaded PDF ...
- URL url;
- HttpsURLConnection con = null;
- try {
- isLaunched = false;
- url = new URL(help);
- con = (HttpsURLConnection) url.openConnection();
- if (con != null) {
- con.connect();
- }
- isLaunched = true;
- } catch (SocketTimeoutException ex) {
- logger.log(Level.WARNING, "Timeout connecting to " + help, ex);
- } catch (MalformedURLException e1) {
- logger.log(Level.SEVERE, "Malformed URL " + help, e1);
- } catch (IOException e) {
- logger.log(Level.WARNING, "Failed Access to " + help, e);
- } finally {
- if (con != null) {
- con.disconnect();
- }
- }
- // END KGU 2018-12-24
- if (!isLaunched) {
- String message = Menu.msgBrowseFailed.getText().replace("%", help);
- boolean offlineShown = this.showHelpPDF();
- if (offlineShown) {
- message += "\n\n" + Menu.msgShowingOfflineGuide.getText();
- }
- JOptionPane.showMessageDialog(null,
- message,
- Menu.msgTitleURLError.getText(),
- offlineShown ? JOptionPane.WARNING_MESSAGE : JOptionPane.ERROR_MESSAGE);
- // TODO We might look for a downloaded PDF version and offer to open this instead...
-
- } // END KGU#250 2016-09-17
- else {
- // Download the current PDF version if there hasn't been any by now.
- this.downloadHelpPDF(false, null);
- }
- }
- // END KGU#208 2016-07-22
-
- // START KGU#791 2010-10-20: Issue #801 - we need a background thread for explicit download
- private boolean helpDownloadCancelled = false;
-
- /**
- * Tries to download the most recent user guide as PDF in a backround thread
- * with progress bar. Will override a possibly existing file.
- *
- * @param title - the menu item caption to be used as window title
- */
- public void downloadHelpPDF(String title) {
- SwingWorker worker = new SwingWorker() {
-
- @Override
- protected Boolean doInBackground() throws Exception {
- return downloadHelpPDF(true, this);
- }
-
- public void done() {
- if (isCancelled()) {
- // We must tell method downloadHelpPDF that the task was aborted
- // (The possibly incompletely transferred file must be deleted.)
- helpDownloadCancelled = true;
- }
- }
-
- };
- new DownloadMonitor(getFrame(), worker, title, Element.E_HELP_FILE_SIZE);
- }
- // END KGU#791 2020-10-20
-
- // START KGU#791 2020-01-20: Enh. #801 support offline help
- /**
- * Tries to download the PDF version of the user guide to the ini directory
- *
- * @param overrideExisting - if an existing user guide file is to be
- * overriden by the newest one
- * @param worker - if given then the transfer chunks are chosen smaller and
- * a regular progress message will be sent
- * @return true if the download was done and successful.
- */
- public boolean downloadHelpPDF(boolean overrideExisting, SwingWorker worker) {
- /* See https://stackoverflow.com/questions/921262/how-to-download-and-save-a-file-from-internet-using-java
- * for technical discussion
- */
- // KGU#791 2020-10-20 Method revised to allow running in a backround thread
- helpDownloadCancelled = false;
- String helpFileName = Element.E_HELP_FILE;
- File helpDir = Ini.getIniDirectory(true);
- File helpFile = new File(helpDir.getAbsolutePath() + File.separator + helpFileName);
- String helpFileURI = Element.E_DOWNLOAD_PAGE + "?file=" + helpFileName;
- boolean overwritten = false;
- long copiedTotal = 0;
- long chunk = (worker == null) ? Integer.MAX_VALUE : 1 << 16;
- try {
- URL website = new URL(helpFileURI);
- if (!helpFile.exists() || overrideExisting) {
- try ( InputStream inputStream = website.openStream(); ReadableByteChannel readableByteChannel = Channels.newChannel(inputStream); FileOutputStream fileOutputStream = new FileOutputStream(helpFile)) {
- overwritten = true;
- long copied = 0;
- do {
- copied = fileOutputStream.getChannel().
- transferFrom(readableByteChannel, copiedTotal, chunk);
- if (worker != null) {
- worker.firePropertyChange("progress", copiedTotal, copiedTotal + copied);
- }
- copiedTotal += copied;
- } while (copied > 0);
- } catch (IOException ex) {
- logger.log(Level.INFO, "Failed to download help file!", ex);
- if (overrideExisting) {
- String error = ex.getMessage();
- if (error == null) {
- error = ex.toString();
- } else if (ex instanceof UnknownHostException) {
- error = Menu.msgHostNotAvailable.getText().replace("%", error);
- }
- JOptionPane.showMessageDialog(null,
- Menu.msgDownloadFailed.getText().replace("%", error),
- Menu.msgTitleURLError.getText(),
- JOptionPane.ERROR_MESSAGE);
- }
- }
- }
- } catch (MalformedURLException ex) {
- logger.log(Level.CONFIG, helpFileURI, ex);
- }
- if (helpDownloadCancelled && overwritten && helpFile.exists()) {
- helpFile.delete(); // File is likely to be defective
- copiedTotal = 0;
- }
- //System.out.println("Leaving downloadHelpPDF()");
- return copiedTotal > 0;
- }
-
- /**
- * Tries to present a downloaded PDF version of the user guide from the ini
- * directory.
- *
- * @return true if a user guide file is present and could be shown.
- */
- private boolean showHelpPDF() {
- String helpFileName = Element.E_HELP_FILE;
- File helpDir = Ini.getIniDirectory(true);
- File helpFile = new File(helpDir.getAbsolutePath() + File.separator + helpFileName);
- if (helpFile.canRead()) {
- return Desktop.open(helpFile);
- }
- return false;
- }
- // END KGU#791 2020-01-20
-
- /*========================================
- * update method
- *========================================*/
- /**
- * Shows an info box with the link to the download page of Structorizer and
- * informs whether there is a newer version available.
- *
- * @see #updateNSD(boolean)
- */
- public void updateNSD() // START KGU#300 2016-12-02: Enh. #300
- {
- updateNSD(true);
- }
-
- /**
- * Checks the availability of a newer version on the download page and shows
- * an info box with the link to the download page of Structorizer if a new
- * version is available or {@code evenWithoutNewerVersion} is true.
- *
- * @param evenWithoutNewerVersion - whether the infor box is always to be
- * popped up.
- * @see #updateNSD()
- */
- public void updateNSD(boolean evenWithoutNewerVersion) // END KGU#300 2016-12-02
- {
- // KGU#35 2015-07-29: Bob's code adopted with slight modification (Homepage URL put into a variable)
- // START KGU#563 2018-07-26: Issue #566
- //final String home = "https://structorizer.fisch.lu";
- final String home = Element.E_HOME_PAGE;
- // END KGU#563 2018-07-26
-
- // START KGU#300 2016-12-02: Enh. #300
- String latestVersion = getLatestVersionIfNewer();
- if (!evenWithoutNewerVersion && latestVersion == null) {
- return;
- }
- // END KGU#300 2016-12-02
-
- try {
- // START KGU#247 2016-09-17: Issue #243/#245 Translation support for update window content
- //JEditorPane ep = new JEditorPane("text/html","Goto " + home + " to look for updates
and news about Structorizer.");
- String fontAttr = "";
- double scaleFactor = Double.valueOf(Ini.getInstance().getProperty("scaleFactor", "1"));
- if (scaleFactor > 1) {
- int fontSize = (int) (3 * scaleFactor);
- fontAttr = " size=" + fontSize;
- }
- // START KGU#300 2016-12-02: Enh. #300
- String versionInfo = "";
- if (latestVersion != null) {
- versionInfo = Menu.msgNewerVersionAvail.getText().replace("%", latestVersion) + "
";
- }
- // END KGU#300 2016-12-02
- JEditorPane ep = new JEditorPane("text/html", ""
- + // START KGU#300 2016-12-02: Enh. #300
- versionInfo
- + // END KGU#300 2016-12-02
- Menu.msgGotoHomepage.getText().replace("%", "" + home + "")
- + "");
- // END KGU#247 2016-09-17
- ep.addHyperlinkListener(new HyperlinkListener() {
- @Override
- public void hyperlinkUpdate(HyperlinkEvent evt) {
- if (evt.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) {
- // START KGU#250 2016-09-17: Issue #245 (defective Linux integration workaround)
- //try {
- // Desktop.getDesktop().browse(evt.getURL().toURI());
- //}
- //catch(Exception ex)
- //{
- // ex.printStackTrace();
- //}
- String errorMessage = null;
- try {
- if (!lu.fisch.utils.Desktop.browse(evt.getURL().toURI())) {
- errorMessage = Menu.msgBrowseFailed.getText().replace("%", evt.getURL().toString());
- };
- } catch (Exception ex) {
- // START KGU#484 2018-04-05: Issue #463
- //ex.printStackTrace();
- logger.log(Level.WARNING, "Defective homepage link.", ex);
- // END KGU#484 2018-04-05
- errorMessage = ex.getLocalizedMessage();
- if (errorMessage == null) {
- errorMessage = ex.getMessage();
- }
- if (errorMessage == null || errorMessage.isEmpty()) {
- errorMessage = ex.toString();
- }
- }
- if (errorMessage != null) {
- JOptionPane.showMessageDialog(null,
- errorMessage,
- Menu.msgTitleURLError.getText(),
- JOptionPane.ERROR_MESSAGE);
-
- }
- // END KGU#250 2016-09-17
- }
- }
- });
- ep.setEditable(false);
- JLabel label = new JLabel();
- ep.setBackground(label.getBackground());
-
- JOptionPane.showMessageDialog(this.getFrame(), ep);
- } catch (Exception e) {
- // START KGU#484 2018-04-05: Issue #463
- //e.printStackTrace();
- logger.log(Level.WARNING, "Trouble accessing homepage.", e);
- // END KGU#484 2018-04-05
- }
- }
-
- // START KGU#300 2016-12-02 Enh. #300 Support for version retrieval
- /**
- * Helper method for {@link #updateNSD()}
- *
- * @return the version string, e.g. "3.29-14", of the latest version
- * available or null, depending on whether online version retrieval is
- * enabled by {@link #retrieveVersion}.
- */
- private String retrieveLatestVersion() {
- // START KGU#563 2018-07-26: Issue #566
- //final String http_url = "https://structorizer.fisch.lu/version.txt";
- final String http_url = Element.E_HOME_PAGE + "/version.txt";
- // END KGU#563 2018-07-26
-
- String version = null;
- if (retrieveVersion) {
- try {
-
- URL url = new URL(http_url);
- HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
-
- if (con != null) {
-
- BufferedReader br
- = new BufferedReader(
- new InputStreamReader(con.getInputStream()));
-
- String input;
- while ((input = br.readLine()) != null && version == null) {
- if (input.matches("\\d+\\.\\d+([-.][0-9]+)?")) {
- version = input;
- }
- }
- br.close();
-
- }
-
- } catch (MalformedURLException e) {
- logger.severe(e.toString());
- } catch (IOException e) {
- logger.warning(e.toString());
- }
- }
- return version;
- }
-
- // START KGU#300 2016-12-06: Not actually needed
-// private static int[] splitVersionString(String version)
-// {
-// StringList versionParts = StringList.explode(version, "\\.");
-// versionParts = StringList.explode(versionParts, "-");
+ }
+
+ /**
+ * Retrieves the types for subroutine variables {@code subVars} from the
+ * type map {@code parentTypes} of the calling routine and adopts or
+ * implants required includables.
+ *
+ * @param parentTypes - type map of the calling routine
+ * @param groups - Arranger groups of the calling routine (for Includable
+ * implantation)
+ * @param targetGroupName - name of the target group for the routine
+ * @param sub - the subroutine (its includeList may be modified)
+ * @param subVars - the interesting variables of the routine
+ * @return a StringList of type names in order of {@code subVars}.
+ */
+ private StringList prepareArgTypesForSub(HashMap parentTypes,
+ Collection groups, String targetGroupName, Root sub, StringList subVars) {
+ // START KGU#921 2021-01-30: Bugfix #921 we must ensure topological ordering
+ //HashMap sharedTypesMap = new HashMap();
+ HashMap sharedTypesMap = new LinkedHashMap();
+ // END KGU#921 2021-01-30
+ StringList typeNames = new StringList();
+ for (int i = 0; i < subVars.count(); i++) {
+ String typeName = "";
+ TypeMapEntry varType = null;
+ String varName = subVars.get(i);
+ if (Function.testIdentifier(varName, false, "")) {
+ varType = parentTypes.get(varName);
+ if (varType != null) {
+ typeName = varType.getCanonicalType(true, true);
+ } // START KGU#864 2020-04-28: Bugfix #865
+ else if (varName.equals("true") || varName.contentEquals("false")) {
+ typeName = "boolean";
+ }
+ // END KGU#864 2020-04-28
+ } else {
+ typeName = Element.identifyExprType(parentTypes, varName, true);
+ if (!typeName.isEmpty()) {
+ varType = parentTypes.get(":" + typeName);
+ }
+ }
+ // START KGU#921 2021-01-30: Bugfix #921 Had to be recursive!
+ //if (varType != null && varType.isRecord()) {
+ // Element defining = varType.getDeclaringElement();
+ // if (defining != null) {
+ // Root typeSource = Element.getRoot(defining);
+ // if (typeSource == root) {
+ // sharedTypesMap.putIfAbsent(varType.typeName, defining);
+ // }
+ // else if (typeSource != null) {
+ // sub.addToIncludeList(typeSource);
+ // }
+ // }
+ //}
+ gatherSharedTypes(sub, sharedTypesMap, varType, parentTypes);
+ // END KGU#921 2021-01-30
+ typeNames.add(typeName);
+ }
+ if (!sharedTypesMap.isEmpty()) {
+ // FIXME: We might also offer a combo box containing the already included diagrams of root
+ String hint = Menu.msgMustBeIdentifier.getText() + "\n";
+ String prompt1 = Menu.msgIncludableName.getText() + ": ";
+ String prompt = prompt1;
+ String includableName = null;
+ do {
+ includableName = JOptionPane.showInputDialog(prompt);
+ prompt = hint + prompt1;
+ } while (includableName == null || !Function.testIdentifier(includableName, false, null));
+ Root incl = null;
+ if (Arranger.hasInstance()) {
+ Vector includes = Arranger.getInstance().findIncludesByName(includableName, root, false);
+ if (!includes.isEmpty()) {
+ incl = includes.firstElement();
+ incl.addUndo();
+ }
+ }
+ boolean isNewIncl = incl == null;
+ if (isNewIncl) {
+ incl = new Root();
+ incl.setText(includableName);
+ incl.setInclude(true);
+ // adopt presentation properties from root
+ //incl.highlightVars = Element.E_VARHIGHLIGHT;
+ incl.isBoxed = root.isBoxed;
+ }
+ for (Element source : sharedTypesMap.values()) {
+ ((Subqueue) source.parent).removeElement(source);
+ incl.children.addElement(source);
+ }
+ incl.setChanged(false); // The argument false does NOT mean to reset the changed flag!
+ if (isNewIncl) {
+ // START KGU#638 2019-01-20: Issue #668 - Improved group association behaviour
+ //Arranger.getInstance().addToPool(incl, NSDControl.getFrame());
+ Arranger.getInstance().addToPool(incl, NSDControl.getFrame(), targetGroupName);
+ // END KGU#638 3019-01-20
+ }
+ // START KGU#626 2019-01-06: Enh. #657
+ // Associate the includable to all groups root is member of
+ if (groups != null) {
+ for (Group group : groups) {
+ Arranger.getInstance().attachRootToGroup(group, incl, null, this.getFrame());
+ }
+ }
+ // END KGU#626 2019-01-06
+ root.addToIncludeList(includableName);
+ sub.addToIncludeList(includableName);
+ }
+ return typeNames;
+ }
+ // END KGU#365 2017-03-19
+
+ // START KGU#921 2021-01-30: Bugfix #921
+ /**
+ * Recursively gathers the underlying complex (i.e. definition-mandatory)
+ * types the subroutine {@code sub} depends on together with their defining
+ * elements if retrievable.
+ *
+ * @param sub - a new subroutine diagram
+ * @param sharedTypesMap - the map of types assumed necessarily to be
+ * shared, may be enhanced here
+ * @param varType - a definitely referred type
+ * @param parentTypeMap - the type map of the calling diagram,
+ */
+ private void gatherSharedTypes(Root sub, HashMap sharedTypesMap, TypeMapEntry varType, HashMap parentTypeMap) {
+ if (varType != null) {
+ if (varType.isRecord() || varType.isEnum()) {
+ // Ensure a topological order of types by post-order traversal
+ if (varType.isRecord()) {
+ for (TypeMapEntry subType : varType.getComponentInfo(true).values()) {
+ gatherSharedTypes(sub, sharedTypesMap, subType, parentTypeMap);
+ }
+ }
+ Element defining = varType.getDeclaringElement();
+ if (defining != null) {
+ Root typeSource = Element.getRoot(defining);
+ if (typeSource == root) {
+ sharedTypesMap.putIfAbsent(varType.typeName, defining);
+ } else if (typeSource != null) {
+ sub.addToIncludeList(typeSource);
+ }
+ }
+ } else if (varType.isArray()) {
+ // Try to fetch the element type
+ String typeDescr = varType.getCanonicalType(true, false);
+ int i = 0;
+ while (i < typeDescr.length() && typeDescr.charAt(i) == '@') {
+ i++;
+ }
+ typeDescr = typeDescr.substring(i);
+ if (Function.testIdentifier(typeDescr, false, null)
+ && (varType = parentTypeMap.get(":" + typeDescr)) != null) {
+ gatherSharedTypes(sub, sharedTypesMap, varType, parentTypeMap);
+ }
+ }
+ }
+ }
+ // END KGU#921 2021-01-30
+
+ // START KGU#365 2017-04-14: Enh. #380
+ /**
+ * Retrieves all {@link Jump} elements within the span of {@code elements}
+ * trying to leave outside the span.
+ */
+ private List findUnsatisfiedJumps(IElementSequence elements) {
+ final class JumpFinder implements IElementVisitor {
+
+ private Subqueue scope = null;
+ private List foundJumps = new LinkedList();
+
+ public JumpFinder(Subqueue scope) {
+ this.scope = scope;
+ }
+
+ public List getJumps() {
+ return foundJumps;
+ }
+
+ @Override
+ public boolean visitPreOrder(Element _ele) {
+ if (_ele instanceof Jump) {
+ Jump jmp = (Jump) _ele;
+ if (jmp.isReturn() || jmp.isLeave() && jmp.getLeftLoop(scope) == null) {
+ this.foundJumps.add(jmp);
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visitPostOrder(Element _ele) {
+ return true;
+ }
+
+ }
+
+ Subqueue scope = elements.getSubqueue();
+ JumpFinder finder = new JumpFinder(scope);
+ scope.traverse(finder);
+ return finder.getJumps();
+
+ }
+ // END KGU#65 2017-04-14
+
+ // START KGU#667 2019-02-26: Enh. #689
+ /**
+ * @return true if the selected element is a {@link Call} and a called
+ * routine signature can be extracted or if the selected element is a
+ * {@link Root} and its include list is not empty.
+ * @see #editSubNSD()
+ */
+ public boolean canEditSub() {
+ boolean canEdit = false;
+ if (selected != null && selected instanceof Call) {
+ Function called = ((Call) selected).getCalledRoutine();
+ // We don't want to open an editor in case of a recursive call.
+ canEdit = (called != null && !(called.getSignatureString().equals(root.getSignatureString(false, false))));
+ }
+ // START KGU#770 2021-01-27: Enh. #917 Also support Includables
+ else if (selected != null && selected instanceof Root) {
+ canEdit = ((Root) selected).includeList != null
+ && !((Root) selected).includeList.isEmpty();
+ }
+ // END KGU#770 2021-01-27
+ return canEdit;
+ }
+
+ /**
+ * Summons the called subroutine of the selected {@link Call} into a
+ * {@link Mainfom} instance, possibly opens a new one. May instead offer a
+ * choice list of Includable names if the selected element is {@link Root}
+ * with non-empty include list an then summon the selected Includable in the
+ * same way.
+ *
+ * @see #canEditSub()
+ */
+ public void editSubNSD() {
+ // START KGU#770 2021-01-27: Enh. #917
+ Root referredRoot = null;
+ String targetGroupName = null; // This will be relevant for a new diagram
+ Collection myGroups = null;
+ // END KGU#770 2021-01-27
+ if (selected instanceof Call && this.canEditSub()) {
+ Call call = (Call) selected;
+ Function called = call.getCalledRoutine();
+ // START KGU#770 2021-01-27: Enh. #917
+ //Root referredRoot = null;
+ // END KGU#770 2021-01-27
+ // Try to find the subroutine in Arranger
+ if (Arranger.hasInstance()) {
+ Vector candidates = Arranger.getInstance()
+ .findRoutinesBySignature(called.getName(), called.paramCount(), root, false);
+ // Open a choice list if the group approach alone wasn't successful
+ referredRoot = chooseReferredRoot(candidates, Menu.msgChooseSubroutine.getText());
+ }
+ // START KGU#770 2021-01-27: Enh. #917
+ //String targetGroupName = null; // This will be relevant for a new subroutine
+ // END KGU#770 2021-01-27
+ // Create new subroutine root if we haven't been able to select an existing one
+ if (referredRoot == null) {
+ if (JOptionPane.showConfirmDialog(getFrame(),
+ Menu.msgCreateSubroutine.getText().replace("%", called.getSignatureString()),
+ Menu.msgTitleQuestion.getText(),
+ JOptionPane.OK_CANCEL_OPTION) != JOptionPane.OK_OPTION) {
+ return;
+ }
+ referredRoot = new Root();
+ myGroups = Arranger.getInstance().getGroupsFromRoot(root, true);
+ StringList params = new StringList();
+ for (int i = 0; i < called.paramCount(); i++) {
+ String param = called.getParam(i);
+ params.add(param);
+ }
+ // START KGU#744 2019-10-05: Issue #758 - retrieve argument types and care for shared types
+ StringList argTypes = this.prepareArgTypesForSub(root.getTypeInfo(), myGroups, targetGroupName, referredRoot, params);
+ String paramSeparator = ", ";
+ for (int i = 0; i < params.count(); i++) {
+ String typeName = argTypes.get(i).replace("@", "array of ");
+ // START KGU#864 2020-04-28: Bugfix #865
+ //if (!Function.testIdentifier(params.get(i), "")) {
+ String param = params.get(i);
+ if (!Function.testIdentifier(param, false, "") || param.equals("true") || param.equals("false")) {
+ // END KGU#864 2020-04-28
+ params.set(i, param = ("param" + (i + 1)));
+ }
+ if (!typeName.isEmpty() && !typeName.equals("???")) {
+ params.set(i, param + ": " + typeName);
+ paramSeparator = "; ";
+ }
+ }
+ // END KGU#744 2019-10-05
+ String result = "";
+ if (((Call) selected).isFunctionCall(false)) {
+ StringList lineTokens = Element.splitLexically(call.getUnbrokenText().get(0), true);
+ lineTokens.removeAll(" ");
+ String var = Call.getAssignedVarname(lineTokens, true);
+ if (Function.testIdentifier(var, false, null)) {
+ TypeMapEntry typeEntry = root.getTypeInfo().get(var);
+ result = typeEntry.getCanonicalType(true, true).replace("@", "array of ");
+ if (result == null) {
+ result = "";
+ }
+ }
+ if (!result.trim().isEmpty()) {
+ result = ": " + result.trim();
+ } else {
+ result = ": ???";
+ }
+ }
+ referredRoot.setText(called.getName() + "(" + params.concatenate(paramSeparator) + ")" + result);
+ referredRoot.setProgram(false);
+ }
+ // START KGU#770 2021-01-27: Enh. #917
+ } else if (selected instanceof Root && this.canEditSub()) {
+ StringList includeNames = ((Root) selected).includeList;
+ if (root.isInclude() && includeNames.contains(root.getMethodName())) {
+ root.addUndo();
+ includeNames.removeAll(root.getMethodName());
+ if (includeNames.isEmpty()) {
+ JOptionPane.showMessageDialog(getFrame(),
+ Menu.msgCyclicInclusion.getText(),
+ Menu.msgTitleWarning.getText(),
+ JOptionPane.WARNING_MESSAGE);
+ return;
+ }
+ }
+ String inclName = null;
+ if (includeNames.count() > 1) {
+ inclName = (String) JOptionPane.showInputDialog(getFrame(),
+ Menu.msgChooseIncludable.getText(),
+ Menu.msgTitleQuestion.getText(),
+ JOptionPane.QUESTION_MESSAGE, null, // Use default icon
+ includeNames.toArray(), // Array of choices
+ includeNames.get(0)); // Initial choice
+ if (inclName == null) {
+ return;
+ }
+ } else {
+ inclName = includeNames.get(0);
+ }
+ // Try to find the Includable in Arranger
+ Vector candidates = Arranger.getInstance()
+ .findIncludesByName(inclName, (Root) selected, false);
+ // Prevent cyclic inclusion
+ candidates.remove(root);
+ // Open a choice list if the group approach alone wasn't successful
+ referredRoot = chooseReferredRoot(candidates, Menu.msgChooseIncludable.getText());
+ // Create new subroutine root if we haven't been able to select an existing one
+ if (referredRoot == null) {
+ if (JOptionPane.showConfirmDialog(getFrame(),
+ Menu.msgCreateIncludable.getText().replace("%", inclName),
+ Menu.msgTitleQuestion.getText(),
+ JOptionPane.OK_CANCEL_OPTION) != JOptionPane.OK_OPTION) {
+ return;
+ }
+ referredRoot = new Root();
+ referredRoot.setText(inclName);
+ referredRoot.setInclude();
+ }
+ }
+ myGroups = Arranger.getInstance().getGroupsFromRoot(root, true);
+ if (referredRoot != null) {
+ referredRoot.setChanged(false);
+ // Now care for the group context. If the parent diagram hadn't been in Arranger then put it there now
+ if (myGroups.isEmpty() && Arranger.getInstance().getGroupsFromRoot(root, false).isEmpty()) {
+ // If the diagram is a program then create an exclusive group named after the main diagram
+ if (root.isProgram()) {
+ targetGroupName = root.getMethodName(true);
+ Arranger.getInstance().addToPool(root, this.getFrame(), targetGroupName);
+ myGroups = Arranger.getInstance().getGroupsFromRoot(root, true);
+ } else {
+ Arranger.getInstance().addToPool(root, this.getFrame());
+ }
+ } else if (Arranger.getInstance().getGroupsFromRoot(root, false).size() == myGroups.size()) {
+ // Parent diagram is arranged but not member of the default group - then its children shouldn't be either
+ targetGroupName = myGroups.iterator().next().getName();
+ }
+ // END KGU#770 2021-01-27
+ // START KGU#744 2019-10-05: Issue #758 - In case the connected subForm already handles the subroutine don't force to save it
+ //if (subForm == null || subForm.diagram == null || !subForm.diagram.saveNSD(true) || !subForm.setRoot(subroutine)) {
+ if (subForm == null
+ || subForm.diagram == null
+ || subForm.diagram.getRoot() != referredRoot
+ && (!subForm.diagram.saveNSD(true) || !subForm.setRoot(referredRoot))) {
+ // END KGU#744 2019-10-05
+ subForm = new Mainform(false);
+ subForm.addWindowListener(new WindowListener() {
+ @Override
+ public void windowOpened(WindowEvent e) {
+ }
+
+ @Override
+ public void windowClosing(WindowEvent e) {
+ // A dead Mainform causes enormous trouble if we try to work with it.
+ if (subForm == e.getSource()) {
+ subForm = null;
+ }
+ }
+
+ @Override
+ public void windowClosed(WindowEvent e) {
+ ((Mainform) (e.getSource())).removeWindowListener(this);
+ // START KGU#744 2019-10-05: Bugfix #758 We are not always informed on windowClosing
+ if (subForm == e.getSource()) {
+ subForm = null;
+ }
+ // END KGU#744 2019-10-05
+ }
+
+ @Override
+ public void windowIconified(WindowEvent e) {
+ }
+
+ @Override
+ public void windowDeiconified(WindowEvent e) {
+ }
+
+ @Override
+ public void windowActivated(WindowEvent e) {
+ }
+
+ @Override
+ public void windowDeactivated(WindowEvent e) {
+ }
+
+ });
+ }
+ if (subForm.diagram.getRoot() != referredRoot) {
+ subForm.setRoot(referredRoot);
+ }
+ // If it is a new root then add it to Arranger
+ if (targetGroupName != null) {
+ Arranger.getInstance().addToPool(referredRoot, subForm, targetGroupName);
+ }
+ // START KGU#744 2019-10-05: Bugfix #758 - The subroutine has always to be added to Arranger
+ else {
+ Arranger.getInstance().addToPool(referredRoot, subForm);
+ }
+ Arranger.getInstance().setVisible(true);
+ // END KGU#744 2019-10-05
+ if (!subForm.isVisible()) {
+ subForm.setVisible(true);
+ }
+ // START KGU#744 2019-10-05: Bugfix #758
+ int state = subForm.getExtendedState();
+ if ((state & Frame.ICONIFIED) != 0) {
+ subForm.setExtendedState(state & ~Frame.ICONIFIED);
+ }
+ // END KGU#744 2019-10-05
+ Point loc = NSDControl.getFrame().getLocation();
+ Point locSub = subForm.getLocation();
+ if (loc.equals(locSub)) {
+ subForm.setLocation(loc.x + 20, loc.y + 20);
+ }
+ // START KGU#770 2021-01-27: Enh. #689, #917
+ // We must of course give the focus to the opened editor
+ subForm.requestFocus();
+ // END KGU#770 2021-01-27
+ }
+ }
+
+ /**
+ * Disambiguates the referenced {@link Root} among the {@code candidates}
+ * with user assistance if necessary.
+ *
+ * @param candidates - the vector of candidate {@link Root}s
+ * @param rootType - localised name of the rout type
+ * @return either the selected {@link Root} or {@code null}
+ */
+ private Root chooseReferredRoot(Vector candidates, String rootType) {
+ Root referredRoot = null;
+ // If the finding is unambiguous, get it
+ if (candidates.size() == 1) {
+ referredRoot = candidates.get(0);
+ } else if (candidates.size() > 1) {
+ // Open a choice list with full paths and let the user decide
+ String[] choices = new String[candidates.size()];
+ int i = 0;
+ for (Root cand : candidates) {
+ choices[i++] = cand.getSignatureString(true, false);
+ }
+ String input = (String) JOptionPane.showInputDialog(getFrame(),
+ Menu.msgChooseSubroutine.getText().replace("%", rootType),
+ Menu.msgTitleQuestion.getText(),
+ JOptionPane.QUESTION_MESSAGE, null, // Use default icon
+ choices, // Array of choices
+ choices[0]); // Initial choice
+ if (input != null && !input.trim().isEmpty()) {
+ for (i = 0; i < choices.length && referredRoot != null; i++) {
+ if (input.equals(choices[i])) {
+ referredRoot = candidates.get(i);
+ }
+ }
+ }
+ }
+ return referredRoot;
+ }
+ // END KGU#667 2019-02-26
+
+ /*========================================
+ * transmute method(s)
+ *========================================*/
+ // START KGU#199 2016-07-06: Enh. #188 - perform the possible conversion
+ /**
+ * Converts the selected element(s) into some substitute according to the
+ * specified transmutation rules (undoable).
+ *
+ * @see #canTransmute()
+ */
+ public void transmuteNSD() {
+ Subqueue parent = (Subqueue) selected.parent;
+ if (selected instanceof Instruction) {
+ //root.addUndo();
+ try {
+ addUndoNSD(false);
+ } catch (CancelledException e) {
+ return;
+ }
+ if (selected.getUnbrokenText().count() > 1) {
+ transmuteToSequence(parent);
+ } else {
+ transmuteToSpecialInstr(parent);
+ }
+ } else if (selected instanceof IElementSequence) {
+ root.addUndo();
+ transmuteToCompoundInstr(parent);
+ } // START KGU#229 2016-08-01: Enh. #213 - FOR loop decomposition
+ else if (selected instanceof For && ((For) selected).style == For.ForLoopStyle.COUNTER) {
+ root.addUndo();
+ decomposeForLoop(parent);
+ } // END KGU#229 2016-08-01
+ // START KGU#267 2016-10-03: Enh. #257 - CASE decomposition
+ else if (selected instanceof Case) {
+ root.addUndo();
+ decomposeCase(parent);
+ }
+ // END KGU#267 2016-10-03
+ // START KGU#357 2017-03-10: Enh. #367: swapping of sides
+ else if (selected instanceof Alternative && ((Alternative) selected).qFalse.getSize() > 0) {
+ root.addUndo();
+ swapBranches((Alternative) selected);
+ }
+ // END KGU#357 2017-03-10
+ this.doButtons();
+ redraw();
+ analyse();
+ // START KGU#444 2017-10-23: Issue #417 - reduce scrolling complexity
+ adaptScrollUnits();
+ // END KGU#444 2017-10-23
+ // START KGU#705 2019-09-23: Enh. #738
+ updateCodePreview();
+ // END KGU#705 2019-09-23
+ }
+
+ // START KGU#357 2017-03-10: Enh. #367
+ /**
+ * Helper method of {@link #transmuteNSD()}
+ */
+ private void swapBranches(Alternative _alt) {
+ String condition = _alt.getText().getText();
+ String negCondition = Element.negateCondition(condition);
+ _alt.setText(negCondition);
+ Subqueue temp = _alt.qFalse;
+ _alt.qFalse = _alt.qTrue;
+ _alt.qTrue = temp;
+ // The width of the condition is likely to have changed
+ _alt.resetDrawingInfoUp(); // KGU#590 2018-10-01: Corrected Down -> Up
+ redraw();
+ analyse();
+ }
+ // END KGU#357 2017-03-10
+
+ /**
+ * Helper method of {@link #transmuteNSD()}
+ */
+ private void transmuteToSequence(Subqueue parent) {
+ // Comment will be split as follows:
+ // If the number of strings of the comment equals the number of instruction
+ // lines then the strings are assigned one by one to he resulting instructions
+ // (thereby splitting multi-line strings into StringLists),
+ // otherwise the first instruction will get all comment.
+ int index = parent.getIndexOf(selected);
+ StringList comment = selected.getComment();
+ StringList text = selected.getBrokenText();
+ int count = text.count();
+ boolean distributeComment = (count == comment.count());
+ for (int i = 0; i < count; i++) {
+ Instruction instr = (Instruction) selected.copy();
+ instr.setText(StringList.explode(text.get(i), "\n"));
+ if (distributeComment) {
+ instr.setComment(StringList.explode(comment.get(i), "\n"));
+ } else if (i != 0) {
+ instr.comment.clear();
+ }
+ parent.insertElementAt(instr, index + i + 1);
+ }
+ parent.removeElement(index);
+ selected = new SelectedSequence(parent, index, index + count - 1);
+ selectedDown = null;
+ selected.setSelected(true);
+ }
+
+ /**
+ * Helper method of {@link #transmuteNSD()}
+ */
+ private void transmuteToSpecialInstr(Subqueue parent) {
+ Instruction instr = (Instruction) selected;
+ Element elem = instr;
+ if (instr instanceof Call || instr instanceof Jump) {
+ elem = new Instruction(instr);
+ } else if (instr.isProcedureCall(false) || instr.isFunctionCall(false)) {
+ elem = new Call(instr);
+ } else if (instr.isJump()) {
+ elem = new Jump(instr);
+ }
+ int index = parent.getIndexOf(instr);
+ parent.insertElementAt(elem, index + 1);
+ parent.removeElement(index);
+ this.selected = elem;
+ this.selectedDown = this.selected;
+ }
+
+ /**
+ * Helper subroutine of {@link #transmuteNSD()}
+ */
+ private void transmuteToCompoundInstr(Subqueue parent) {
+ // Comments will be composed as follows:
+ // If none of the selected elements had a non-empty comment then the resulting
+ // comment will be empty. Otherwise the resulting comment will contain as many
+ // strings as elements. Each of them will be the respective element comment,
+ // possibly containing several newlines if it was a multi-line comment.
+ Instruction instr = (Instruction) ((IElementSequence) selected).getElement(0);
+ StringList composedComment = StringList.getNew(instr.getComment().getText().trim());
+ int nElements = ((IElementSequence) selected).getSize();
+ int index = parent.getIndexOf(instr);
+ boolean brkpt = instr.isBreakpoint();
+ // START KGU#213 2016-08-01: Enh. #215
+ int brkCount = instr.getBreakTriggerCount();
+ // END KGU#213 2016-08-01
+ // Find out whether all elements are of the same kind
+ boolean sameKind = true;
+ for (int i = 1; sameKind && i < nElements; i++) {
+ if (((IElementSequence) selected).getElement(i).getClass() != instr.getClass()) {
+ sameKind = false;
+ }
+ }
+ // If so...
+ if (sameKind) {
+ // ... then clone the first element of the sequence as same class
+ instr = (Instruction) instr.copy();
+ } else {
+ // ... else clone the first element of the sequence as simple instruction
+ instr = new Instruction(instr);
+ }
+ ((IElementSequence) selected).removeElement(0);
+ nElements--;
+ // And now append the contents of the remaining elements, removing them from the selection
+ for (int i = 0; i < nElements; i++) {
+ Element ele = ((IElementSequence) selected).getElement(0);
+ instr.getText().add(ele.getText());
+ composedComment.add(ele.getComment().getText().trim());
+ if (ele.isBreakpoint()) {
+ brkpt = true;
+ }
+ // START KGU#213 2016-08-01: Enh. #215
+ // Use the earliest breakTriggerCount
+ int brkCnt = ele.getBreakTriggerCount();
+ if (brkCnt > 0 && brkCnt < brkCount) {
+ brkCount = brkCnt;
+ }
+ // END KGU#213 2016-08-01
+ ((IElementSequence) selected).removeElement(0);
+ }
+ // If there was no substantial comment then we must not create one, otherwise
+ // the cmment is to consist of as many strings as instruction lines - where
+ // each of them may contain newlines for reversibility
+ if (!composedComment.concatenate().trim().isEmpty()) {
+ instr.setComment(composedComment);
+ } else {
+ instr.getComment().clear();
+ }
+ // If any of the implicated instructions had a breakpoint then set it here, too
+ if (brkpt && !instr.isBreakpoint()) {
+ instr.toggleBreakpoint();
+ }
+ // START KGU#213 2016-08-01: Enh. #215
+ // Use the earliest breakTriggerCount
+ instr.setBreakTriggerCount(brkCount);
+ // END KGU#213 2016-08-01
+
+ instr.setSelected(true);
+ parent.insertElementAt(instr, index);
+ this.selected = instr;
+ this.selectedDown = this.selected;
+ }
+ // END KGU#199 2016-07-06
+
+ // START KGU#229 2016-08-01: Enh. #213 - FOR loop decomposition
+ /**
+ * Helper method of {@link #transmuteNSD()}
+ */
+ private void decomposeForLoop(Subqueue parent) {
+ // Comment will be tranferred to the While loop.
+ For forLoop = (For) selected;
+ String asgmtOpr = " <- ";
+ if (forLoop.getText().get(0).contains(":=")) {
+ asgmtOpr = " := ";
+ }
+ int step = forLoop.getStepConst();
+ Element[] elements = new Element[3];
+ elements[0] = new Instruction(forLoop.getCounterVar() + asgmtOpr + forLoop.getStartValue());
+ // START KGU#229 2016-09-09: Take care of the configured prefix and postfix
+ //While whileLoop = new While(forLoop.getCounterVar() + (step < 0 ? " >= " : " <= ") + forLoop.getEndValue());
+ String prefix = "", postfix = "";
+ if (!CodeParser.getKeyword("preWhile").trim().isEmpty()) {
+ prefix = CodeParser.getKeyword("preWhile");
+ if (!prefix.endsWith(" ")) {
+ prefix += " ";
+ }
+ }
+ if (!CodeParser.getKeyword("postWhile").trim().isEmpty()) {
+ postfix = CodeParser.getKeyword("postWhile");
+ if (!postfix.startsWith(" ")) {
+ postfix = " " + postfix;
+ }
+ }
+ While whileLoop = new While(prefix + forLoop.getCounterVar() + (step < 0 ? " >= " : " <= ") + forLoop.getEndValue() + postfix);
+ // END KGU#229 2016-09-09
+ elements[1] = whileLoop;
+ elements[2] = new Instruction(forLoop.getCounterVar() + asgmtOpr + forLoop.getCounterVar() + (step < 0 ? " - " : " + ") + Math.abs(forLoop.getStepConst()));
+
+ whileLoop.setComment(forLoop.getComment());
+ if (forLoop.isBreakpoint()) {
+ whileLoop.toggleBreakpoint();
+ }
+ whileLoop.setBreakTriggerCount(forLoop.getBreakTriggerCount());
+ whileLoop.q = forLoop.getBody();
+ whileLoop.q.parent = whileLoop;
+ whileLoop.q.addElement(elements[2]);
+ whileLoop.setCollapsed(forLoop.isCollapsed(true));
+ for (int i = 0; i < elements.length; i++) {
+ Element elem = elements[i];
+ elem.setColor(forLoop.getColor());
+ elem.deeplyCovered = forLoop.deeplyCovered;
+ elem.simplyCovered = forLoop.simplyCovered;
+ }
+ int index = parent.getIndexOf(forLoop);
+ for (int i = 0; i < 2; i++) {
+ parent.insertElementAt(elements[1 - i], index + 1);
+ }
+ parent.removeElement(index);
+ this.selected = new SelectedSequence(parent, index, index + 1);
+ // START KGU#229 2016-09-11: selection must be made visible!
+ this.selected.setSelected(true);
+ // END KGU#229 2016-09-11
+ this.selectedDown = this.selected;
+ }
+ // END KGU#229 2016-08-01
+
+ // START KGU#267 2016-10-03: Enh. #257 - CASE structure decomposition
+ /**
+ * Helper method of {@link #transmuteNSD()}
+ */
+ private void decomposeCase(Subqueue parent) {
+ // Comment will be transferred to the first replacing element
+ // (discriminator variable assignment or outermost Alternative).
+ Case caseElem = (Case) selected;
+ // List of replacing nested alternatives
+ List alternatives = new LinkedList();
+ // Possibly preceding assignment of the selection expression value
+ Instruction asgnmt = null;
+ // tokenized selection expression
+ StringList selTokens = Element.splitLexically(caseElem.getText().get(0), true);
+ // Eliminate parser preference keywords
+ String[] redundantKeywords = {CodeParser.getKeyword("preCase"), CodeParser.getKeyword("postCase")};
+ for (String keyword : redundantKeywords) {
+ if (!keyword.trim().isEmpty()) {
+ StringList tokenizedKey = Element.splitLexically(keyword, false);
+ int pos = -1;
+ while ((pos = selTokens.indexOf(tokenizedKey, pos + 1, !CodeParser.ignoreCase)) >= 0) {
+ for (int i = 0; i < tokenizedKey.count(); i++) {
+ selTokens.delete(pos);
+ }
+ }
+ }
+ }
+ String discriminator = selTokens.concatenate().trim();
+ // If the discriminating expression isn't just a variable then assign its value to an
+ // artificial variable first and use this as discriminator further on.
+ if (!Function.testIdentifier(discriminator, false, "")) {
+ String discrVar = "discr" + caseElem.hashCode();
+ asgnmt = new Instruction(discrVar + " <- " + discriminator);
+ discriminator = discrVar;
+ asgnmt.setColor(caseElem.getColor());
+ }
+
+ // Take care of the configured prefix and postfix
+ String prefix = "", postfix = "";
+ if (!CodeParser.getKeyword("preAlt").trim().isEmpty()) {
+ prefix = CodeParser.getKeyword("preAlt");
+ if (!prefix.endsWith(" ")) {
+ prefix += " ";
+ }
+ }
+ if (!CodeParser.getKeyword("postAlt").trim().isEmpty()) {
+ postfix = CodeParser.getKeyword("postAlt");
+ if (!postfix.startsWith(" ")) {
+ postfix = " " + postfix;
+ }
+ }
+
+ int nAlts = 0; // number of alternatives created so far
+ for (int lineNo = 1; lineNo < caseElem.getText().count(); lineNo++) {
+ String line = caseElem.getText().get(lineNo);
+ // Specific handling of the last branch
+ if (lineNo == caseElem.getText().count() - 1) {
+ // In case it's a "%", nothing is to be added, otherwise the last
+ // branch is to be the else path of the innermost alternative
+ if (!line.equals("%")) {
+ // This should not happen before the first alternative has been created!
+ alternatives.get(nAlts - 1).qFalse = caseElem.qs.get(lineNo - 1);
+ alternatives.get(nAlts - 1).qFalse.parent = alternatives.get(nAlts - 1);
+ }
+ } else {
+ String[] selectors = line.split(",");
+ String cond = "";
+ for (String selConst : selectors) {
+ cond += " || (" + discriminator + " = " + selConst.trim() + ")";
+ }
+ // START KGU#288 2016-11-06: Issue #279
+ //cond = cond.substring(4).replace("||", CodeParser.getKeywordOrDefault("oprOr", "or"));
+ cond = cond.substring(4).replace("||", CodeParser.getKeywordOrDefault("oprOr", "or"));
+ // END KGU#288 2016-11-06
+ Alternative newAlt = new Alternative(prefix + cond + postfix);
+ newAlt.qTrue = caseElem.qs.get(lineNo - 1);
+ newAlt.qTrue.parent = newAlt;
+ alternatives.add(newAlt);
+ if (nAlts > 0) {
+ alternatives.get(nAlts - 1).qFalse.addElement(newAlt);
+ }
+ nAlts++;
+ }
+ }
+
+ Element firstSubstitutor = (asgnmt != null) ? asgnmt : alternatives.get(0);
+ firstSubstitutor.setComment(caseElem.getComment());
+ if (caseElem.isBreakpoint()) {
+ firstSubstitutor.toggleBreakpoint();
+ }
+ firstSubstitutor.setBreakTriggerCount(caseElem.getBreakTriggerCount());
+ for (Alternative alt : alternatives) {
+ alt.setColor(caseElem.getColor());
+ alt.deeplyCovered = caseElem.deeplyCovered;
+ alt.simplyCovered = caseElem.simplyCovered;
+ }
+ alternatives.get(0).setCollapsed(caseElem.isCollapsed(true));
+
+ int index = parent.getIndexOf(caseElem);
+ parent.removeElement(index);
+ parent.insertElementAt(alternatives.get(0), index);
+ if (asgnmt != null) {
+ parent.insertElementAt(asgnmt, index);
+ this.selected = new SelectedSequence(parent, index, index + 1);
+ } else {
+ this.selected = parent.getElement(index);
+ }
+ this.selected.setSelected(true);
+ this.selectedDown = this.selected;
+ }
+ // END KGU#267 2016-10-03
+
+ // START KGU#282 2016-10-16: Issue #272 (draft)
+ /*=======================================*
+ * Turtleizer precision methods
+ *=======================================*/
+ /**
+ * Replaces all Turtleizer {@code fd} and {@code bk} procedure calls by the
+ * more precise {@code forward} and {@code backward} instructions
+ * ({@code precisionUp} = true) or the other way round ({@code precisionUp}
+ * = false) in the selected elements
+ *
+ * @param precisionUp - whether to convert to the more precise or to the
+ * less precise versions
+ */
+ public void replaceTurtleizerAPI(boolean precisionUp) {
+ final class TurtleizerSwitcher implements IElementVisitor {
+
+ private int from;
+ // START #272 2016-10-17 (KGU): detect changes (to get rid of void undo entry
+ private boolean act = false;
+ private int nChanges = 0;
+ // END #272 2016-10-17
+ private final String[][] functionPairs = {{"fd", "forward"}, {"bk", "backward"}};
+
+ public TurtleizerSwitcher(boolean upgrade) {
+ this.from = upgrade ? 0 : 1;
+ }
+
+ public boolean visitPreOrder(Element _ele) {
+ if (_ele.getClass().getSimpleName().equals("Instruction")) {
+ for (int i = 0; i < _ele.getText().count(); i++) {
+ String line = _ele.getText().get(i);
+ if (Instruction.isTurtleizerMove(line)) {
+ Function fct = new Function(line);
+ for (int j = 0; j < functionPairs.length; j++) {
+ String oldName = functionPairs[j][from];
+ if (fct.getName().equals(oldName)) {
+ // START #272 2016-10-17
+ //_ele.getText().set(i, functionPairs[j][1 - from] + line.trim().substring(oldName.length()));
+ if (this.act) {
+ _ele.getText().set(i, functionPairs[j][1 - from] + line.trim().substring(oldName.length()));
+ }
+ nChanges++;
+ // END #272 2016-10-17
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ public boolean visitPostOrder(Element _ele) {
+ return true;
+ }
+
+ // START #272 2016-10-17 (KGU)
+ public void activate() {
+ this.nChanges = 0;
+ this.act = true;
+ }
+
+ public int getNumberOfReplacements() {
+ return nChanges;
+ }
+ // END #272 2016-10-17
+
+ }
+
+ // START #272 2016-10-17 (KGU): Inform the user and get rid of void undo entry
+ //root.addUndo();
+ //selected.traverse(new TurtleizerSwitcher(precisionUp));
+ // First mere count run
+ TurtleizerSwitcher switcher = new TurtleizerSwitcher(precisionUp);
+ selected.traverse(switcher);
+ int nReplaced = switcher.getNumberOfReplacements();
+ if (nReplaced > 0) {
+ // There will be substitutions, so get dangerous.
+ //root.addUndo();
+ try {
+ addUndoNSD(false);
+ } catch (CancelledException e) {
+ return;
+ }
+ switcher.activate();
+ selected.traverse(switcher);
+ }
+ JOptionPane.showMessageDialog(this.getFrame(),
+ Menu.msgReplacementsDone.getText().replace("%", Integer.toString(nReplaced)));
+ // END #272 2016-10-17
+ // START KGU#705 2019-09-23: Enh. #738
+ updateCodePreview();
+ // END KGU#705 2019-09-23
+ }
+ // END KGU#282 2016-10-16
+
+ // START KGU#602 2018-10-26: Enh. #419
+ /**
+ * Adjusts line breaking for the selected element(s). Requests the details
+ * interactively from the user.
+ */
+ public void rebreakLines() {
+ if (this.selected != null) {
+ // The current maximum line lengths of the selected element(s)
+ Element selectedEls = this.selected;
+ int flatMax = selectedEls.getMaxLineLength(false);
+ int deepMax = selectedEls.getMaxLineLength(true);
+ int lastLineLimit = this.lastWordWrapLimit <= 0 ? deepMax : this.lastWordWrapLimit;
+ JPanel pnl = new JPanel();
+ JLabel lblMaxLenSel = new JLabel(Menu.msgMaxLineLengthSelected.getText().
+ replace("%", Integer.toString(flatMax)));
+ JLabel lblMaxLenSub = new JLabel(Menu.msgMaxLineLengthSubstructure.getText().
+ replace("%", Integer.toString(deepMax)));
+ JLabel lblNewLen = new JLabel(Menu.lblNewMaxLineLength.getText());
+ JSpinner spnNewLen = new JSpinner();
+ SpinnerModel spnModelLen = new SpinnerNumberModel(0, 0, 255, 5);
+ spnNewLen.setModel(spnModelLen);
+ spnNewLen.setValue(lastLineLimit);
+ JCheckBox cbRecursive = new JCheckBox(Menu.lblInvolveSubtree.getText());
+ JCheckBox cbPreserve = new JCheckBox(Menu.lblPreserveContinuators.getText());
+ cbRecursive.setSelected(!(selectedEls instanceof Instruction));
+ cbPreserve.setSelected(lastLineLimit < (cbRecursive.isSelected() ? deepMax : flatMax));
+
+ GridBagConstraints gbcLimits = new GridBagConstraints();
+ gbcLimits.insets = new Insets(0, 5, 5, 5);
+ gbcLimits.weightx = 1.0;
+ gbcLimits.anchor = GridBagConstraints.LINE_START;
+
+ pnl.setLayout(new GridBagLayout());
+
+ gbcLimits.gridx = 0;
+ gbcLimits.gridy = 0;
+ gbcLimits.gridwidth = GridBagConstraints.REMAINDER;
+ pnl.add(lblMaxLenSel, gbcLimits);
+
+ gbcLimits.gridy++;
+ pnl.add(lblMaxLenSub, gbcLimits);
+
+ gbcLimits.gridy++;
+ gbcLimits.gridwidth = 1;
+ pnl.add(lblNewLen, gbcLimits);
+
+ gbcLimits.gridx++;
+ gbcLimits.gridwidth = GridBagConstraints.REMAINDER;
+ gbcLimits.fill = GridBagConstraints.HORIZONTAL;
+ pnl.add(spnNewLen, gbcLimits);
+
+ gbcLimits.gridx = 0;
+ gbcLimits.gridy++;
+ gbcLimits.fill = GridBagConstraints.NONE;
+ pnl.add(cbRecursive, gbcLimits);
+ gbcLimits.gridy++;
+ pnl.add(cbPreserve, gbcLimits);
+
+ ChangeListener changeListener = new ChangeListener() {
+
+ private final JSpinner spnLen = spnNewLen;
+ private final JCheckBox chkRec = cbRecursive, chkPres = cbPreserve;
+ private final int flatLen = flatMax, deepLen = deepMax;
+
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ int limit = (int) spnLen.getValue();
+ if (chkRec.isSelected() && limit > deepLen || !chkRec.isSelected() && limit > flatLen) {
+ chkPres.setSelected(false);
+ }
+ }
+
+ };
+
+ // Without this hack, directly entering a number in the spinner's text field wouldn't fire the ChangeEvent
+ DefaultFormatter formatter = (DefaultFormatter) ((JSpinner.DefaultEditor) spnNewLen.getEditor()).getTextField().getFormatter();
+ formatter.setCommitsOnValidEdit(true);
+
+ spnNewLen.addChangeListener(changeListener);
+ cbRecursive.addChangeListener(changeListener);
+
+ int answer = JOptionPane.showConfirmDialog(
+ this.getFrame(), pnl,
+ Menu.ttlBreakTextLines.getText(),
+ JOptionPane.OK_CANCEL_OPTION);
+
+ if (answer == JOptionPane.OK_OPTION) {
+ root.addUndo();
+ boolean recursive = cbRecursive.isSelected();
+ boolean preserve = cbPreserve.isSelected();
+ this.lastWordWrapLimit = (short) (int) spnNewLen.getValue();
+ boolean changed = false;
+ if (selectedEls instanceof Root) {
+ changed = selectedEls.breakTextLines(this.lastWordWrapLimit, !preserve);
+ if (recursive && ((Root) selectedEls).breakElementTextLines(this.lastWordWrapLimit, !preserve)) {
+ changed = true;
+ }
+ } else if (!recursive && !(selectedEls instanceof IElementSequence)) {
+ changed = selectedEls.breakTextLines(this.lastWordWrapLimit, !preserve);
+ } else {
+ if (!(selectedEls instanceof IElementSequence)) {
+ selectedEls = new SelectedSequence(selectedEls, selectedEls);
+ }
+ IElementSequence.Iterator iter = ((IElementSequence) selectedEls).iterator(recursive);
+ while (iter.hasNext()) {
+ if (iter.next().breakTextLines(this.lastWordWrapLimit, !preserve)) {
+ changed = true;
+ }
+ }
+ }
+ if (!changed) {
+ root.undo(false);
+ }
+ // START KGU#940 2021-02-24: Bugfix #419 - Drawing update had been missing
+ redraw();
+ // END KGU#940 2021-02-24
+ // START KGU#705 2019-09-23: Enh. #738
+ updateCodePreview();
+ // END KGU#705 2019-09-23
+ }
+ }
+ }
+ // END KGU#602 2016-10-26
+
+ // START KGU#43 2015-10-12
+ /*========================================
+ * breakpoint methods
+ *========================================*/
+ /**
+ * Enables or disables the breakpoint on the selected element(s) depending
+ * on the previous state. Does not affect a possibly configured break
+ * trigger.
+ *
+ * @see Element#toggleBreakpoint()
+ * @see #editBreakTrigger()
+ * @see #clearBreakpoints()
+ */
+ public void toggleBreakpoint() {
+ Element ele = getSelected();
+ if (ele != null) {
+ ele.toggleBreakpoint();
+ redraw();
+ }
+ }
+
+ // START KGU#213 2016-08-02: Enh. #215
+ /**
+ * Opens a dialog that allows to set the break trigger value (i.e. the
+ * execution count value that triggers a breakpoint if enabled.
+ *
+ * @see #toggleBreakpoint()
+ * @see #clearBreakpoints()
+ */
+ public void editBreakTrigger() {
+ // TODO Auto-generated method stub
+ Element ele = getSelected();
+ if (ele != null) {
+ int trigger = ele.getBreakTriggerCount();
+ // FIXME: Replace this quick-and-dirty approach by something more functional
+ String str = JOptionPane.showInputDialog(this.getFrame(),
+ Menu.msgBreakTriggerPrompt.getText(),
+ Integer.toString(trigger));
+ if (str != null) {
+ // START KGU#252 2016-09-21: Issue 248 - Linux (Java 1.7) workaround
+ boolean isDone = false;
+ // END KGU#252 2016-09-21
+ try {
+ // START KGU#252 2016-09-21: Issue 248 - Linux (Java 1.7) workaround
+ //ele.setBreakTriggerCount(Integer.parseUnsignedInt(str));
+ isDone = ele.setBreakTriggerCount(Integer.parseInt(str));
+ // END KGU#252 2016-09-21
+ // We assume the intention to activate the breakpoint with the configuration
+ if (!ele.isBreakpoint()) {
+ // FIXME This might not work properly with recursive algorithms (i.e. on stack unwinding)
+ ele.toggleBreakpoint();
+ }
+ redraw();
+ } catch (NumberFormatException ex) {
+ // START KGU#252 2016-09-21: Issue 248 - Linux (Java 1.7) workaround
+ //JOptionPane.showMessageDialog(this,
+ // Menu.msgBreakTriggerIgnored.getText(),
+ // Menu.msgTitleWrongInput.getText(),
+ // JOptionPane.ERROR_MESSAGE);
+ // END KGU#252 2016-09-21
+ }
+ // START KGU#252 2016-09-21: Issue 248 - Linux (Java 1.7) workaround
+ if (!isDone) {
+ JOptionPane.showMessageDialog(this.getFrame(),
+ Menu.msgBreakTriggerIgnored.getText(),
+ Menu.msgTitleWrongInput.getText(),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ // END KGU#252 2016-09-21
+ }
+ }
+ }
+ // END KGU#213 2016-08-02
+
+ /**
+ * Unsets all enabled breakpoints throughout the current diagram.
+ *
+ * @see #toggleBreakpoint()
+ * @see #editBreakTrigger()
+ */
+ public void clearBreakpoints() {
+ // FIXME (Issue #954): All clones in the Executor call stack must also be cleared!
+ root.clearBreakpoints();
+ redraw();
+ }
+
+ // START KGU#952 2021-03-03: Issue #954
+ /**
+ * Disables (or enables) the supervision of Breakpoints by {@link Executor}
+ *
+ * @param disable - if {@code true} then all breakpoints in all diagrams
+ * will be disabled, otherwise they will be activated again.
+ */
+ public void disableBreakpoints(boolean disable) {
+ Element.E_BREAKPOINTS_ENABLED = !disable;
+ if (disable) {
+ Element.E_BREAKPOINTCOLOR = Element.E_COMMENTCOLOR;
+ } else {
+ Element.E_BREAKPOINTCOLOR = Color.RED;
+ }
+ redraw();
+ doButtons();
+ }
+
+ /**
+ * Clears all execution flags and counts throughout the entire diagram held
+ * as {@link #root}.
+ */
+ public void clearExecutionStatus() {
+ root.clearExecutionStatus();
+ redraw();
+ }
+ // END KGU#43 2015-10-12
+
+ /*========================================
+ * print method
+ *========================================*/
+ /**
+ * Opens the print preview for the current {@link #root} from which it can
+ * be printed.
+ *
+ * @see #exportPDF()
+ */
+ public void printNSD() {
+ /*
+ // printing support
+ //--- Create a printerJob object
+ PrinterJob printJob = PrinterJob.getPrinterJob ();
+ //--- Set the printable class to this one since we
+ //--- are implementing the Printable interface
+ printJob.setPrintable (this);
+ //--- Show a print dialog to the user. If the user
+ //--- clicks the print button, then print, otherwise
+ //--- cancel the print job
+ if (printJob.printDialog())
+ {
+ try
+ {
+ printJob.print();
+ }
+ catch (Exception PrintException)
+ {
+ PrintException.printStackTrace();
+ }
+ }
+ */
+ //PrintPreview.print(this);
+ /*
+ PrintPreview pp = new PrintPreview(this,"Print Previwe");
+ Point p = getLocationOnScreen();
+ pp.setLocation(Math.round(p.x+(getVisibleRect().width-pp.getWidth())/2), Math.round(p.y)+(getVisibleRect().height-pp.getHeight())/2);
+ pp.setVisible(true);
+ */
+ // START KGU#170 2018-06-11: Issue #143 - on opening the print preview a comment popup should vanish
+ hideComments();
+ // END KGU#170 2018-06-11
+ PrintPreview pp = new PrintPreview(NSDControl.getFrame(), this);
+ Point p = getLocationOnScreen();
+ pp.setLocation(Math.round(p.x + (getVisibleRect().width - pp.getWidth()) / 2 + this.getVisibleRect().x),
+ Math.round(p.y) + (getVisibleRect().height - pp.getHeight()) / 2 + this.getVisibleRect().y);
+ pp.setVisible(true);
+ }
+
+ // START KGU#2 2015-11-19
+ /*========================================
+ * arrange method
+ *========================================*/
+ /**
+ * Push the current root to the Arranger and pin it there. If Arranger
+ * wasn't visible then it will be (re-)opened.
+ */
+ public void arrangeNSD() // START KGU#626 2018-12-28: Enh. #657
+ {
+ arrangeNSD(null);
+ }
+
+ /**
+ * Push the current root to the Arranger and pin it there. If Arranger
+ * wasn't visible then it will be (re-)opened.
+ *
+ * @param sourceFilename - the base name of a code file the diagram was
+ * imported from if so, null otherwise
+ */
+ public void arrangeNSD(String sourceFilename) // END KGU#626 2018-12-28
+ {
+ //System.out.println("Arranger button pressed!");
+ Arranger arr = Arranger.getInstance();
+ arr.addToPool(root, NSDControl.getFrame(), sourceFilename);
+ arr.setVisible(true);
+ // KGU#280 2016-10-11: Obsolete now
+ //isArrangerOpen = true; // Gives the Executor a hint where to find a subroutine pool
+ }
+ // END KGU#2 2015-11-19
+
+ // START KGU#125 2016-01-06: Possibility to adopt a diagram if it's orphaned
+ public void adoptArrangedOrphanNSD(Root root) {
+ if (isArrangerOpen()) {
+ Arranger arr = Arranger.getInstance();
+ // START KGU#742 2019-10-04: This caused ConcurrentModificationExceptions
+ //arr.addToPool(root, frame);
+ arr.adoptRootIfOrphaned(root, (Mainform) NSDControl.getFrame());
+ //END KGU#741 2019-10-04
+ }
+ }
+ // END KGU#125 2016-01-06
+
+ /*========================================
+ * about method
+ *========================================*/
+ /**
+ * Opens the About window with version info, authors tab, license text,
+ * change log tab, and paths tab.
+ */
+ public void aboutNSD() {
+ About about = new About(NSDControl.getFrame());
+ Point p = getLocationOnScreen();
+ about.setLocation(Math.round(p.x + (getVisibleRect().width - about.getWidth()) / 2 + this.getVisibleRect().x),
+ Math.round(p.y) + (getVisibleRect().height - about.getHeight()) / 2 + this.getVisibleRect().y);
+ // START KGU#300 2016-12-02: Enh. #300 - Add info about newer version if enabled
+ String newVersion = this.getLatestVersionIfNewer();
+ if (newVersion != null) {
+ about.lblVersion.setText(about.lblVersion.getText() + " (" + Menu.msgNewerVersionAvail.getText().replace("%", newVersion) + ")");
+ }
+ // END KGU#300 2016-12-02
+ about.setVisible(true);
+ }
+
+ /*========================================
+ * export picture method
+ *========================================*/
+ /**
+ * Opens a dialog for the configuration of a multi-tile PNG export and a
+ * {@link FileChooser} and performs the respective image export.
+ *
+ * @see #exportPNG()
+ * @see #exportSVG()
+ * @see #exportEMF()
+ * @see #exportPDF()
+ * @see #exportSWF()
+ */
+ public void exportPNGmulti() {
+ // START KGU#183 2016-04-24: Issue #169 - retain old selection
+ Element wasSelected = selected;
+ // END KGU#183 2016-04-24
+
+ // START KGU#41 2015-10-11
+ //root.selectElementByCoord(-1,-1); // Unselect all elements
+ //redraw();
+ unselectAll(true);
+ // END KGU#41 2015-10-11
+
+ JFileChooser dlgSave = new JFileChooser("Export diagram as Multi-PNG ...");
+ // START KGU#287 2017-01-09: Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
+ GUIScaler.rescaleComponents(dlgSave);
+ // END KGU#287 2017-01-09
+ // set directory
+ if (lastExportDir != null) {
+ dlgSave.setCurrentDirectory(lastExportDir);
+ } else if (root.getFile() != null) {
+ dlgSave.setCurrentDirectory(root.getFile());
+ } else {
+ dlgSave.setCurrentDirectory(currentDirectory);
+ }
+ // propose name
+ // START KGU 2015-10-16: There is already a suitable method on root
+ // String nsdName = root.getText().get(0);
+ // nsdName.replace(':', '_');
+ // if(nsdName.indexOf(" (")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf(" ("));}
+ // if(nsdName.indexOf("(")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf("("));}
+ String nsdName = root.proposeFileName();
+ // END KGU 2015-10-16
+ dlgSave.setSelectedFile(new File(nsdName));
+
+ // START KGU#170 2016-04-01: Enh. #110 - select the provided filter
+ //dlgSave.addChoosableFileFilter(new lu.fisch.structorizer.io.PNGFilter());
+ PNGFilter filter = new PNGFilter();
+ dlgSave.addChoosableFileFilter(filter);
+ dlgSave.setFileFilter(filter);
+ hideComments(); // Issue #143: Hide the current comment popup if visible
+ // END KGU#170 2016-04-01
+ int result = dlgSave.showSaveDialog(NSDControl.getFrame());
+ if (result == JFileChooser.APPROVE_OPTION) {
+ lastExportDir = dlgSave.getSelectedFile().getParentFile();
+ String filename = dlgSave.getSelectedFile().getAbsoluteFile().toString();
+ if (!filename.substring(filename.length() - 4, filename.length()).toLowerCase().equals(".png")) {
+ filename += ".png";
+ }
+
+ // START KGU#224 2016-07-28: Issue #209 Test was nonsense since the actual file names will be different
+ //File file = new File(filename);
+ File file = new File(filename.replace(".png", "-00-00.png"));
+ // END KGU#224 2016-07-28
+ boolean writeDown = true;
+
+ if (file.exists()) {
+ int response = JOptionPane.showConfirmDialog(this.getFrame(),
+ Menu.msgOverwriteFiles.getText(),
+ Menu.btnConfirmOverwrite.getText(),
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE);
+ if (response == JOptionPane.NO_OPTION) {
+ writeDown = false;
+ }
+ }
+ if (writeDown == true) {
+ // START KGU#218 2016-07-28: Issue #206 Localization efforts
+ //int cols = Integer.valueOf(JOptionPane.showInputDialog(null, "Into how many columns do you want to split the output?", "1"));
+ //int rows = Integer.valueOf(JOptionPane.showInputDialog(null, "Into how many rows do you want to split the output?", "3"));
+ int cols = Integer.valueOf(JOptionPane.showInputDialog(null, Menu.msgDialogExpCols.getText(), "1"));
+ int rows = Integer.valueOf(JOptionPane.showInputDialog(null, Menu.msgDialogExpRows.getText(), "3"));
+ // END KGU#218 2016-07-28
+
+ BufferedImage image = new BufferedImage(root.width + 1, root.height + 1, BufferedImage.TYPE_4BYTE_ABGR);
+ // START KGU#221 2016-07-28: Issue #208 Need to achieve transparent background
+ //printAll(image.getGraphics());
+ // START KGU#906 2021-01-06: Enh. #905
+ //redraw(image.createGraphics());
+ redraw(image.createGraphics(), DrawingContext.DC_IMAGE_EXPORT);
+ // END KGU#906 2021-01-06
+ // END KGU#221 2016-07-28
+ // source: http://answers.yahoo.com/question/index?qid=20110821001157AAcdXVk
+ // source: http://kalanir.blogspot.com/2010/02/how-to-split-image-into-chunks-java.html
+ try {
+ // 1. Load image file into memory
+ //File file = new File("mario.png"); // mario.png in the same working directory
+ //FileInputStream fis = new FileInputStream(file);
+ //BufferedImage image = ImageIO.read(fis);
+
+ // 2. Decide the number of pieces, and calculate the size of each chunk
+ //int rows = 4;
+ //int cols = 6;
+ int chunks = rows * cols;
+
+ int chunkWidth = image.getWidth() / cols;
+ int chunkHeight = image.getHeight() / rows;
+ // START KGU#223 2016-07-28: Bugfix #209 - identify the integer division defects
+ int widthDefect = image.getWidth() % cols;
+ int heightDefect = image.getHeight() % rows;
+ // END KGU#223 2016-07-28
+
+ // 3. Define an Image array to hold image chunks
+ int count = 0;
+ BufferedImage imgs[] = new BufferedImage[chunks];
+
+ // 4. Fill the Image array with split image parts
+ for (int x = 0; x < rows; x++) {
+ for (int y = 0; y < cols; y++) {
+ //Initialize the image array with image chunks
+ // START KGU#223 2016-07-28: Bugfix #209
+ // We must compensate the rounding defects lest the right and lower borders should be cut
+ //imgs[count] = new BufferedImage(chunkWidth, chunkHeight, image.getType());
+ int tileWidth = chunkWidth + (y < cols - 1 ? 0 : widthDefect);
+ int tileHeight = chunkHeight + (x < rows - 1 ? 0 : heightDefect);
+ imgs[count] = new BufferedImage(tileWidth, tileHeight, image.getType());
+ // END KGU#223 2016-07-28
+
+ // draws the image chunk
+ Graphics2D gr = imgs[count++].createGraphics();
+ // START KGU#223 2016-07-28: Bugfix #209
+ //gr.drawImage(image, 0, 0, chunkWidth, chunkHeight, chunkWidth * y, chunkHeight * x, chunkWidth * y + chunkWidth, chunkHeight * x + chunkHeight, null);
+ // We need to achieve transparent background
+ gr.drawImage(image, 0, 0, tileWidth, tileHeight, chunkWidth * y, chunkHeight * x, chunkWidth * y + tileWidth, chunkHeight * x + tileHeight, null);
+ // END KGU#223 2016-07-28
+ gr.dispose();
+ }
+ }
+
+ // 5. Save mini images into image files
+ // START KGU#224 2016-07-28: Issue #209 - provide the original base name
+ file = new File(filename);
+ filename = file.getAbsolutePath();
+ // END KGU#224 2016-07-28
+ for (int i = 0; i < imgs.length; i++) {
+ // START KGU#224 2016-07-28: Issue #209 - Better file name coding
+ //File f = new File(file.getAbsolutePath().replace(".png", "-"+i+".png"));
+ File f = new File(filename.replace(".png", String.format("-%1$02d-%2$02d.png", i / cols, i % cols)));
+ // END KGU#224 2016-07-28
+ ImageIO.write(imgs[i], "png", f);
+ }
+ } catch (Exception e) {
+ JOptionPane.showMessageDialog(this.getFrame(),
+ Menu.msgErrorImageSave.getText(),
+ Menu.msgTitleError.getText(),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+ // START KGU#183 2016-04-24: Issue #169 - restore old selection
+ selected = wasSelected;
+ if (selected != null) {
+ selected.setSelected(true);
+ }
+ redraw();
+ // END KGU#183 2016-04-24
+ // START KGU#456 2017-11-05: Enh. #452
+ if (root.advanceTutorialState(26, root)) {
+ analyse();
+ }
+ // END KGU#456 2017-11-05
+ }
+
+ /**
+ * Opens a {@link FileChooser} and performs the image export as PNG file.
+ *
+ * @see #exportPNGmulti()
+ * @see #exportSVG()
+ * @see #exportEMF()
+ * @see #exportPDF()
+ * @see #exportSWF()
+ */
+ public void exportPNG() {
+ // START KGU#183 2016-04-24: Issue #169 - retain old selection
+ Element wasSelected = selected;
+ // END KGU#183 2016-04-24
+
+ // START KGU#41 2015-10-11
+ //root.selectElementByCoord(-1,-1); // Unselect all elements
+ //redraw();
+ unselectAll(true);
+ // END KGU#41 2015-10-11
+
+ JFileChooser dlgSave = new JFileChooser("Export diagram as PNG ...");
+ // START KGU#287 2017-01-09: Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
+ GUIScaler.rescaleComponents(dlgSave);
+ // END KGU#287 2017-01-09
+ // set directory
+ if (lastExportDir != null) {
+ dlgSave.setCurrentDirectory(lastExportDir);
+ } else if (root.getFile() != null) {
+ dlgSave.setCurrentDirectory(root.getFile());
+ } else {
+ dlgSave.setCurrentDirectory(currentDirectory);
+ }
+ // propose name
+ // START KGU 2015-10-16: There is already a suitable method
+ // String nsdName = root.getText().get(0);
+ // nsdName.replace(':', '_');
+ // if(nsdName.indexOf(" (")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf(" ("));}
+ // if(nsdName.indexOf("(")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf("("));}
+ String nsdName = root.proposeFileName();
+ // END KGU 2015-10-16
+ dlgSave.setSelectedFile(new File(nsdName));
+
+ // START KGU 2016-04-01: Enh. #110 - select the provided filter
+ //dlgSave.addChoosableFileFilter(new lu.fisch.structorizer.io.PNGFilter());
+ PNGFilter filter = new PNGFilter();
+ dlgSave.addChoosableFileFilter(filter);
+ dlgSave.setFileFilter(filter);
+ hideComments(); // Issue #143: Hide the current comment popup if visible
+ // END KGU 2016-04-01
+ int result = dlgSave.showSaveDialog(NSDControl.getFrame());
+ if (result == JFileChooser.APPROVE_OPTION) {
+ lastExportDir = dlgSave.getSelectedFile().getParentFile();
+ String filename = dlgSave.getSelectedFile().getAbsoluteFile().toString();
+ if (!filename.substring(filename.length() - 4, filename.length()).toLowerCase().equals(".png")) {
+ filename += ".png";
+ }
+
+ File file = new File(filename);
+ if (checkOverwrite(file, false) == 0) {
+ BufferedImage bi = new BufferedImage(root.width + 1, root.height + 1, BufferedImage.TYPE_4BYTE_ABGR);
+ // START KGU#221 2016-07-28: Issue #208 Need to achieve transparent background
+ //printAll(bi.getGraphics());
+ // START KGU#906 2021-01-06: Enh. #905
+ //redraw(bi.createGraphics());
+ redraw(bi.createGraphics(), DrawingContext.DC_IMAGE_EXPORT);
+ // END KGU#906 2021-01-06
+ // END KGU#221 2016-07-28
+ try {
+ ImageIO.write(bi, "png", file);
+ } catch (Exception e) {
+ JOptionPane.showMessageDialog(this.getFrame(),
+ Menu.msgErrorImageSave.getText(),
+ Menu.msgTitleError.getText(),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+ // START KGU#183 2016-04-24: Issue #169 - restore old selection
+ selected = wasSelected;
+ if (selected != null) {
+ selected.setSelected(true);
+ }
+ redraw();
+ // END KGU#183 2016-04-24
+ // START KGU#456 2017-11-05: Enh. #452
+ if (root.advanceTutorialState(26, root)) {
+ analyse();
+ }
+ // END KGU#456 2017-11-05
+ }
+
+ /**
+ * Opens a {@link FileChooser} and performs the image export as EMF file.
+ *
+ * @see #exportPNG()
+ * @see #exportPNGmulti()
+ * @see #exportSVG()
+ * @see #exportPDF()
+ * @see #exportSWF()
+ */
+ public void exportEMF() {
+ // START KGU#183 2016-04-24: Issue #169 - retain old selection
+ Element wasSelected = selected;
+ // END KGU#183 2016-04-24
+
+ // START KGU#41 2015-10-11
+ //root.selectElementByCoord(-1,-1); // Unselect all elements
+ //redraw();
+ unselectAll(true);
+ // END KGU#41 2015-10-11
+
+ JFileChooser dlgSave = new JFileChooser("Export diagram as EMF ...");
+ // START KGU#287 2017-01-09: Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
+ GUIScaler.rescaleComponents(dlgSave);
+ // END KGU#287 2017-01-09
+ // set directory
+ if (lastExportDir != null) {
+ dlgSave.setCurrentDirectory(lastExportDir);
+ } else if (root.getFile() != null) {
+ dlgSave.setCurrentDirectory(root.getFile());
+ } else {
+ dlgSave.setCurrentDirectory(currentDirectory);
+ }
+ // propose name
+ // START KGU 2015-10-16: D.R.Y. - There is already a suitable method
+ // String nsdName = root.getText().get(0);
+ // nsdName.replace(':', '_');
+ // if(nsdName.indexOf(" (")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf(" ("));}
+ // if(nsdName.indexOf("(")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf("("));}
+ String nsdName = root.proposeFileName();
+ // END KGU 2015-10-16
+ dlgSave.setSelectedFile(new File(nsdName));
+
+ // START KGU 2016-04-01: Enh. #110 - select the provided filter
+ //dlgSave.addChoosableFileFilter(new lu.fisch.structorizer.io.EMFFilter());
+ EMFFilter filter = new EMFFilter();
+ dlgSave.addChoosableFileFilter(filter);
+ dlgSave.setFileFilter(filter);
+ hideComments(); // Issue #143: Hide the current comment popup if visible
+ // END KGU 2016-04-01
+ int result = dlgSave.showSaveDialog(NSDControl.getFrame());
+ if (result == JFileChooser.APPROVE_OPTION) {
+ lastExportDir = dlgSave.getSelectedFile().getParentFile();
+ String filename = dlgSave.getSelectedFile().getAbsoluteFile().toString();
+ if (!filename.substring(filename.length() - 4, filename.length()).toLowerCase().equals(".emf")) {
+ filename += ".emf";
+ }
+
+ File file = new File(filename);
+ if (checkOverwrite(file, false) == 0) {
+ try {
+ EMFGraphics2D emf = new EMFGraphics2D(new FileOutputStream(filename),
+ new Dimension(root.width + 12, root.height + 12));
+
+ emf.startExport();
+ lu.fisch.graphics.Canvas c = new lu.fisch.graphics.Canvas(emf);
+ lu.fisch.graphics.Rect myrect = root.prepareDraw(c);
+ myrect.left += 6;
+ myrect.top += 6;
+ root.draw(c, myrect, null, false);
+ emf.endExport();
+ } catch (Exception e) {
+ // START KGU#484 2018-04-05: Issue #463
+ //e.printStackTrace();
+ logger.log(Level.WARNING, "Trouble exporting as image.", e);
+ // END KGU#484 2018-04-05
+ }
+ }
+ }
+ // START KGU#183 2016-04-24: Issue #169 - restor old selection
+ selected = wasSelected;
+ if (selected != null) {
+ selected.setSelected(true);
+ }
+ redraw();
+ // END KGU#183 2016-04-24
+ // START KGU#456 2017-11-05: Enh. #452
+ if (root.advanceTutorialState(26, root)) {
+ analyse();
+ }
+ // END KGU#456 2017-11-05
+ }
+
+ /**
+ * Opens a {@link FileChooser} and performs the image export as SVG file.
+ *
+ * @see #exportPNG()
+ * @see #exportPNGmulti()
+ * @see #exportEMF()
+ * @see #exportPDF()
+ * @see #exportSWF()
+ */
+ public void exportSVG() // does not work!!
+ {
+ // START KGU#183 2016-04-24: Issue #169 - retain old selection
+ Element wasSelected = selected;
+ // END KGU#183 2016-04-24
+
+ // START KGU#41 2015-10-11
+ //root.selectElementByCoord(-1,-1); // Unselect all elements
+ //redraw();
+ unselectAll(true);
+ // END KGU#41 2015-10-11
+
+ JFileChooser dlgSave = new JFileChooser("Export diagram as SVG ...");
+ // START KGU#287 2017-01-09: Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
+ GUIScaler.rescaleComponents(dlgSave);
+ // END KGU#287 2017-01-09
+ // set directory
+ if (lastExportDir != null) {
+ dlgSave.setCurrentDirectory(lastExportDir);
+ } else if (root.getFile() != null) {
+ dlgSave.setCurrentDirectory(root.getFile());
+ } else {
+ dlgSave.setCurrentDirectory(currentDirectory);
+ }
+ // propose name
+ // START KGU 2015-10-16: D.R.Y. - there is already a suitable method
+ // String nsdName = root.getText().get(0);
+ // nsdName.replace(':', '_');
+ // if(nsdName.indexOf(" (")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf(" ("));}
+ // if(nsdName.indexOf("(")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf("("));}
+ String nsdName = root.proposeFileName();
+ // END KGU 2015-10-16
+ dlgSave.setSelectedFile(new File(nsdName));
+
+ // START KGU 2016-04-01: Enh. #110 - select the provided filter
+ //dlgSave.addChoosableFileFilter(new lu.fisch.structorizer.io.SVGFilter());
+ SVGFilter filter = new SVGFilter();
+ dlgSave.addChoosableFileFilter(filter);
+ dlgSave.setFileFilter(filter);
+ hideComments(); // Issue #143: Hide the current comment popup if visible
+ // END KGU 2016-04-01
+ int result = dlgSave.showSaveDialog(NSDControl.getFrame());
+ if (result == JFileChooser.APPROVE_OPTION) {
+ lastExportDir = dlgSave.getSelectedFile().getParentFile();
+ String filename = dlgSave.getSelectedFile().getAbsoluteFile().toString();
+ if (!filename.substring(filename.length() - 4, filename.length()).toLowerCase().equals(".svg")) {
+ filename += ".svg";
+ }
+
+ File file = new File(filename);
+ if (checkOverwrite(file, false) == 0) {
+ try {
+ SVGGraphics2D svg = new SVGGraphics2D(new FileOutputStream(filename), new Dimension(root.width + 12, root.height + 12));
+ svg.startExport();
+ lu.fisch.graphics.Canvas c = new lu.fisch.graphics.Canvas(svg);
+ lu.fisch.graphics.Rect myrect = root.prepareDraw(c);
+ myrect.left += 6;
+ myrect.top += 6;
+ root.draw(c, myrect, null, false);
+ svg.endExport();
+
+ // re-read the file ...
+ StringBuffer buffer = new StringBuffer();
+ InputStreamReader isr = new InputStreamReader(new FileInputStream(filename));
+ Reader in = new BufferedReader(isr);
+ int ch;
+ while ((ch = in.read()) > -1) {
+ buffer.append((char) ch);
+ }
+ // START KGU 2015-12-04
+ in.close();
+ // END KGU 2015-12-04
+
+ // ... and encode it UTF-8
+ FileOutputStream fos = new FileOutputStream(filename);
+ Writer out = new OutputStreamWriter(fos, "UTF-8");
+ out.write(buffer.toString());
+ out.close();
+
+ } catch (Exception e) {
+ // START KGU#484 2018-04-05: Issue #463
+ //e.printStackTrace();
+ logger.log(Level.WARNING, "Trouble exporting as image.", e);
+ // END KGU#484 2018-04-05
+ }
+ }
+ }
+
+ // START KGU#183 2016-04-24: Issue #169 - restore old selection
+ //unselectAll();
+ selected = wasSelected;
+ if (selected != null) {
+ selected.setSelected(true);
+ }
+ redraw();
+ // END KGU#183 2016-04-24
+ // START KGU#456 2017-11-05: Enh. #452
+ if (root.advanceTutorialState(26, root)) {
+ analyse();
+ }
+ // END KGU#456 2017-11-05
+ }
+
+ /**
+ * Opens a {@link FileChooser} and performs the image export as SWF file.
+ *
+ * @see #exportPNG()
+ * @see #exportPNGmulti()
+ * @see #exportSVG()
+ * @see #exportPDF()
+ * @see #exportEMF()
+ */
+ public void exportSWF() {
+ // START KGU#183 2016-04-24: Issue #169 - retain old selection
+ Element wasSelected = selected;
+ // END KGU#183 2016-04-24
+
+ // START KGU 2015-10-11
+ //root.selectElementByCoord(-1,-1); // Unselect all elements
+ //redraw();
+ unselectAll(true);
+ // END KGU 2015-10-11
+
+ JFileChooser dlgSave = new JFileChooser("Export diagram as SWF ...");
+ // START KGU#287 2017-01-09: Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
+ GUIScaler.rescaleComponents(dlgSave);
+ // END KGU#287 2017-01-09
+ // set directory
+ if (lastExportDir != null) {
+ dlgSave.setCurrentDirectory(lastExportDir);
+ } else if (root.getFile() != null) {
+ dlgSave.setCurrentDirectory(root.getFile());
+ } else {
+ dlgSave.setCurrentDirectory(currentDirectory);
+ }
+ // propose name
+ // START KGU 2015-10-16: D.R.Y. - there is already a suitable method
+ // String nsdName = root.getText().get(0);
+ // nsdName.replace(':', '_');
+ // if(nsdName.indexOf(" (")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf(" ("));}
+ // if(nsdName.indexOf("(")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf("("));}
+ String nsdName = root.proposeFileName();
+ // END KGU 2015-10-16
+ dlgSave.setSelectedFile(new File(nsdName));
+
+ // START KGU 2016-04-01: Enh. #110 - select the provided filter
+ //dlgSave.addChoosableFileFilter(new lu.fisch.structorizer.io.SWFFilter());
+ SWFFilter filter = new SWFFilter();
+ dlgSave.addChoosableFileFilter(filter);
+ dlgSave.setFileFilter(filter);
+ hideComments(); // Issue #143: Hide the current comment popup if visible
+ // END KGU 2016-04-01
+ int result = dlgSave.showSaveDialog(NSDControl.getFrame());
+ if (result == JFileChooser.APPROVE_OPTION) {
+ lastExportDir = dlgSave.getSelectedFile().getParentFile();
+ String filename = dlgSave.getSelectedFile().getAbsoluteFile().toString();
+ if (!filename.substring(filename.length() - 4, filename.length()).toLowerCase().equals(".swf")) {
+ filename += ".swf";
+ }
+
+ File file = new File(filename);
+ if (checkOverwrite(file, false) == 0) {
+ try {
+ SWFGraphics2D svg = new SWFGraphics2D(new FileOutputStream(filename), new Dimension(root.width + 12, root.height + 12));
+
+ svg.startExport();
+ lu.fisch.graphics.Canvas c = new lu.fisch.graphics.Canvas(svg);
+ lu.fisch.graphics.Rect myrect = root.prepareDraw(c);
+ myrect.left += 6;
+ myrect.top += 6;
+ root.draw(c, myrect, null, false);
+ svg.endExport();
+ } catch (Exception e) {
+ // START KGU#484 2018-04-05: Issue #463
+ //e.printStackTrace();
+ logger.log(Level.WARNING, "Trouble exporting as image.", e);
+ // END KGU#484 2018-04-05
+ }
+ }
+ }
+ // START KGU#183 2016-04-24: Issue #169 - restore old selection
+ selected = wasSelected;
+ if (selected != null) {
+ selected.setSelected(true);
+ }
+ redraw();
+ // END KGU#183 2016-04-24
+ // START KGU#456 2017-11-05: Enh. #452
+ if (root.advanceTutorialState(26, root)) {
+ analyse();
+ }
+ // END KGU#456 2017-11-05
+ }
+
+ /**
+ * Opens a {@link FileChooser} and performs the image export as PDF file.
+ *
+ * @see #exportPNG()
+ * @see #exportPNGmulti()
+ * @see #exportSVG()
+ * @see #exportEMF()
+ * @see #exportSWF()
+ * @see #printNSD()
+ */
+ public void exportPDF() {
+ // START KGU#183 2016-04-24: Issue #169 - retain old selection
+ Element wasSelected = selected;
+ // END KGU#183 2016-04-24
+
+ // START KGU 2015-10-11
+ //root.selectElementByCoord(-1,-1); // Unselect all elements
+ //redraw();
+ unselectAll(true);
+ // END KGU 2015-10-11
+
+ JFileChooser dlgSave = new JFileChooser("Export diagram as PDF ...");
+ // START KGU#287 2017-01-09: Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
+ GUIScaler.rescaleComponents(dlgSave);
+ // END KGU#287 2017-01-09
+ // set directory
+ if (lastExportDir != null) {
+ dlgSave.setCurrentDirectory(lastExportDir);
+ } else if (root.getFile() != null) {
+ dlgSave.setCurrentDirectory(root.getFile());
+ } else {
+ dlgSave.setCurrentDirectory(currentDirectory);
+ }
+ // propose name
+ // START KGU 2015-10-16: D.R.Y. - there is already a suitable method
+ // String nsdName = root.getText().get(0);
+ // nsdName.replace(':', '_');
+ // if(nsdName.indexOf(" (")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf(" ("));}
+ // if(nsdName.indexOf("(")>=0) {nsdName=nsdName.substring(0,nsdName.indexOf("("));}
+ String nsdName = root.proposeFileName();
+ // END KGU 2015-10-16
+ dlgSave.setSelectedFile(new File(nsdName));
+
+ // START KGU 2016-04-01: Enh. #110 - select the provided filter
+ //dlgSave.addChoosableFileFilter(new lu.fisch.structorizer.io.PDFFilter());
+ PDFFilter filter = new PDFFilter();
+ dlgSave.addChoosableFileFilter(filter);
+ dlgSave.setFileFilter(filter);
+ hideComments(); // Issue #143: Hide the current comment popup if visible
+ // END KGU 2016-04-01
+ int result = dlgSave.showSaveDialog(NSDControl.getFrame());
+ if (result == JFileChooser.APPROVE_OPTION) {
+ lastExportDir = dlgSave.getSelectedFile().getParentFile();
+ String filename = dlgSave.getSelectedFile().getAbsoluteFile().toString();
+ if (!filename.substring(filename.length() - 4, filename.length()).toLowerCase().equals(".pdf")) {
+ filename += ".pdf";
+ }
+
+ File file = new File(filename);
+ if (checkOverwrite(file, false) == 0) {
+ try {
+ PDFGraphics2D pdf = new PDFGraphics2D(new FileOutputStream(filename), new Dimension(root.width + 12, root.height + 12));
+
+ pdf.startExport();
+ lu.fisch.graphics.Canvas c = new lu.fisch.graphics.Canvas(pdf);
+ lu.fisch.graphics.Rect myrect = root.prepareDraw(c);
+ myrect.left += 6;
+ myrect.top += 6;
+ root.draw(c, myrect, null, false);
+ pdf.endExport();
+ } catch (Exception e) {
+ // START KGU#484 2018-04-05: Issue #463
+ //e.printStackTrace();
+ logger.log(Level.WARNING, "Trouble exporting as image.", e);
+ // END KGU#484 2018-04-05
+ }
+ }
+ }
+ // START KGU#183 2016-04-24: Issue #169 - restore old selection
+ selected = wasSelected;
+ if (selected != null) {
+ selected.setSelected(true);
+ }
+ redraw();
+ // END KGU#183 2016-04-24
+ // START KGU#456 2017-11-05: Enh. #452
+ if (root.advanceTutorialState(26, root)) {
+ analyse();
+ }
+ // END KGU#456 2017-11-05
+ }
+
+ // START KGU#396 2020-03-03: Enh. #440 Specific export interface for PapDesigner
+ /**
+ * Exports the current diagram (possibly with all referenced subdiagrams) as
+ * PAP flowcharts compatible with PapDesigner.
+ *
+ * @param din66001_1982 - whether the newer DIN 66001 (from 1982) is to be
+ * applied (otherwise the obsolete standard version from 1966 will be
+ * adhered to)
+ * @see #exportPap(Root, boolean)
+ */
+ public void exportPap(boolean din66001_1982) {
+ exportPap(root, din66001_1982);
+ }
+
+ /**
+ * Exports the given diagram {@code _root} (possibly with all referenced
+ * subdiagrams) as PAP flowchart compatible with PapDesigner
+ *
+ * @param _root - the top level {@link Root} to be exported
+ * @param din66001_1982 - whether the newer DIN 66001 (from 1982) is to be
+ * applied (otherwise the obsolete standard version from 1966 will be
+ * adhered to) #see {@link #exportPap(boolean)}
+ */
+ public void exportPap(Root _root, boolean din66001_1982) {
+ try {
+ Generator gen = new PapGenerator();
+ gen.setPluginOption("din66001_1982", din66001_1982);
+ hideComments(); // Hide the current comment popup if visible
+ File exportDir
+ = gen.exportCode(_root,
+ (lastCodeExportDir != null ? lastCodeExportDir : currentDirectory),
+ NSDControl.getFrame(),
+ (Arranger.hasInstance() ? Arranger.getInstance() : null));
+ if (exportDir != null) {
+ this.lastCodeExportDir = exportDir;
+ }
+ } catch (Exception ex) {
+ String message = ex.getLocalizedMessage();
+ if (message == null) {
+ message = ex.getMessage();
+ }
+ if (message == null || message.isEmpty()) {
+ message = ex.toString();
+ }
+ JOptionPane.showMessageDialog(this.getFrame(),
+ Menu.msgErrorUsingGenerator.getText().replace("%", PapGenerator.class.getSimpleName()) + "\n" + message,
+ Menu.msgTitleError.getText(),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ // END KGU#396 2020-03-03
+
+
+ /*========================================
+ * Import method for foreign diagrams
+ *========================================*/
+ // START KGU#386 2017-04-25: version 3.26-06 - new import sources
+ /**
+ * Imports diagrams from alien file formats (e.g. from Struktogrammeditor)
+ *
+ * @param _className - Name of the appropriate importer class (to be
+ * configured via plugins)
+ * @param _specificOptions - importer-specific key-value pairs
+ */
+ public void importNSD(String _className, Vector> _specificOptions) {
+ // only save if something has been changed
+ saveNSD(true);
+
+ if (!this.checkRunning()) {
+ return; // Don't proceed if the root is being executed
+ }
+ // open an existing file
+ // create dialog
+ JFileChooser dlgOpen = new JFileChooser();
+ // Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
+ GUIScaler.rescaleComponents(dlgOpen);
+ INSDImporter parser = null;
+ try {
+ // FIXME: For future Java versions we may need a factory here
+ Class> impClass = Class.forName(_className);
+ parser = (INSDImporter) impClass.getDeclaredConstructor().newInstance();
+
+ dlgOpen.setDialogTitle(Menu.msgTitleNSDImport.getText().replace("%", parser.getDialogTitle()));
+ // set directory
+ dlgOpen.setCurrentDirectory(currentDirectory);
+ // config dialogue
+ FileFilter filter = parser.getFileFilter();
+ dlgOpen.addChoosableFileFilter(filter);
+ dlgOpen.setFileFilter(filter);
+ // show & get result
+ int result = dlgOpen.showOpenDialog(this);
+ // react to result
+ if (result == JFileChooser.APPROVE_OPTION) {
+ //boolean hil = root.highlightVars;
+ // FIXME: Replace this with a generalized version of openNSD(String)
+ root = parser.parse(dlgOpen.getSelectedFile().toURI().toString());
+ //root.highlightVars = hil;
+ if (Element.E_VARHIGHLIGHT) {
+ root.retrieveVarNames(); // Initialise the variable table, otherwise the highlighting won't work
+ }
+ currentDirectory = dlgOpen.getSelectedFile();
+ redraw();
+ }
+ } catch (Exception ex) {
+ String message = ex.getLocalizedMessage();
+ if (message == null) {
+ message = ex.getMessage();
+ }
+ if (message == null || message.isEmpty()) {
+ message = ex.toString();
+ }
+ JOptionPane.showMessageDialog(this.getFrame(), message,
+ Menu.msgTitleError.getText(), JOptionPane.ERROR_MESSAGE);
+ // START KGU#484 2018-04-05: Issue #463
+ //ex.printStackTrace();
+ logger.log(Level.WARNING, "Using parser " + _className + " failed.", ex);
+ // END KGU#484 2018-04-05
+ }
+ // START KGU#444/KGU#618 2018-12-18: Issue #417, #649
+ this.adaptScrollUnits();
+ // END KGU#444/KGU#618 2018-12-18
+ }
+ // END KGU#386 2017-04-25
+
+ /*========================================
+ * import methods for code
+ *========================================*/
+ // START KGU#537 2018-06-29: Enh. #553
+ /**
+ * Internal helper class for the background parsing of code to be imported.
+ *
+ * @author Kay Gürtzig
+ */
+ private class ImportWorker extends SwingWorker, Integer> {
+
+ private CodeParser parser;
+ private File file;
+ private Ini ini;
+ private String logPath;
+
+ public ImportWorker(CodeParser _parser, File _file, Ini _ini, String _logPath) {
+ this.parser = _parser;
+ this.file = _file;
+ this.ini = _ini;
+ this.logPath = _logPath;
+ }
+
+ @Override
+ protected List doInBackground() throws Exception {
+ //System.out.println("*** " + this.getClass().getSimpleName()+" going to work!");
+ this.parser.setSwingWorker(this);
+ List roots = null;
+ roots = parser.parse(file.getAbsolutePath(),
+ ini.getProperty("impImportCharset", "ISO-8859-1"),
+ // START KGU#354 2017-04-27: Enh. #354
+ logPath
+ // END KGU#354 2017-04-27
+ );
+ return roots;
+ }
+
+ }
+ // END KGU#537 2018-06-30
+
+ /**
+ * Gets an instance of the given parser class, interactively selects a
+ * source file for the chosen language parses the file and tries to build a
+ * structogram from it in a background thread.
+ *
+ * @param options
+ */
+ public void importCode(/*String _parserClassName,*/) {
+ // only save if something has been changed
+ saveNSD(true);
+
+ CodeParser parser = null;
+
+ // START KGU#354 2017-03-14: Enh. #354
+ this.retrieveParsers();
+ // END KGU#354 2017-03-14
+
+ JFileChooser dlgOpen = new JFileChooser();
+ // START KGU#287 2017-01-09: Bugfix #330 Ensure Label items etc. be scaled for L&F "Nimbus"
+ GUIScaler.rescaleComponents(dlgOpen);
+ // END KGU#287 2017-01-09
+ dlgOpen.setDialogTitle(Menu.msgTitleImport.getText());
+ // set directory
+ // START KGU#354 2017-04-26: Enh. #354
+ //if(root.getFile()!=null)
+ //{
+ // dlgOpen.setCurrentDirectory(root.getFile());
+ //}
+ File importDir = this.lastCodeImportDir;
+ if (importDir != null || (importDir = root.getFile()) != null) {
+ dlgOpen.setCurrentDirectory(importDir);
+ }
+ // END KGU#354 2017-04-26
+ else {
+ dlgOpen.setCurrentDirectory(currentDirectory);
+ }
+
+ for (CodeParser psr : parsers) {
+ dlgOpen.addChoosableFileFilter(psr);
+ // START KGU#354 2017-04-26: Enh. #354 GUI improvement
+ if (psr.getDialogTitle().equals(this.lastImportFilter)) {
+ dlgOpen.setFileFilter(psr);
+ }
+ }
+ //dlgOpen.setFileFilter(parser);
+
+ hideComments(); // Issue #143: Hide the current comment popup if visible
+ int result = dlgOpen.showOpenDialog(NSDControl.getFrame());
+
+ if (result == JFileChooser.APPROVE_OPTION) {
+ File file = dlgOpen.getSelectedFile().getAbsoluteFile();
+
+ if (!file.canRead()) {
+ JOptionPane.showMessageDialog(this.getFrame(),
+ Menu.msgImportFileReadError.getText().replace("%", file.getPath()));
+ return;
+ }
+
+ // Identify a suited or the selected parser
+ javax.swing.filechooser.FileFilter filter = dlgOpen.getFileFilter();
+
+ parser = identifyParser(file, filter);
+
+ if (parser == null) {
+ JOptionPane.showMessageDialog(this.getFrame(),
+ Menu.msgImportCancelled.getText().replace("%", file.getPath()));
+ return;
+ }
+
+ // START KGU#354 2017-04-26: Enh. #354
+ this.lastImportFilter = parser.getDialogTitle();
+ this.lastCodeImportDir = file.getParentFile();
+ // END KGU#354 2017-04-26
+
+ Cursor origCursor = getCursor();
+ try {
+ setCursor(new Cursor(Cursor.WAIT_CURSOR));
+
+ // load and parse source-code
+ //CParser cp = new CParser("C-ANSI.cgt");
+ // START KGU#194 2016-05-08: Bugfix #185 - mechanism for multiple roots per file
+ //Root rootNew = d7.parse(filename);
+ // START KGU#265 2016-09-28: Enh. #253 brought the Charset configuration. So make use of it.
+ //List newRoots = d7.parse(filename, "ISO-8859-1");
+ Ini ini = Ini.getInstance();
+ // START KGU#354 2017-04-27: Enh. #354
+ boolean isVerbose = ini.getProperty("impLogToDir", "false").equals("true");
+ String logPath = null;
+ if (isVerbose) {
+ logPath = ini.getProperty("impLogDir", "");
+ if (logPath.isEmpty()) {
+ logPath = file.getParent();
+ } else if (logPath.equals(".")) {
+ if (currentDirectory != null) {
+ if (!currentDirectory.isDirectory()) {
+ logPath = currentDirectory.getParent();
+ } else {
+ logPath = currentDirectory.getPath();
+ }
+ }
+ }
+ }
+ // END KGU#354 2017-04-27
+ // START KGU#354 2017-05-11: Enh. #354 - we better use a new instance instead of statically sharing it
+ parser = parser.getClass().getDeclaredConstructor().newInstance();
+ // END KGU#354 2017-05-11
+ // START KGU#395 2017-07-02: Enh. #357
+ String parserClassName = parser.getClass().getSimpleName();
+ for (int i = 0; i < parserPlugins.size(); i++) {
+ GENPlugin plug = parserPlugins.get(i);
+ if (plug.getKey().equals(parserClassName)) {
+ this.setPluginSpecificOptions(parser, parserClassName, plug.options);
+ }
+ }
+ // END KGU#395 2017-07-02
+ // START KGU#537 2018-06-30: Enh. #553
+ // List newRoots = parser.parse(file.getAbsolutePath(),
+ // ini.getProperty("impImportCharset", "ISO-8859-1"),
+ // // START KGU#354 2017-04-27: Enh. #354
+ // logPath
+ // // END KGU#354 2017-04-27
+ // );
+ ImportWorker worker = new ImportWorker(parser, file, ini, logPath);
+ // Pop up the progress monitor (it will be closed via the OK buttons).
+ new CodeImportMonitor(this.getFrame(), worker, parser.getDialogTitle());
+ List newRoots = worker.get();
+ // END KGU#537 2018-06-30
+ // END KGU#265 2016-09-28
+ // END KGU#194 2016-05-08
+ if (parser.error.equals("") && !worker.isCancelled()) {
+ //boolean hil = root.highlightVars;
+ // START KGU#194 2016-05-08: Bugfix #185 - there may be multiple routines
+ Root firstRoot = null;
+ //root = rootNew;
+ Iterator iter = newRoots.iterator();
+ if (iter.hasNext()) {
+ firstRoot = iter.next();
+ }
+ // START KGU#553 2018-07-10: In case of too many diagrams Structorizer would go zombie
+ int nRoots = newRoots.size();
+ int maxRoots = Integer.parseInt(ini.getProperty("impMaxRootsForDisplay", "20"));
+ if (nRoots > maxRoots) {
+ String[] options = {Menu.lblContinue.getText(), Menu.lblCancel.getText()};
+ int chosen = JOptionPane.showOptionDialog(this.getFrame(),
+ Menu.msgTooManyDiagrams.getText().replace("%", Integer.toString(maxRoots)),
+ Menu.ttlCodeImport.getText(),
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.WARNING_MESSAGE, null,
+ options, 0);
+ if (chosen != JOptionPane.OK_OPTION) {
+ newRoots.clear();
+ iter = newRoots.iterator();
+ }
+ startSerialMode();
+ try {
+ while (iter.hasNext() && getSerialDecision(SerialDecisionAspect.SERIAL_SAVE) != SerialDecisionStatus.NO_TO_ALL) {
+ Root nextRoot = iter.next();
+ //nextRoot.highlightVars = hil;
+ nextRoot.setChanged(false);
+ // If the saving attempt fails, ask whether the saving loop is to be cancelled
+ if (!this.saveNSD(nextRoot, false)) {
+ if (JOptionPane.showConfirmDialog(
+ this.getFrame(),
+ Menu.msgCancelAll.getText(),
+ Menu.ttlCodeImport.getText(),
+ JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
+ // User decided not to save further diagrams.
+ setSerialDecision(SerialDecisionAspect.SERIAL_SAVE, false);
+ }
+ // Saving failed, but no abort, so go on with next file (don't change status)
+ }
+ }
+ } finally {
+ endSerialMode();
+ newRoots.clear();
+ iter = newRoots.iterator();
+ nRoots = 1;
+ }
+ }
+ // END KGU#553 2018-07-10
+ while (iter.hasNext()) {
+ root = iter.next();
+ //root.highlightVars = hil;
+ if (Element.E_VARHIGHLIGHT) {
+ root.retrieveVarNames(); // Initialise the variable table, otherwise the highlighting won't work
+ }
+ // The Root must be marked for saving
+ root.setChanged(false);
+ // ... and be added to the Arranger
+ // START KGU#626 2018-12-28 Enh. #657 - group management introduced
+ //this.arrangeNSD();
+ this.arrangeNSD(file.getName());
+ // END KGU#626 2018-12-28
+ Arranger.getInstance().enableNotification(false);
+ }
+ if (firstRoot != null) {
+ root = firstRoot;
+ // END KGU#194 2016-05-08
+ //root.highlightVars = hil;
+ if (Element.E_VARHIGHLIGHT) {
+ root.retrieveVarNames(); // Initialise the variable table, otherwise the highlighting won't work
+ }
+ // START KGU#183 2016-04-24: Enh. #169
+ selected = root;
+ selected.setSelected(true);
+ // END KGU#183 2016-04-24
+ // START KGU#192 2016-05-02: #184 - The Root must be marked for saving
+ root.setChanged(false);
+ // END KGU#192 2016-05-02
+ // START KGU#354 2017-05-23: Enh.#354 - with many roots it's better to push the principal root to the Arranger, too
+ // START KGU#626 2018-12-28: Enh. #657 - with groups, push the main diagram, too, also in case of a program
+ //if (nRoots > 2 || !root.isProgram()) {
+ // this.arrangeNSD();
+ //}
+ if (nRoots > 2) {
+ this.arrangeNSD(file.getName());
+ }
+ // END KGU#626 2018-12-28
+ // END KGU#354 2017-05-23
+ // START KGU#194 2016-05-08: Bugfix #185 - multiple routines per file
+ }
+ // END KGU#194 2016-05-08
+ } else {
+ // show error
+ // START KGU 2016-01-11: Yes and No buttons somewhat strange...
+ //JOptionPane.showOptionDialog(null,d7.error,
+ // "Parser Error",
+ // JOptionPane.OK_OPTION,JOptionPane.ERROR_MESSAGE,null,null,null);
+ // START KGU#364 2017-12-12: Issue #471 - Allow to copy the content
+ //JOptionPane.showMessageDialog(this.NSDControl.getFrame(),
+ // parser.error,
+ // Menu.msgTitleParserError.getText(),
+ // JOptionPane.ERROR_MESSAGE, null);
+ String[] options = {Menu.lblOk.getText(), Menu.lblCopyToClipBoard.getText()};
+ int chosen = JOptionPane.showOptionDialog(this.getFrame(),
+ parser.error,
+ Menu.msgTitleParserError.getText(),
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.ERROR_MESSAGE, null,
+ options, 0);
+ if (chosen == 1) {
+ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ // START KGU#604 2018-10-29: Enh. #627 - Append a stacktrace if available
+ //StringSelection toClip = new StringSelection(parser.error);
+ String errorString = parser.error;
+ if (parser.exception != null) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ parser.exception.printStackTrace(new PrintStream(baos));
+ errorString += "\n\nSTACK TRACE\n(A more detailed trace will be in the structorizer log file):\n\n" + baos.toString();
+ }
+ StringSelection toClip = new StringSelection(errorString);
+ // END KGU#604 2018-10-29
+ clipboard.setContents(toClip, null);
+ }
+ // END KGU#364 2017-12-12
+ // END KGU 2016-01-11
+ }
+ } catch (java.util.concurrent.CancellationException ex) {
+ JOptionPane.showMessageDialog(this.getFrame(),
+ Menu.msgImportCancelled.getText().replace("%", file.getPath()));
+ } catch (Exception ex) {
+ String message = ex.getLocalizedMessage();
+ if (message == null) {
+ message = ex.getMessage();
+ // START KGU#484 2018-04-05: Issue #463
+ //ex.printStackTrace();
+ logger.log(Level.WARNING, "", ex);
+ // END KGU#484 2018-04-05
+ }
+ if (message == null || message.isEmpty()) {
+ message = ex.toString();
+ }
+ JOptionPane.showMessageDialog(this.getFrame(),
+ Menu.msgErrorUsingParser.getText().replace("%", parser.getDialogTitle()) + "\n" + message,
+ Menu.msgTitleError.getText(),
+ JOptionPane.ERROR_MESSAGE);
+ } finally {
+ doButtons();
+ redraw();
+ analyse();
+ // START KGU#444/KGU#618 2018-12-18: Issue #417, #649 - We may have obtained huge diagrams...
+ this.adaptScrollUnits();
+ // END KGU#444/KGU#618 2018-12-18
+ // START KGU#705 2019-09-24: Enh. #738
+ updateCodePreview();
+ // END KGU#705 2019-09-24
+ setCursor(origCursor);
+ if (Arranger.hasInstance()) {
+ // KGU#947 2021-03-01 Bugfix #950 Bad implementation caused permanent loss of notifications
+ Arranger.getInstance().enableNotification(true);
+ }
+ }
+ }
+ }
+
+ // START KGU#354 2017-03-15: Enh. #354 - auxiliary methods
+ // Tries to disambiguate the parser for the given file
+ private CodeParser identifyParser(File file, FileFilter usedFilter) {
+ CodeParser parser = null;
+
+ Vector candidates = new Vector();
+ String[] choice = new String[parsers.size()];
+ Vector candStrings = new Vector();
+ // We are better prepared for the ambiguous case...
+ int nr0 = 1, nr = 1;
+ final String format = "%2d: %s";
+ for (CodeParser psr : parsers) {
+ String descr = psr.getDescription();
+ choice[nr0 - 1] = String.format(format, nr0, descr);
+ nr0++;
+ if (usedFilter == psr) {
+ // The user had explicitly chosen this filter, so we are ready
+ parser = psr;
+ break;
+ } else if (psr.accept(file)) {
+ candidates.add(psr);
+ candStrings.add(String.format(format, nr++, descr));
+ }
+ }
+
+ if (parser == null) {
+ if (candidates.size() == 1) {
+ parser = candidates.get(0);
+ } else {
+ if (!candidates.isEmpty()) {
+ choice = candStrings.toArray(new String[candStrings.size()]);
+ } else {
+ candidates = parsers;
+ }
+ JComboBox cbParsers = new JComboBox(choice);
+ String prompt = Menu.msgSelectParser.getText().replace("%", file.getName());
+ int resp = JOptionPane.showConfirmDialog(null,
+ new Object[]{prompt, cbParsers},
+ Menu.ttlCodeImport.getText(),
+ JOptionPane.OK_CANCEL_OPTION);
+ if (resp == JOptionPane.OK_OPTION) {
+ int index = cbParsers.getSelectedIndex();
+ // Well this test is of course mere paranoia...
+ if (index >= 0 && index < candidates.size()) {
+ parser = candidates.get(index);
+ }
+ }
+ }
+ }
+ return parser;
+ }
+
+ /**
+ * Lazy initialization method for static field {@link #parsers}
+ */
+ private void retrieveParsers() {
+ if (parsers != null) {
+ return;
+ }
+ parsers = new Vector();
+ String errors = "";
+ try ( BufferedInputStream buff = new BufferedInputStream(getClass().getResourceAsStream("parsers.xml"))) {
+ GENParser genp = new GENParser();
+ parserPlugins = genp.parse(buff);
+ } catch (IOException e) {
+ // START KGU#484 2018-04-05: Issue #463
+ //e.printStackTrace();
+ logger.log(Level.WARNING, "Couldn't close parser plugin definition file.", e);
+ // END KGU#484 2018-04-05
+ }
+ for (int i = 0; parserPlugins != null && i < parserPlugins.size(); i++) {
+ GENPlugin plugin = parserPlugins.get(i);
+ final String className = plugin.className;
+ try {
+ Class> genClass = Class.forName(className);
+ parsers.add((CodeParser) genClass.getDeclaredConstructor().newInstance());
+ } catch (Exception ex) {
+ errors += "\n" + plugin.title + ": " + ex.getLocalizedMessage();
+ }
+ }
+ if (!errors.isEmpty()) {
+ errors = Menu.msgTitleLoadingError.getText() + errors;
+ JOptionPane.showMessageDialog(this.getFrame(), errors,
+ Menu.msgTitleParserError.getText(), JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ // END KGU#354 2017-03-15
+
+ /*========================================
+ * export code methods
+ *========================================*/
+ /**
+ * Export the current diagram to the programming language associated to the
+ * generator {@code _generatorClassName}
+ *
+ * @param _generatorClassName - class name of he generator to be used
+ * @param _specificOptions - generator-specific options
+ */
+ public void export(String _generatorClassName, Vector> _specificOptions) {
+ // START KGU#815 2020-02-20: Enh. 828 - We offer not only the export of groups but also of diagrams
+ // (Code moved to export(Root, String, Vector))
+ export(root, _generatorClassName, _specificOptions);
+ // END KGU#815 2020-02-20
+ }
+
+ // START KGU#815 2020-03-16: Enh. #828
+ /**
+ * Export the given diagram {@code _root} to the programming language
+ * associated to the generator {@code _generatorClassName}.
+ *
+ * @param _generatorClassName - class name of he generator to be used
+ * @param _specificOptions - generator-specific options
+ */
+ public void export(Root _root, String _generatorClassName, Vector> _specificOptions) {
+ // START KGU#901 2020-12-29: Issue #901 apply WAIT_CURSOR during time-consuming actions
+ Cursor origCursor = getCursor();
+ // END KGU#901 2020-12-29
+ try {
+ Class> genClass = Class.forName(_generatorClassName);
+ Generator gen = (Generator) genClass.getDeclaredConstructor().newInstance();
+ // START KGU#170 2016-04-01: Issue #143
+ hideComments(); // Hide the current comment popup if visible
+ // END KGU#170 2016-04-01
+ // START KGU#815 2020-03-30: Enh. #828 If called from ArrangerIndex, options will be null
+ if (_specificOptions == null) {
+ for (GENPlugin plugin : Menu.generatorPlugins) {
+ if (plugin.className.equals(_generatorClassName)) {
+ _specificOptions = plugin.options;
+ break;
+ }
+ }
+ if (_specificOptions == null) {
+ _specificOptions = new Vector>();
+ }
+ }
+ // END KGU#815 2020-03-20
+ // START KGU#395 2017-05-11: Enh. #357
+ this.setPluginSpecificOptions(gen, _generatorClassName, _specificOptions);
+ // END KGU#395 2017-05-11
+ // START KGU#901 2020-12-29: Issue #901 applay WAIT_CURSOR for time-consuming actions
+ setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ // END KGU#901 2020-12-29
+ // START KGU 2017-04-26: Remember the export directory
+ //gen.exportCode(root, currentDirectory, NSDControl.getFrame());
+ // START KGU#654 2019-02-16: Enh. #681 Don't overwrite the last export dir in case the export failed or was cancelled
+ //this.lastCodeExportDir =
+ File exportDir
+ = // END KGU#654 2019-02-16
+ gen.exportCode(_root,
+ (lastCodeExportDir != null ? lastCodeExportDir : currentDirectory),
+ // START KGU#676/KGU#679 2019-03-13: Enh. #696,#698 Specify the routine pool expicitly
+ //NSDControl.getFrame());
+ NSDControl.getFrame(),
+ (Arranger.hasInstance() ? Arranger.getInstance() : null));
+ // END KGU#676 2019-03-13
+ // START KGU#654 2019-02-16: Enh. #681
+ // START KGU#456 2017-11-05: Enh. #452
+ if (_root == root && root.advanceTutorialState(26, root)) {
+ analyse();
+ }
+ // END KGU#456 2017-11-05
+ // START KGU#654 2019-02-15/16: Enh. #681 - count the successful exports to the target language
+ if (exportDir != null) {
+ this.lastCodeExportDir = exportDir;
+
+ String prefGenName = this.getPreferredGeneratorName();
+ String thisGenName = null;
+ for (GENPlugin plugin : Menu.generatorPlugins) {
+ if (plugin.className.equals(_generatorClassName)) {
+ thisGenName = plugin.title;
+ break;
+ }
+ }
+ if (thisGenName.equals(this.lastGeneratorName)) {
+ if (++this.generatorUseCount == this.generatorProposalTrigger && this.generatorProposalTrigger > 0
+ && !prefGenName.equals(this.lastGeneratorName)) {
+ // START KGU#901 2020-12-29: Issue #901 applay WAIT_CURSOR for time-consuming actions
+ setCursor(origCursor);
+ // END KGU#901 2020-12-29
+ if (JOptionPane.showConfirmDialog(this.getFrame(),
+ Menu.msgSetAsPreferredGenerator.getText().replace("%1", thisGenName).replaceAll("%2", Integer.toString(this.generatorUseCount)),
+ Menu.lbFileExportCodeFavorite.getText().replace("%", thisGenName),
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
+ this.prefGeneratorName = thisGenName;
+ Ini.getInstance().setProperty("genExportPreferred", thisGenName);
+ Ini.getInstance().save();
+ // START KGU#705 2019-09-23: Enh. #738
+ this.updateCodePreview();
+ // END KGU#705 2019-09-23
+ // doButtons() is assumed to be performed after his method had been called, anyway
+ }
+ }
+ } else {
+ this.lastGeneratorName = thisGenName;
+ this.generatorUseCount = 1;
+ }
+ }
+ // END KGU#654 2019-02-15/16
+ } catch (Exception ex) {
+ // START KGU#901 2020-12-29: Issue #901 applay WAIT_CURSOR for time-consuming actions
+ setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ // END KGU#901 2020-12-29
+ String message = ex.getLocalizedMessage();
+ if (message == null) {
+ message = ex.getMessage();
+ }
+ if (message == null || message.isEmpty()) {
+ message = ex.toString();
+ }
+ JOptionPane.showMessageDialog(this.getFrame(),
+ Menu.msgErrorUsingGenerator.getText().replace("%", _generatorClassName) + "\n" + message,
+ Menu.msgTitleError.getText(),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ // START KGU#901 2020-12-29: Issue #901 apply WAIT_CURSOR during time-consuming actions
+ finally {
+ setCursor(origCursor);
+ }
+ // END KGU#901 2020-12-29
+ }
+
+ /**
+ * Export the group represented by the programming language associated to
+ * the generator {@code _generatorClassName}
+ *
+ * @param group - The {@link Group} to be exported
+ * @param generatorName - class name of the generator to be used
+ * @param extraOptions - a possible extra option map (handled like plugin
+ * options) or null
+ */
+ public void exportGroup(Group group, String generatorName, Map extraOptions) {
+ hideComments(); // Hide the current comment popup if visible (issue #143)
+ File groupFile = group.getFile();
+ File targetDir = lastCodeExportDir;
+ // START KGU#935 2021-02-12: Bugfix #936
+ //if ((targetDir == null || Ini.getInstance().getProperty("", "true").equals("true")) && groupFile.exists()) {
+ if ((targetDir == null || Ini.getInstance().getProperty("", "true").equals("true"))
+ && groupFile != null && groupFile.exists()) {
+ // END KGU#935 2021-02-12
+ targetDir = groupFile.getParentFile();
+ }
+ if (targetDir == null || !targetDir.exists()) {
+ targetDir = currentDirectory;
+ }
+ String groupName = group.proposeFileName().replace(".", "_");
+
+ // START KGU#901 2020-12-29: Issue #901 applay WAIT_CURSOR for time-consuming actions
+ Cursor origCursor = getCursor();
+ // END KGU#901 2020-12-29
+ try {
+ Class> genClass = Class.forName(generatorName);
+ Generator gen = (Generator) genClass.getDeclaredConstructor().newInstance();
+ Vector> options = null;
+ for (GENPlugin plugin : Menu.generatorPlugins) {
+ if (plugin.className.equals(generatorName)) {
+ options = plugin.options;
+ break;
+ }
+ }
+ if (options == null) {
+ options = new Vector>();
+ }
+ this.setPluginSpecificOptions(gen, generatorName, options);
+ // START KGU#396 2020-04-01: Temporary extra mechanism for #440
+ if (extraOptions != null) {
+ for (Map.Entry option : extraOptions.entrySet()) {
+ gen.setPluginOption(option.getKey(), option.getValue());
+ }
+ }
+ // END KGU#396 2020-04-01
+
+ // START KGU#901 2020-12-29: Issue #901 applay WAIT_CURSOR for time-consuming actions
+ setCursor(new Cursor(Cursor.WAIT_CURSOR));
+ // END KGU#901 2020-12-29
+ File exportDir = gen.exportCode(group.getSortedRoots(), groupName,
+ targetDir,
+ NSDControl.getFrame(),
+ (Arranger.hasInstance() ? Arranger.getInstance() : null));
+
+ if (exportDir != null) {
+ this.lastCodeExportDir = exportDir;
+ }
+ } catch (Exception ex) {
+ // START KGU#901 2020-12-29: Issue #901 applay WAIT_CURSOR for time-consuming actions
+ setCursor(origCursor);
+ // END KGU#901 2020-12-29
+ String message = ex.getLocalizedMessage();
+ if (message == null) {
+ message = ex.getMessage();
+ }
+ if (message == null || message.isEmpty()) {
+ message = ex.toString();
+ }
+ JOptionPane.showMessageDialog(this.getFrame(),
+ Menu.msgErrorUsingGenerator.getText().replace("%", generatorName) + "\n" + message,
+ Menu.msgTitleError.getText(),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ // START KGU#901 2020-12-29: Issue #901 applay WAIT_CURSOR for time-consuming actions
+ finally {
+ setCursor(origCursor);
+ }
+ // END KGU#901 2020-12-29
+ }
+ // END KGU#815 2020-03-16
+
+ // START KGU#705 2019-09-23: Enh. #738: Code preview support
+ /**
+ * Place a code preview for the current diagram to the currrent favourite
+ * programming language. Also fills the {@link #codePreviewMap} with
+ * associations between {@link Element}s and line intervals.
+ *
+ * @param _specificOptions - generator-specific options
+ */
+ public void updateCodePreview() {
+ if (this.show_CODE_PREVIEW && this.codePreview != null) {
+ String generatorName = this.getPreferredGeneratorName();
+ try {
+ codePreviewMap = new HashMap();
+ Generator gen = null;
+ Arranger arranger = null;
+ if (Arranger.hasInstance()) {
+ arranger = Arranger.getInstance();
+ }
+ for (GENPlugin plugin : Menu.generatorPlugins) {
+ if (plugin.title.equals(generatorName)) {
+ Class> genClass = Class.forName(plugin.className);
+ gen = (Generator) genClass.getDeclaredConstructor().newInstance();
+ fetchPluginSpecificExportOptions(gen);
+ String code = gen.deriveCode(root,
+ NSDControl.getFrame(),
+ arranger,
+ codePreviewMap);
+ codePreview.setText(code);
+ break;
+ }
+ }
+ setCodePreviewTooltip();
+ } catch (Exception ex) {
+ String message = ex.getLocalizedMessage();
+ if (message == null) {
+ message = ex.getMessage();
+ }
+ if (message == null || message.isEmpty()) {
+ message = ex.toString();
+ }
+ JOptionPane.showMessageDialog(this.getFrame(),
+ Menu.msgErrorUsingGenerator.getText().replace("%", generatorName) + "\n" + message,
+ Menu.msgTitleError.getText(),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ // TODO Auto-generated method stub
+ highlightCodeForSelection();
+ }
+ });
+ //highlightCodeForSelection();
+ }
+
+ private void fetchPluginSpecificExportOptions(Generator _generator) {
+ for (GENPlugin plugin : Menu.generatorPlugins) {
+ if (plugin.className.equals(_generator.getClass().getName())) {
+ // FIXME: Improve performance here! Avoid repetitive retrieval but ensure sensitiveness to changes
+ setPluginSpecificOptions(_generator, plugin.className, plugin.options);
+ break;
+ }
+ }
+ }
+ // END KGU#705 2019-09-23
+
+ // START KGU#395 2017-05-11: Enh. #357 / Revised KGU#416 2017-06-20
+ private void setPluginSpecificOptions(IPluginClass _gen, String _generatorClassName,
+ Vector> _specificOptions) {
+ Ini ini = Ini.getInstance();
+ for (HashMap optionSpec : _specificOptions) {
+ String optionKey = optionSpec.get("name");
+ String valueStr = ini.getProperty(_generatorClassName + "." + optionKey, "");
+ Object value = null;
+ String type = optionSpec.get("type");
+ String items = optionSpec.get("items");
+ // Now convert the option into the specified type
+ if (!valueStr.isEmpty() && type != null || items != null) {
+ // Better we fail with just a single option than with the entire method
+ try {
+ if (items != null) {
+ value = valueStr;
+ } else if (type.equalsIgnoreCase("character")) {
+ value = valueStr.charAt(0);
+ } else if (type.equalsIgnoreCase("boolean")) {
+ value = Boolean.parseBoolean(valueStr);
+ } else if (type.equalsIgnoreCase("int") || type.equalsIgnoreCase("integer")) {
+ value = Integer.parseInt(valueStr);
+ } else if (type.equalsIgnoreCase("unsigned")) {
+ value = Integer.parseUnsignedInt(valueStr);
+ } else if (type.equalsIgnoreCase("double") || type.equalsIgnoreCase("float")) {
+ value = Double.parseDouble(valueStr);
+ } else if (type.equalsIgnoreCase("string")) {
+ value = valueStr;
+ }
+ } catch (NumberFormatException ex) {
+ String message = ex.getMessage();
+ if (message == null || message.isEmpty()) {
+ message = ex.toString();
+ }
+ logger.log(Level.SEVERE, "{0}: {1} on converting \"{2}\" to {3} for {4}",
+ new Object[]{
+ _gen.getClass().getSimpleName(),
+ message,
+ valueStr,
+ type,
+ optionKey});
+ }
+ }
+ if (value != null) {
+ _gen.setPluginOption(optionKey, value);
+ }
+ }
+ }
+ // END KGU#395 2017-05-11
+
+ // START KGU#208 2016-07-22: Enh. #199
+ /*========================================
+ * help method
+ *========================================*/
+ /**
+ * Tries to open the online User Guide in the browser
+ */
+ public void helpNSD() {
+ // START KGU#563 2018-07-26: Issue #566
+ //String help = "http://help.structorizer.fisch.lu/index.php";
+ String help = Element.E_HELP_PAGE;
+ // END KGU#563 2018-07-26
+ boolean isLaunched = false;
+ try {
+ isLaunched = lu.fisch.utils.Desktop.browse(new URI(help));
+ } catch (URISyntaxException ex) {
+ // START KGU#484 2018-04-05: Issue #463
+ //ex.printStackTrace();
+ logger.log(Level.WARNING, "Can't browse help URL.", ex);
+ // END KGU#484 2018-04-05
+ }
+ // START KGU 2018-12-24
+ // The isLaunched mechanism above does not signal an unavailable help page.
+ // With the following code we can find out whether the help page was available...
+ // TODO In this case we might offer to download the PDF for offline use,
+ // otherwise we could try to open a possibly previously downloaded PDF ...
+ URL url;
+ HttpsURLConnection con = null;
+ try {
+ isLaunched = false;
+ url = new URL(help);
+ con = (HttpsURLConnection) url.openConnection();
+ if (con != null) {
+ con.connect();
+ }
+ isLaunched = true;
+ } catch (SocketTimeoutException ex) {
+ logger.log(Level.WARNING, "Timeout connecting to " + help, ex);
+ } catch (MalformedURLException e1) {
+ logger.log(Level.SEVERE, "Malformed URL " + help, e1);
+ } catch (IOException e) {
+ logger.log(Level.WARNING, "Failed Access to " + help, e);
+ } finally {
+ if (con != null) {
+ con.disconnect();
+ }
+ }
+ // END KGU 2018-12-24
+ if (!isLaunched) {
+ String message = Menu.msgBrowseFailed.getText().replace("%", help);
+ boolean offlineShown = this.showHelpPDF();
+ if (offlineShown) {
+ message += "\n\n" + Menu.msgShowingOfflineGuide.getText();
+ }
+ JOptionPane.showMessageDialog(null,
+ message,
+ Menu.msgTitleURLError.getText(),
+ offlineShown ? JOptionPane.WARNING_MESSAGE : JOptionPane.ERROR_MESSAGE);
+ // TODO We might look for a downloaded PDF version and offer to open this instead...
+
+ }
+ else {
+ // Download the current PDF version if there hasn't been any by now.
+ this.downloadHelpPDF(false, null);
+ }
+ }
+ // END KGU#208 2016-07-22
+
+ // START KGU#791 2010-10-20: Issue #801 - we need a background thread for explicit download
+ private boolean helpDownloadCancelled = false;
+
+ /**
+ * Tries to download the most recent user guide as PDF in a backround thread
+ * with progress bar. Will override a possibly existing file.
+ *
+ * @param title - the menu item caption to be used as window title
+ */
+ public void downloadHelpPDF(String title) {
+ SwingWorker worker = new SwingWorker() {
+
+ @Override
+ protected Boolean doInBackground() throws Exception {
+ return downloadHelpPDF(true, this);
+ }
+
+ public void done() {
+ if (isCancelled()) {
+ // We must tell method downloadHelpPDF that the task was aborted
+ // (The possibly incompletely transferred file must be deleted.)
+ helpDownloadCancelled = true;
+ }
+ }
+
+ };
+ new DownloadMonitor(getFrame(), worker, title, Element.E_HELP_FILE_SIZE);
+ }
+ // END KGU#791 2020-10-20
+
+ // START KGU#791 2020-01-20: Enh. #801 support offline help
+ /**
+ * Tries to download the PDF version of the user guide to the ini directory
+ *
+ * @param overrideExisting - if an existing user guide file is to be
+ * overriden by the newest one
+ * @param worker - if given then the transfer chunks are chosen smaller and
+ * a regular progress message will be sent
+ * @return true if the download was done and successful.
+ */
+ public boolean downloadHelpPDF(boolean overrideExisting, SwingWorker worker) {
+ /* See https://stackoverflow.com/questions/921262/how-to-download-and-save-a-file-from-internet-using-java
+ * for technical discussion
+ */
+ // KGU#791 2020-10-20 Method revised to allow running in a backround thread
+ helpDownloadCancelled = false;
+ String helpFileName = Element.E_HELP_FILE;
+ File helpDir = Ini.getIniDirectory(true);
+ File helpFile = new File(helpDir.getAbsolutePath() + File.separator + helpFileName);
+ String helpFileURI = Element.E_DOWNLOAD_PAGE + "?file=" + helpFileName;
+ boolean overwritten = false;
+ long copiedTotal = 0;
+ long chunk = (worker == null) ? Integer.MAX_VALUE : 1 << 16;
+ try {
+ URL website = new URL(helpFileURI);
+ if (!helpFile.exists() || overrideExisting) {
+ try ( InputStream inputStream = website.openStream(); ReadableByteChannel readableByteChannel = Channels.newChannel(inputStream); FileOutputStream fileOutputStream = new FileOutputStream(helpFile)) {
+ overwritten = true;
+ long copied = 0;
+ do {
+ copied = fileOutputStream.getChannel().
+ transferFrom(readableByteChannel, copiedTotal, chunk);
+ if (worker != null) {
+ worker.firePropertyChange("progress", copiedTotal, copiedTotal + copied);
+ }
+ copiedTotal += copied;
+ } while (copied > 0);
+ } catch (IOException ex) {
+ logger.log(Level.INFO, "Failed to download help file!", ex);
+ if (overrideExisting) {
+ String error = ex.getMessage();
+ if (error == null) {
+ error = ex.toString();
+ } else if (ex instanceof UnknownHostException) {
+ error = Menu.msgHostNotAvailable.getText().replace("%", error);
+ }
+ JOptionPane.showMessageDialog(null,
+ Menu.msgDownloadFailed.getText().replace("%", error),
+ Menu.msgTitleURLError.getText(),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+ } catch (MalformedURLException ex) {
+ logger.log(Level.CONFIG, helpFileURI, ex);
+ }
+ if (helpDownloadCancelled && overwritten && helpFile.exists()) {
+ helpFile.delete(); // File is likely to be defective
+ copiedTotal = 0;
+ }
+ //System.out.println("Leaving downloadHelpPDF()");
+ return copiedTotal > 0;
+ }
+
+ /**
+ * Tries to present a downloaded PDF version of the user guide from the ini
+ * directory.
+ *
+ * @return true if a user guide file is present and could be shown.
+ */
+ private boolean showHelpPDF() {
+ String helpFileName = Element.E_HELP_FILE;
+ File helpDir = Ini.getIniDirectory(true);
+ File helpFile = new File(helpDir.getAbsolutePath() + File.separator + helpFileName);
+ if (helpFile.canRead()) {
+ return Desktop.open(helpFile);
+ }
+ return false;
+ }
+ // END KGU#791 2020-01-20
+
+ /*========================================
+ * update method
+ *========================================*/
+ /**
+ * Shows an info box with the link to the download page of Structorizer and
+ * informs whether there is a newer version available.
+ *
+ * @see #updateNSD(boolean)
+ */
+ public void updateNSD() // START KGU#300 2016-12-02: Enh. #300
+ {
+ updateNSD(true);
+ }
+
+ /**
+ * Checks the availability of a newer version on the download page and shows
+ * an info box with the link to the download page of Structorizer if a new
+ * version is available or {@code evenWithoutNewerVersion} is true.
+ *
+ * @param evenWithoutNewerVersion - whether the infor box is always to be
+ * popped up.
+ * @see #updateNSD()
+ */
+ public void updateNSD(boolean evenWithoutNewerVersion) // END KGU#300 2016-12-02
+ {
+ // KGU#35 2015-07-29: Bob's code adopted with slight modification (Homepage URL put into a variable)
+ // START KGU#563 2018-07-26: Issue #566
+ //final String home = "https://structorizer.fisch.lu";
+ final String home = Element.E_HOME_PAGE;
+ // END KGU#563 2018-07-26
+
+ // START KGU#300 2016-12-02: Enh. #300
+ String latestVersion = getLatestVersionIfNewer();
+ if (!evenWithoutNewerVersion && latestVersion == null) {
+ return;
+ }
+ // END KGU#300 2016-12-02
+
+ try {
+ // START KGU#247 2016-09-17: Issue #243/#245 Translation support for update window content
+ //JEditorPane ep = new JEditorPane("text/html","Goto " + home + " to look for updates
and news about Structorizer.");
+ String fontAttr = "";
+ double scaleFactor = Double.valueOf(Ini.getInstance().getProperty("scaleFactor", "1"));
+ if (scaleFactor > 1) {
+ int fontSize = (int) (3 * scaleFactor);
+ fontAttr = " size=" + fontSize;
+ }
+ // START KGU#300 2016-12-02: Enh. #300
+ String versionInfo = "";
+ if (latestVersion != null) {
+ versionInfo = Menu.msgNewerVersionAvail.getText().replace("%", latestVersion) + "
";
+ }
+ // END KGU#300 2016-12-02
+ JEditorPane ep = new JEditorPane("text/html", ""
+ + // START KGU#300 2016-12-02: Enh. #300
+ versionInfo
+ + // END KGU#300 2016-12-02
+ Menu.msgGotoHomepage.getText().replace("%", "" + home + "")
+ + "");
+ // END KGU#247 2016-09-17
+ ep.addHyperlinkListener(new HyperlinkListener() {
+ @Override
+ public void hyperlinkUpdate(HyperlinkEvent evt) {
+ if (evt.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) {
+ // START KGU#250 2016-09-17: Issue #245 (defective Linux integration workaround)
+ //try {
+ // Desktop.getDesktop().browse(evt.getURL().toURI());
+ //}
+ //catch(Exception ex)
+ //{
+ // ex.printStackTrace();
+ //}
+ String errorMessage = null;
+ try {
+ if (!lu.fisch.utils.Desktop.browse(evt.getURL().toURI())) {
+ errorMessage = Menu.msgBrowseFailed.getText().replace("%", evt.getURL().toString());
+ };
+ } catch (Exception ex) {
+ // START KGU#484 2018-04-05: Issue #463
+ //ex.printStackTrace();
+ logger.log(Level.WARNING, "Defective homepage link.", ex);
+ // END KGU#484 2018-04-05
+ errorMessage = ex.getLocalizedMessage();
+ if (errorMessage == null) {
+ errorMessage = ex.getMessage();
+ }
+ if (errorMessage == null || errorMessage.isEmpty()) {
+ errorMessage = ex.toString();
+ }
+ }
+ if (errorMessage != null) {
+ JOptionPane.showMessageDialog(null,
+ errorMessage,
+ Menu.msgTitleURLError.getText(),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ // END KGU#250 2016-09-17
+ }
+ }
+ });
+ ep.setEditable(false);
+ JLabel label = new JLabel();
+ ep.setBackground(label.getBackground());
+
+ JOptionPane.showMessageDialog(this.getFrame(), ep);
+ } catch (Exception e) {
+ // START KGU#484 2018-04-05: Issue #463
+ //e.printStackTrace();
+ logger.log(Level.WARNING, "Trouble accessing homepage.", e);
+ // END KGU#484 2018-04-05
+ }
+ }
+
+ // START KGU#300 2016-12-02 Enh. #300 Support for version retrieval
+ /**
+ * Helper method for {@link #updateNSD()}
+ *
+ * @return the version string, e.g. "3.29-14", of the latest version
+ * available or null, depending on whether online version retrieval is
+ * enabled by {@link #retrieveVersion}.
+ */
+ private String retrieveLatestVersion() {
+ // START KGU#563 2018-07-26: Issue #566
+ //final String http_url = "https://structorizer.fisch.lu/version.txt";
+ final String http_url = Element.E_HOME_PAGE + "/version.txt";
+ // END KGU#563 2018-07-26
+
+ String version = null;
+ if (retrieveVersion) {
+ try {
+
+ URL url = new URL(http_url);
+ HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
+
+ if (con != null) {
+
+ BufferedReader br
+ = new BufferedReader(
+ new InputStreamReader(con.getInputStream()));
+
+ String input;
+ while ((input = br.readLine()) != null && version == null) {
+ if (input.matches("\\d+\\.\\d+([-.][0-9]+)?")) {
+ version = input;
+ }
+ }
+ br.close();
+
+ }
+
+ } catch (MalformedURLException e) {
+ logger.severe(e.toString());
+ } catch (IOException e) {
+ logger.warning(e.toString());
+ }
+ }
+ return version;
+ }
+
+// START KGU#300 2016-12-06: Not actually needed
+// private static int[] splitVersionString(String version)
+// {
+// StringList versionParts = StringList.explode(version, "\\.");
+// versionParts = StringList.explode(versionParts, "-");
// int[] versionNumbers = new int[versionParts.count()];
// for (int i = 0; i < versionParts.count(); i++) {
// try {
@@ -7920,1922 +7781,1865 @@ private String retrieveLatestVersion() {
// }
// return versionNumbers;
// }
- // END KGU#300 2016-12-06
- /**
- * @return the version string, e.g. "3.30-05", of the latest version more
- * adavanced than the currently running version if online version retrieval
- * is enabled ({@link #retrieveVersion}) and a newer version is available;
- * null otherwise.
- */
- public String getLatestVersionIfNewer() {
- int cmp = 0;
- String latestVerStr = retrieveLatestVersion();
- if (latestVerStr != null) {
- // START KGU#300 2016-12-06: The lexicographic comparison is quite perfect here
-// int[] thisVersion = splitVersionString(Element.E_VERSION);
-// int[] currVersion = splitVersionString(latestVerStr);
-// int minLen = Math.min(thisVersion.length, currVersion.length);
-// for (int i = 0; i < minLen && cmp == 0; i++) {
-// if (currVersion[i] < thisVersion[i]) {
-// cmp = -1;
-// }
-// else if (currVersion[i] > thisVersion[i]) {
-// cmp = 1;
-// }
-// }
-// if (cmp == 0 && minLen < currVersion.length) {
-// cmp = 1;
-// }
- cmp = latestVerStr.compareTo(Element.E_VERSION);
- // END KGU#300 2016-12-06
- }
- return (cmp > 0 ? latestVerStr : null);
- }
-
- public void setRetrieveVersion(boolean _retrieveVersion) {
- retrieveVersion = _retrieveVersion;
- // START KGU#792 2020-02-04: Bugfix #805
- Ini.getInstance().setProperty("retrieveVersion", Boolean.toString(Diagram.retrieveVersion));
- // END KGU#792 2020-02-04
- }
- // END KGU#300 2016-12-02
-
- /*========================================
+// END KGU#300 2016-12-06
+
+ /**
+ * @return the version string, e.g. "3.30-05", of the latest version more
+ * adavanced than the currently running version if online version retrieval
+ * is enabled ({@link #retrieveVersion}) and a newer version is available;
+ * null otherwise.
+ */
+ public String getLatestVersionIfNewer() {
+ int cmp = 0;
+ String latestVerStr = retrieveLatestVersion();
+ if (latestVerStr != null) {
+ // START KGU#300 2016-12-06: The lexicographic comparison is quite perfect here
+ // int[] thisVersion = splitVersionString(Element.E_VERSION);
+ // int[] currVersion = splitVersionString(latestVerStr);
+ // int minLen = Math.min(thisVersion.length, currVersion.length);
+ // for (int i = 0; i < minLen && cmp == 0; i++) {
+ // if (currVersion[i] < thisVersion[i]) {
+ // cmp = -1;
+ // }
+ // else if (currVersion[i] > thisVersion[i]) {
+ // cmp = 1;
+ // }
+ // }
+ // if (cmp == 0 && minLen < currVersion.length) {
+ // cmp = 1;
+ // }
+ cmp = latestVerStr.compareTo(Element.E_VERSION);
+ // END KGU#300 2016-12-06
+ }
+ return (cmp > 0 ? latestVerStr : null);
+ }
+
+ public void setRetrieveVersion(boolean _retrieveVersion) {
+ retrieveVersion = _retrieveVersion;
+ // START KGU#792 2020-02-04: Bugfix #805
+ Ini.getInstance().setProperty("retrieveVersion", Boolean.toString(Diagram.retrieveVersion));
+ // END KGU#792 2020-02-04
+ }
+ // END KGU#300 2016-12-02
+
+ /*========================================
* the preferences dialog methods
*========================================*/
- /**
- * Opens the colour configuration dialog and processes configuration
- * changes.
- */
- public void colorsNSD() {
- // START KGU#245 2018-07-02: Converted to arrays
- //Colors colors = new Colors(NSDControl.getFrame());
- Colors colors = new Colors(NSDControl.getFrame(), Element.colors.length);
- // END KGU#245 2018-07-02
- Point p = getLocationOnScreen();
- colors.setLocation(Math.round(p.x + (getVisibleRect().width - colors.getWidth()) / 2 + this.getVisibleRect().x),
- Math.round(p.y + (getVisibleRect().height - colors.getHeight()) / 2 + this.getVisibleRect().y));
-
- // set fields
- // START KGU#245 2018-07-02: Converted to arrays
-// colors.color0.setBackground(Element.color0);
-// colors.color1.setBackground(Element.color1);
-// colors.color2.setBackground(Element.color2);
-// colors.color3.setBackground(Element.color3);
-// colors.color4.setBackground(Element.color4);
-// colors.color5.setBackground(Element.color5);
-// colors.color6.setBackground(Element.color6);
-// colors.color7.setBackground(Element.color7);
-// colors.color8.setBackground(Element.color8);
-// colors.color9.setBackground(Element.color9);
- for (int i = 0; i < Element.colors.length; i++) {
- colors.colors[i].setBackground(Element.colors[i]);
- }
- // END KGU#245 2018-07-02
-
- colors.pack();
- colors.setVisible(true);
-
- // START KGU#393 2017-05-09: Issue #400 - check whether changes were committed
- if (colors.OK) {
- // END KGU#393 2017-05-09
- // get fields
- // START KGU#245 2018-07-02: Converted to arrays
-// Element.color0=colors.color0.getBackground();
-// Element.color1=colors.color1.getBackground();
-// Element.color2=colors.color2.getBackground();
-// Element.color3=colors.color3.getBackground();
-// Element.color4=colors.color4.getBackground();
-// Element.color5=colors.color5.getBackground();
-// Element.color6=colors.color6.getBackground();
-// Element.color7=colors.color7.getBackground();
-// Element.color8=colors.color8.getBackground();
-// Element.color9=colors.color9.getBackground();
- for (int i = 0; i < Element.colors.length; i++) {
- Element.colors[i] = colors.colors[i].getBackground();
- }
- // END KGU#245 2018-07-02
-
- NSDControl.updateColors();
-
- // save fields to ini-file
- Element.saveToINI();
- // START KGU#393 2017-05-09: Issue #400
- }
- // END KGU#393 2017-05-09
-
- }
-
- /**
- * Opens the structure prefereneces dialog and processes configuration
- * changes.
- */
- public void preferencesNSD() {
- Preferences preferences = new Preferences(NSDControl.getFrame());
- Point p = getLocationOnScreen();
- preferences.setLocation(Math.round(p.x + (getVisibleRect().width - preferences.getWidth()) / 2 + this.getVisibleRect().x),
- Math.round(p.y + (getVisibleRect().height - preferences.getHeight()) / 2 + this.getVisibleRect().y));
-
- // set fields
- preferences.edtAltT.setText(Element.preAltT);
- preferences.edtAltF.setText(Element.preAltF);
- preferences.edtAlt.setText(Element.preAlt);
- preferences.txtCase.setText(Element.preCase);
- preferences.edtFor.setText(Element.preFor);
- preferences.edtWhile.setText(Element.preWhile);
- preferences.edtRepeat.setText(Element.preRepeat);
-
- preferences.altPadRight.setSelected(Element.altPadRight);
-
- // START KGU#401 2017-05-18: Issue #405 - allow to reduce CASE width by branch element rotation
- preferences.spnCaseRot.setValue(Element.caseShrinkByRot);
- // END KGU#401 2017-05-18
- // START KGU#376 2017-07-02: Enh. #389
- preferences.edtRoot.setText(Element.preImport);
- // END KGU#376 2017-07-02
- // START KGU#916 2021-01-25: Enh. #915
- preferences.chkCaseEditor.setSelected(Element.useInputBoxCase);
- // END KGU#916 2021-01-25
-
- // START KGU#686 2019-03-22: Enh. #56
- preferences.edtTry.setText(Element.preTry);
- preferences.edtCatch.setText(Element.preCatch);
- preferences.edtFinal.setText(Element.preFinally);
- // END KGU#686 2019-03-22
-
- preferences.pack();
- preferences.setVisible(true);
-
- // START KGU#393 2017-05-09: Issue #400 - check whether changes were committed
- if (preferences.OK) {
- // END KGU#393 2017-05-09
- // START KGU#491 2018-02-09: Bugfix #507 - if branch labels change we force reshaping
- boolean mustInvalidateAlt
- = !Element.preAltT.equals(preferences.edtAltT.getText())
- || !Element.preAltF.equals(preferences.edtAltF.getText());
- // END KGU#491 2018-02-09
- // get fields
- Element.preAltT = preferences.edtAltT.getText();
- Element.preAltF = preferences.edtAltF.getText();
- Element.preAlt = preferences.edtAlt.getText();
- Element.preCase = preferences.txtCase.getText();
- Element.preFor = preferences.edtFor.getText();
- Element.preWhile = preferences.edtWhile.getText();
- Element.preRepeat = preferences.edtRepeat.getText();
- Element.altPadRight = preferences.altPadRight.isSelected();
- // START KGU#686 2019-03-22: Enh. #56
- Element.preTry = preferences.edtTry.getText();
- Element.preCatch = preferences.edtCatch.getText();
- Element.preFinally = preferences.edtFinal.getText();
- // END KGU#686 2019-03-22
- // START KGU#376 2017-07-02: Enh. #389
- String newImportCaption = preferences.edtRoot.getText();
- // END KGU#376 2017-07-02
- // START KGU#401 2017-05-18: Issue #405 - allow to reduce CASE width by branch element rotation
- int newShrinkThreshold = (Integer) preferences.spnCaseRot.getModel().getValue();
- //if (newShrinkThreshold != Element.caseShrinkByRot) {
- if (newShrinkThreshold != Element.caseShrinkByRot
- // START KGU#491 2019-02-09: Bugfix #507
- || mustInvalidateAlt
- // END KGU#491 2019-02-09
- || !newImportCaption.equals(Element.preImport)) {
- root.resetDrawingInfoDown();
- }
- Element.caseShrinkByRot = newShrinkThreshold;
- // END KGU#401 2017-05-18
- // START KGU#916 2021-01-25: Enh. #915
- Element.useInputBoxCase = preferences.chkCaseEditor.isSelected();
- // END KGU#916 2021-01-25
- // START KGU#376 2017-07-02: Enh. #389
- Element.preImport = preferences.edtRoot.getText();
- // END KGU#376 2017-07-02
-
- // save fields to ini-file
- Element.saveToINI();
- redraw();
- // START KGU#393 2017-05-09: Issue #400
- }
- // END KGU#393 2017-05-09
- }
-
- /**
- * Opens the parser preferences dialog and processes configuration changes.
- */
- public void parserNSD() {
- ParserPreferences parserPreferences = new ParserPreferences(NSDControl.getFrame());
- Point p = getLocationOnScreen();
- parserPreferences.setLocation(Math.round(p.x + (getVisibleRect().width - parserPreferences.getWidth()) / 2 + this.getVisibleRect().x),
- Math.round(p.y + (getVisibleRect().height - parserPreferences.getHeight()) / 2 + this.getVisibleRect().y));
-
- // set fields
- parserPreferences.edtAltPre.setText(CodeParser.getKeyword("preAlt"));
- parserPreferences.edtAltPost.setText(CodeParser.getKeyword("postAlt"));
- parserPreferences.edtCasePre.setText(CodeParser.getKeyword("preCase"));
- parserPreferences.edtCasePost.setText(CodeParser.getKeyword("postCase"));
- parserPreferences.edtForPre.setText(CodeParser.getKeyword("preFor"));
- parserPreferences.edtForPost.setText(CodeParser.getKeyword("postFor"));
- // START KGU#3 2015-11-08: New configurable separator for FOR loop step const
- parserPreferences.edtForStep.setText(CodeParser.getKeyword("stepFor"));
- // END KGU#3 2015-11-08
- // START KGU#61 2016-03-21: New configurable keywords for FOR-IN loop
- parserPreferences.edtForInPre.setText(CodeParser.getKeyword("preForIn"));
- parserPreferences.edtForInPost.setText(CodeParser.getKeyword("postForIn"));
- // END KGU#61 2016-03-21
- parserPreferences.edtWhilePre.setText(CodeParser.getKeyword("preWhile"));
- parserPreferences.edtWhilePost.setText(CodeParser.getKeyword("postWhile"));
- parserPreferences.edtRepeatPre.setText(CodeParser.getKeyword("preRepeat"));
- parserPreferences.edtRepeatPost.setText(CodeParser.getKeyword("postRepeat"));
- // START KGU#78 2016-03-25: Enh. #23 - Jump configurability introduced
- parserPreferences.edtJumpLeave.setText(CodeParser.getKeyword("preLeave"));
- parserPreferences.edtJumpReturn.setText(CodeParser.getKeyword("preReturn"));
- parserPreferences.edtJumpExit.setText(CodeParser.getKeyword("preExit"));
- // END KGU#78 2016-03-25
- // START KGU#686 2019-03-18: Enh. #56 - Try / Carch / Throw mechanism implemented
- parserPreferences.edtJumpThrow.setText(CodeParser.getKeyword("preThrow"));
- // END KGU#686 2019-03-18
- parserPreferences.edtInput.setText(CodeParser.getKeyword("input"));
- parserPreferences.edtOutput.setText(CodeParser.getKeyword("output"));
- // START KGU#165 2016-03-25: We need a transparent decision here
- parserPreferences.chkIgnoreCase.setSelected(CodeParser.ignoreCase);
- // END KGU#165 2016-03-25
-
- parserPreferences.pack();
- parserPreferences.setVisible(true);
-
- if (parserPreferences.OK) {
- // START KGU#258 2016-09-26: Enh. #253 - prepare the old settings for a refactoring
- HashMap oldKeywordMap = null;
- boolean wasCaseIgnored = CodeParser.ignoreCase;
- boolean considerRefactoring = root.children.getSize() > 0
- || isArrangerOpen() && Arranger.getInstance().getAllRoots().size() > 0;
-// if (considerRefactoring)
-// {
- oldKeywordMap = new LinkedHashMap();
- for (String key : CodeParser.keywordSet()) {
- // START KGU#288 2016-11-06: Issue #279 - method getOrDefault may not be available
- //String keyword = CodeParser.keywordMap.getOrDefault(key, "");
- //if (!keyword.trim().isEmpty())
- String keyword = CodeParser.getKeyword(key);
- if (keyword != null && !keyword.trim().isEmpty()) // END KGU#288 2016-11-06
- {
- // Complete strings aren't likely to be found in a key, so don't bother
- oldKeywordMap.put(key, Element.splitLexically(keyword, false));
- }
- }
-// }
- // END KGU#258 2016-09-26
-
- // get fields
- CodeParser.setKeyword("preAlt", parserPreferences.edtAltPre.getText());
- CodeParser.setKeyword("postAlt", parserPreferences.edtAltPost.getText());
- CodeParser.setKeyword("preCase", parserPreferences.edtCasePre.getText());
- CodeParser.setKeyword("postCase", parserPreferences.edtCasePost.getText());
- CodeParser.setKeyword("preFor", parserPreferences.edtForPre.getText());
- CodeParser.setKeyword("postFor", parserPreferences.edtForPost.getText());
- // START KGU#3 2015-11-08: New configurable separator for FOR loop step const
- CodeParser.setKeyword("stepFor", parserPreferences.edtForStep.getText());
- // END KGU#3 2015-11-08
- // START KGU#61 2016-03-21: New configurable keywords for FOR-IN loop
- CodeParser.setKeyword("preForIn", parserPreferences.edtForInPre.getText());
- CodeParser.setKeyword("postForIn", parserPreferences.edtForInPost.getText());
- // END KGU#61 2016-03-21
- CodeParser.setKeyword("preWhile", parserPreferences.edtWhilePre.getText());
- CodeParser.setKeyword("postWhile", parserPreferences.edtWhilePost.getText());
- CodeParser.setKeyword("preRepeat", parserPreferences.edtRepeatPre.getText());
- CodeParser.setKeyword("postRepeat", parserPreferences.edtRepeatPost.getText());
- // START KGU#78 2016-03-25: Enh. #23 - Jump configurability introduced
- CodeParser.setKeyword("preLeave", parserPreferences.edtJumpLeave.getText());
- CodeParser.setKeyword("preReturn", parserPreferences.edtJumpReturn.getText());
- CodeParser.setKeyword("preExit", parserPreferences.edtJumpExit.getText());
- // END KGU#78 2016-03-25
- // START KGU#686 2019-03-18: Enh. #56 - Try / Carch / Throw mechanism implemented
- CodeParser.setKeyword("preThrow", parserPreferences.edtJumpThrow.getText());
- // END KGU#686 2019-03-18
- CodeParser.setKeyword("input", parserPreferences.edtInput.getText());
- CodeParser.setKeyword("output", parserPreferences.edtOutput.getText());
- // START KGU#165 2016-03-25: We need a transparent decision here
- CodeParser.ignoreCase = parserPreferences.chkIgnoreCase.isSelected();
- // END KGU#165 2016-03-25
-
- // save fields to ini-file
- CodeParser.saveToINI();
-
- // START KGU#258 2016-09-26: Enh. #253 - now try a refactoring if specified
- boolean redrawn = false;
- if (considerRefactoring && offerRefactoring(oldKeywordMap)) {
- boolean refactorAll = oldKeywordMap.containsKey("refactorAll");
- redrawn = refactorDiagrams(oldKeywordMap, refactorAll, wasCaseIgnored);
- }
- // END KGU#258 2016-09-26
-
- // START KGU#362 2017-03-28: Issue #370
- offerStructPrefAdaptation(oldKeywordMap);
- // END KGU#362 2017-03-28
-
- // START KGU#136 2016-03-31: Bugfix #97 - cached bounds may have to be invalidated
- if (Element.E_VARHIGHLIGHT && !redrawn) {
- // Parser keyword changes may have an impact on the text width ...
- this.resetDrawingInfo();
-
- // START KGU#258 2016-09-26: Bugfix #253 ... and Jumps and loops
- analyse();
- // END KGU#258 2016-09-26
-
- // redraw diagram
- redraw();
- }
- // END KGU#136 2016-03-31
-
- // STAR KGU#705 2019-09-29: Enh. #738
- updateCodePreview();
- // END KGU#705 2019-09-29
- }
- }
-
- // START KGU#258 2016-09-26: Enh. #253: A set of helper methods for refactoring
- /**
- * (To be called after a preference file has been loaded explicitly on user
- * demand.) Based on the refactoringData collected before the loading, a
- * difference analysis between the old and new parser preferences will be
- * done. If changes are detected and there are non-trivial Roots then a
- * dialog box will be popped up showing the changes and offering to refactor
- * the current or all diagrams. If the user agrees then the respective code
- * will be added to the refactoringData and true will be returned, otherwise
- * false. If the user cancels then the original parser preferences will be
- * restored and false will be returned.
- *
- * @param refactoringData - tokenized previous non-empty parser preferences
- * @return true if a refactoring makes sense, false otherwise
- */
- public boolean offerRefactoring(HashMap refactoringData) {
- // Since this method is always called after a preference file has been loaded,
- // we update the preferred export code for the doButtons() call, though it
- // has nothing to do with refactoring
- this.prefGeneratorName = Ini.getInstance().getProperty("genExportPreferred", this.prefGeneratorName);
-
- // No refectoring data was collected then we are done here ...
- if (refactoringData == null) {
- return false;
- }
-
- // Otherwise we look for differences between old and new parser preferences
- // START KGU#719 2019-08-01: New layout for the refactoring dialog
- //StringList replacements = new StringList();
- List replacements = new LinkedList();
- // END KGU#719 2019-08-1
- for (HashMap.Entry entry : refactoringData.entrySet()) {
- String oldValue = entry.getValue().concatenate();
- // START KGU#288 2016-11-06: Issue #279 - Method getOrDefault() missing in OpenJDK
- //String newValue = CodeParser.getKeywordOrDefault(entry.getKey(), "");
- String newValue = CodeParser.getKeywordOrDefault(entry.getKey(), "");
- // END KGU#288 2016-11-06
- if (!oldValue.equals(newValue)) {
- // START KGU#719 2019-08-01: New layout for the refactoring dialog
- //replacements.add(" " + entry.getKey() + ": \"" + oldValue + "\" -> \"" + newValue + "\"");
- replacements.add(new String[]{entry.getKey(), "\"" + oldValue + "\"", "\"" + newValue + "\""});
- // END KGU#719 2019-08-01
- }
- }
- // Only offer the question if there are relevant replacements and at least one non-empty or parked Root
- // START KGU#719 2019-08-01
- if (!replacements.isEmpty() && (root.children.getSize() > 0 || isArrangerOpen() && !Arranger.getInstance().getAllRoots().isEmpty())) // END KGU#719 2019-08-01
- {
- String[] options = {
- Menu.lblRefactorNone.getText(),
- Menu.lblRefactorCurrent.getText(),
- Menu.lblRefactorAll.getText()
- };
- // START KGU#719 2019-08-01: New layout
- JTable replTable = new JTable(0, 3);
- for (String[] tupel : replacements) {
- ((DefaultTableModel) replTable.getModel()).addRow(tupel);
- }
- for (int col = 0; col < Math.min(replTable.getColumnCount(), Menu.hdrRefactoringTable.length); col++) {
- replTable.getColumnModel().getColumn(col).setHeaderValue(Menu.hdrRefactoringTable[col].getText());
- }
- Box box = Box.createVerticalBox();
- Box box1 = Box.createHorizontalBox();
- Box box2 = Box.createHorizontalBox();
- box1.add(new JLabel(Menu.msgRefactoringOffer1.getText()));
- box1.add(Box.createHorizontalGlue());
- box2.add(new JLabel(Menu.msgRefactoringOffer2.getText()));
- box2.add(Box.createHorizontalGlue());
- box.add(box1);
- box.add(Box.createVerticalStrut(5));
- box.add(replTable.getTableHeader());
- box.add(replTable);
- box.add(Box.createVerticalStrut(10));
- box.add(box2);
- replTable.setEnabled(false);
- replTable.setRowHeight((int) (replTable.getRowHeight() * Double.valueOf(Ini.getInstance().getProperty("scaleFactor", "1"))));
- // END KGU#719 2019-08-01
- // START KGU#362 2017-03-28: Issue #370: Restore old settings if user backed off
- //int answer = JOptionPane.showOptionDialog(this,
- // Menu.msgRefactoringOffer.getText().replace("%", "\n" + replacements.getText() + "\n"),
- // Menu.msgTitleQuestion.getText(), JOptionPane.OK_CANCEL_OPTION,
- // JOptionPane.QUESTION_MESSAGE,
- // null,
- // options, options[0]);
- //if (answer != 0 && answer != JOptionPane.CLOSED_OPTION)
- int answer = JOptionPane.CLOSED_OPTION;
- do {
- answer = JOptionPane.showOptionDialog(this.getFrame(),
- // START KGU#719 2019-08-01
- //Menu.msgRefactoringOffer.getText().replace("%", "\n" + replacements.getText() + "\n"),
- box,
- // END KGU#719 2019-08-01
- Menu.msgTitleQuestion.getText(), JOptionPane.OK_CANCEL_OPTION,
- JOptionPane.QUESTION_MESSAGE,
- null,
- options, options[2]);
- if (answer == JOptionPane.CLOSED_OPTION && JOptionPane.showConfirmDialog(this.getFrame(),
- Menu.msgDiscardParserPrefs.getText()) == JOptionPane.OK_OPTION) {
- // Revert the changes
- for (Map.Entry refEntry : refactoringData.entrySet()) {
- CodeParser.setKeyword(refEntry.getKey(), refEntry.getValue().concatenate());
- }
- answer = 2;
- }
- } while (answer == JOptionPane.CLOSED_OPTION);
- if (answer != 0) // END KGU#362 2017-03-28
- {
- if (CodeParser.ignoreCase) {
- refactoringData.put("ignoreCase", StringList.getNew("true"));
- }
- if (answer == 2) {
- refactoringData.put("refactorAll", StringList.getNew("true"));
- }
- return true;
- }
- }
- return false;
- }
-
- // START KGU#362 2017-03-28: Issue #370 - helper methods for preference consistency
- private void offerStructPrefAdaptation(HashMap refactoringData) {
- // START KGU#735 2019-09-29: Issue #753 - first do a check to avoid puzzling questions
- //if (JOptionPane.showConfirmDialog(this.NSDControl.getFrame(),
- // Menu.msgAdaptStructPrefs.getText(), Menu.msgTitleQuestion.getText(),
- // JOptionPane.YES_NO_OPTION) == JOptionPane.OK_OPTION) {
- String updateNeed = null;
- if (((updateNeed = checkPref(Element.preAlt, refactoringData, "preAlt", "postAlt")) != null
- || (updateNeed = checkPref(Element.preWhile, refactoringData, "preWhile", "postWhile")) != null
- || (updateNeed = checkPref(Element.preRepeat, refactoringData, "preRepeat", "postRepeat")) != null
- || (updateNeed = checkPrefCase(Element.preCase, refactoringData)) != null
- || (updateNeed = checkPrefFor(Element.preFor, refactoringData)) != null)
- && JOptionPane.showConfirmDialog(this.getFrame(),
- Menu.msgAdaptStructPrefs.getText().replace("%", updateNeed), Menu.msgTitleQuestion.getText(),
- JOptionPane.YES_NO_OPTION) == JOptionPane.OK_OPTION) {
- // END KGU#735 2019-09-29
- Element.preAlt = replacePref(Element.preAlt,
- refactoringData, "preAlt", "postAlt");
- Element.preWhile = replacePref(Element.preWhile,
- refactoringData, "preWhile", "postWhile");
- Element.preRepeat = replacePref(Element.preRepeat,
- refactoringData, "preRepeat", "postRepeat");
- Element.preCase = replacePrefCase(Element.preCase,
- refactoringData);
- Element.preFor = replacePrefFor(Element.preFor,
- refactoringData);
- }
- }
-
- private String replacePref(String structPref, HashMap refactoringData,
- String prefixKey, String postfixKey) {
- StringList old = refactoringData.get(prefixKey);
- int startPos = 0;
- if (old != null) {
- String oldPrefix = old.concatenate();
- String newPrefix = CodeParser.getKeywordOrDefault(prefixKey, "");
- if (!oldPrefix.trim().isEmpty() && structPref.startsWith(oldPrefix)) {
- structPref = newPrefix + structPref.substring(oldPrefix.length());
- startPos = newPrefix.length();
- }
- }
- old = refactoringData.get(postfixKey);
- if (old != null) {
- String oldPostfix = old.concatenate();
- String newPostfix = CodeParser.getKeywordOrDefault(postfixKey, "");
- if (!oldPostfix.trim().isEmpty() && structPref.substring(startPos).endsWith(oldPostfix)) {
- structPref = structPref.substring(0, structPref.length() - oldPostfix.length()) + newPostfix;
- }
- }
- return structPref;
- }
-
- private String replacePrefCase(String preCase, HashMap refactoringData) {
- StringList structPrefLines = StringList.explode(preCase, "\n");
- String oldPrefix = "";
- String oldPostfix = "";
- String newPrefix = CodeParser.getKeywordOrDefault("preCase", "");
- String newPostfix = CodeParser.getKeywordOrDefault("postCase", "");
- StringList old = refactoringData.get("preCase");
- if (old != null) {
- oldPrefix = old.concatenate();
- }
- old = refactoringData.get("postCase");
- if (old != null) {
- oldPostfix = old.concatenate();
- }
- for (int i = 0; i < structPrefLines.count() - 1; i++) {
- String structPref = structPrefLines.get(i);
- if (!oldPrefix.trim().isEmpty() && structPref.startsWith(oldPrefix)) {
- structPref = newPrefix + structPref.substring(oldPrefix.length());
- }
- if (!oldPostfix.trim().isEmpty() && structPref.endsWith(oldPostfix)) {
- structPref = structPref.trim().substring(0, structPref.length() - oldPostfix.length()) + newPostfix;
- }
- structPrefLines.set(i, structPref);
- }
- return structPrefLines.getText();
- }
-
- private String replacePrefFor(String structPref, HashMap refactoringData) {
- String oldPrefix1 = "";
- String oldPrefix2 = "";
- String oldInfix1 = "";
- String oldInfix1a = "";
- String oldInfix2 = "";
- String newPrefix1 = CodeParser.getKeywordOrDefault("preFor", "");
- String newPrefix2 = CodeParser.getKeywordOrDefault("preForIn", "");
- String newInfix1 = CodeParser.getKeywordOrDefault("postFor", "");
- String newInfix1a = CodeParser.getKeywordOrDefault("stepFor", "");
- String newInfix2 = CodeParser.getKeywordOrDefault("postForIn", "");
- StringList old = null;
- if ((old = refactoringData.get("preFor")) != null) {
- oldPrefix1 = old.concatenate();
- }
- if ((old = refactoringData.get("preForIn")) != null) {
- oldPrefix2 = old.concatenate();
- }
- if ((old = refactoringData.get("postFor")) != null) {
- oldInfix1 = old.concatenate();
- }
- if ((old = refactoringData.get("stepFor")) != null) {
- oldInfix1a = old.concatenate();
- }
- if ((old = refactoringData.get("postForIn")) != null) {
- oldInfix2 = old.concatenate();
- }
- String tail = "";
- if (!oldPrefix1.trim().isEmpty() && !oldInfix1.trim().isEmpty()
- && structPref.startsWith(oldPrefix1) && (tail = structPref.substring(oldPrefix1.length())).contains(oldInfix1)) {
- if (tail.matches(".*?\\W+" + oldInfix1 + "\\W+.*?")) {
- tail = tail.replaceFirst("(.*?\\W+)" + oldInfix1 + "(\\W+.*?)",
- "$1" + Matcher.quoteReplacement(newInfix1) + "$2");
- }
- if (tail.matches(".*?\\W+" + oldInfix1a + "\\W+.*?")) {
- tail = tail.replaceFirst("(.*?\\W+)" + oldInfix1a + "(\\W+.*?)",
- "$1" + Matcher.quoteReplacement(newInfix1a) + "$2");
- }
- structPref = newPrefix1 + tail;
- } else if (!oldPrefix2.trim().isEmpty() && !oldInfix2.trim().isEmpty()
- && structPref.startsWith(oldPrefix2) && (tail = structPref.substring(oldPrefix2.length())).contains(oldInfix2)) {
- if (tail.matches(".*?\\W+" + oldInfix2 + "\\W+.*?")) {
- tail = tail.replaceFirst("(.*?\\W+)" + oldInfix2 + "(\\W+.*?)",
- "$1" + Matcher.quoteReplacement(newInfix2) + "$2");
- }
- structPref = newPrefix2 + tail;
- }
- return structPref;
- }
- // END KGU#362 2017-03-28
-
- // START KGU#735 2019-09-29: Issue #753 - check methods for preference consistency
- private String checkPref(String structPref, HashMap refactoringData,
- String prefixKey, String postfixKey) {
- String newPref = replacePref(structPref, refactoringData, prefixKey, postfixKey);
- if (!newPref.equals(structPref)) {
- return structPref + " --> " + newPref;
- }
- return null;
- }
-
- private String checkPrefCase(String structPref, HashMap refactoringData) {
- String newPref = replacePrefCase(structPref, refactoringData);
- if (!newPref.equals(structPref)) {
- return structPref + " --> " + newPref;
- }
- return null;
- }
-
- private String checkPrefFor(String structPref, HashMap refactoringData) {
- String newPref = replacePrefFor(structPref, refactoringData);
- if (!newPref.equals(structPref)) {
- return structPref + " --> " + newPref;
- }
- return null;
- }
- // END KGU#735 2019-09-29
-
- /**
- * Replaces used parser keywords in the specified diagrams by the keywords
- * associated to them in the keyword map {@code refactoringData}, which also
- * contains the specification whether all open diagrams are to be refactored
- * in this way or just {@link #root}.
- *
- * @param refactoringData - maps old keywords to new keywords and may
- * contain keys "refactorAll" and "ignoreCase" as mere flags.
- */
- public void refactorNSD(HashMap refactoringData) {
- if (refactoringData != null) {
- refactorDiagrams(refactoringData,
- refactoringData.containsKey("refactorAll"),
- refactoringData.containsKey("ignoreCase")
- );
- }
- }
-
- private boolean refactorDiagrams(HashMap oldKeywordMap, boolean refactorAll, boolean wasCaseIgnored) {
- boolean redrawn = false;
- if (oldKeywordMap != null && !oldKeywordMap.isEmpty()) {
- final class Refactorer implements IElementVisitor {
-
- public HashMap oldMap = null;
- boolean ignoreCase = false;
-
- @Override
- public boolean visitPreOrder(Element _ele) {
- _ele.refactorKeywords(oldMap, ignoreCase);
- return true;
- }
-
- @Override
- public boolean visitPostOrder(Element _ele) {
- return true;
- }
-
- Refactorer(HashMap _keyMap, boolean _caseIndifferent) {
- oldMap = _keyMap;
- ignoreCase = _caseIndifferent;
- }
- };
- // START KGU#362 2017-03-28: Issue #370 avoid frozen diagrams
- //root.addUndo();
- //root.traverse(new Refactorer(oldKeywordMap, wasCaseIgnored));
- if (root.storedParserPrefs == null) {
- root.addUndo();
- root.traverse(new Refactorer(oldKeywordMap, wasCaseIgnored));
- }
- // END KGU#362 2017-03-28
- if (refactorAll && isArrangerOpen()) {
- // Well, we hope that the roots won't change the hash code on refactoring...
- for (Root aRoot : Arranger.getInstance().getAllRoots()) {
- // START KGU#362 2017-03-28: Issue #370 avoid frozen diagrams
- //if (root != aRoot) {
- if (root != aRoot && aRoot.storedParserPrefs == null) {
- // END KGU#362 2017-03-28
- aRoot.addUndo();
- aRoot.traverse(new Refactorer(oldKeywordMap, wasCaseIgnored));
- }
- }
- }
-
- // Parser keyword changes may have an impact on the text width ...
- this.resetDrawingInfo();
-
- // START KGU#258 2016-09-26: Bugfix #253 ... and Jumps and loops
- analyse();
- // END KGU#258 2016-09-26
-
- doButtons();
-
- // redraw diagram
- redraw();
-
- redrawn = true;
- }
- return redrawn;
- }
- // END KGU#258 2016-09-26
-
- /**
- * Opens the Arranger Preferences dialog and processes configuration changes
- */
- public void analyserNSD() {
- AnalyserPreferences analyserPreferences = new AnalyserPreferences(NSDControl.getFrame());
- Point p = getLocationOnScreen();
- analyserPreferences.setLocation(Math.round(p.x + (getVisibleRect().width - analyserPreferences.getWidth()) / 2 + this.getVisibleRect().x),
- Math.round(p.y + (getVisibleRect().height - analyserPreferences.getHeight()) / 2 + this.getVisibleRect().y));
-
- // set fields
- // START KGU#239 2016-08-12: Code redesign (2016-09-22: index mapping modified)
- for (int i = 1; i < analyserPreferences.checkboxes.length; i++) {
- analyserPreferences.checkboxes[i].setSelected(Root.check(i));
- }
- // END KGU#239 2016-08-12
- // START KGU#906 2021-01-02: Enh. #905
- analyserPreferences.chkDrawWarningSign.setSelected(Element.E_ANALYSER_MARKER);
- // END KGU#906 2021-01-02
- // START KGU#459 2017-11-15: Enh. #459-1
- boolean hadActiveTutorials = false;
- for (int code : AnalyserPreferences.getOrderedGuideCodes()) {
- if (hadActiveTutorials = Root.check(code)) {
- break;
- }
- }
- // END KGU#459 2017-11-15
-
- analyserPreferences.pack();
- analyserPreferences.setVisible(true);
-
- // get fields
- // START KGU#393 2017-05-09: Issue #400 - check whether changes were actually committed
- if (analyserPreferences.OK) {
- // END KGU#393 2017-05-09
- // START KGU#239 2016-08-12: Code redesign (2016-09-22: index mapping modified)
- for (int i = 1; i < analyserPreferences.checkboxes.length; i++) {
- Root.setCheck(i, analyserPreferences.checkboxes[i].isSelected());
- }
- // END KGU#239 2016-08-12
- // START KGU#906 2021-01-02: Enh. #905
- boolean markersWereOn = Element.E_ANALYSER_MARKER;
- Element.E_ANALYSER_MARKER = analyserPreferences.chkDrawWarningSign.isSelected();
- // END KGU#906 2021-01-02
-
- // save fields to ini-file
- Root.saveToINI();
-
- // START KGU#456/KGU#459 2017-11-15: Enh. #452, #459-1
- updateTutorialQueues();
- if (!hadActiveTutorials) {
- for (int code : AnalyserPreferences.getOrderedGuideCodes()) {
- if (Root.check(code)) {
- showTutorialHint();
- break;
- }
- }
- }
- // END KGU#456 2017-11-15
- // re-analyse
- //root.getVarNames(); // Is done by root.analyse() itself
- analyse();
- // START KGU#906 2021-01-02: Enh. #905
- // START KGU#906 2021-02-28: Issue #905 We have to redraw on test set modifications, too
- //if (markersWereOn != Element.E_ANALYSER_MARKER) {
- if (markersWereOn || (markersWereOn != Element.E_ANALYSER_MARKER)) {
- // END KGU#906 2021-02-28
- redraw();
- }
- // END KGU#906 2021-01-02
- // START KGU#393 2017-05-09: Issue #400
- }
- // END KGU#393 2017-05-09
- }
-
- // START KGU#456 2017-11-15: Enh. #452
- protected void updateTutorialQueues() {
- int[] guideCodes = AnalyserPreferences.getOrderedGuideCodes();
- root.updateTutorialQueue(guideCodes);
- if (Arranger.hasInstance()) {
- for (Root aRoot : Arranger.getInstance().getAllRoots()) {
- aRoot.updateTutorialQueue(guideCodes);
- }
- }
- }
- // END KGU#456 2017-11-15
-
- /**
- * Opens the export options dialog and processes configuration changes.
- */
- public void exportOptions() {
- try {
- Ini ini = Ini.getInstance();
- ini.load();
- ExportOptionDialoge eod = new ExportOptionDialoge(NSDControl.getFrame(), Menu.generatorPlugins);
- if (ini.getProperty("genExportComments", "false").equals("true")) {
- eod.commentsCheckBox.setSelected(true);
- } else {
- eod.commentsCheckBox.setSelected(false);
- }
- // START KGU#16/KGU#113 2015-12-18: Enh. #66, #67
- eod.bracesCheckBox.setSelected(ini.getProperty("genExportBraces", "false").equals("true"));
- eod.lineNumbersCheckBox.setSelected(ini.getProperty("genExportLineNumbers", "false").equals("true"));
- // END KGU#16/KGU#113 2015-12-18
- // START KGU#178 2016-07-20: Enh. #160
- eod.chkExportSubroutines.setSelected(ini.getProperty("genExportSubroutines", "false").equals("true"));
- // END #178 2016-07-20
- // START KGU#162 2016-03-31: Enh. #144
- eod.noConversionCheckBox.setSelected(ini.getProperty("genExportnoConversion", "false").equals("true"));
- // END KGU#162 2016-03-31
- // START KGU#363/KGU#395 2017-05-11: Enh. #372, #357
- eod.chkExportLicenseInfo.setSelected(ini.getProperty("genExportLicenseInfo", "false").equals("true"));
- // END KGU#363/KGU#395 2017-05-11
- // START KGU#816 2020-03-17: Enh. #837
- eod.chkDirectoryFromNsd.setSelected(ini.getProperty("genExportDirFromNsd", "true").equals("true"));
- // END KGU#816 2020-03-17
- // START KGU#854 2020-04-22: Enh. #855
- eod.chkArraySize.setSelected(ini.getProperty("genExportUseArraySize", "false").equals("true"));
- eod.chkStringLen.setSelected(ini.getProperty("genExportUseStringLen", "false").equals("true"));
- eod.spnArraySize.setValue(Integer.parseUnsignedInt(ini.getProperty("genExportArraySizeDefault", "100")));
- eod.spnStringLen.setValue(Integer.parseUnsignedInt(ini.getProperty("genExportStringLenDefault", "256")));
- // END KGU#854 2020-04-22
- // START KGU#170 2016-04-01: Enh. #144 Favourite export generator
- eod.cbPrefGenerator.setSelectedItem(ini.getProperty("genExportPreferred", "Java"));
- // END KGU#170 2016-04-01
- // START KGU#654 2019-02-15: Enh #681 Trigger for proposing recent generator as new favourite
- eod.spnPrefGenTrigger.setValue(generatorProposalTrigger);
- // END KGU#654 2019-02-15
- // START KGU#168 2016-04-04: Issue #149 Charsets for export
- eod.charsetListChanged(ini.getProperty("genExportCharset", Charset.defaultCharset().name()));
- // END KGU#168 2016-04-04
- // START KGU#351 2017-02-26: Enh. #346 / KGU#416 2017-06-20 Revised
- for (int i = 0; i < Menu.generatorPlugins.size(); i++) {
- GENPlugin plugin = Menu.generatorPlugins.get(i);
- String propertyName = "genExportIncl" + plugin.getKey();
- eod.includeLists[i].setText(ini.getProperty(propertyName, ""));
- // START KGU#416 2017-06-20: Enh. #354,#357
- HashMap optionValues = new HashMap();
- for (HashMap optionSpec : plugin.options) {
- String optKey = optionSpec.get("name");
- propertyName = plugin.getKey() + "." + optKey;
- optionValues.put(optKey, ini.getProperty(propertyName, ""));
- }
- eod.generatorOptions.add(optionValues);
- // END KGU#416 2017-06-20
- }
- // END KGU#351 2017-02-26
-
- eod.setVisible(true);
-
- if (eod.goOn == true) {
- ini.setProperty("genExportComments", String.valueOf(eod.commentsCheckBox.isSelected()));
- // START KGU#16/KGU#113 2015-12-18: Enh. #66, #67
- ini.setProperty("genExportBraces", String.valueOf(eod.bracesCheckBox.isSelected()));
- ini.setProperty("genExportLineNumbers", String.valueOf(eod.lineNumbersCheckBox.isSelected()));
- // END KGU#16/KGU#113 2015-12-18
- // START KGU#178 2016-07-20: Enh. #160
- ini.setProperty("genExportSubroutines", String.valueOf(eod.chkExportSubroutines.isSelected()));
- // END #178 2016-07-20
- // START KGU#162 2016-03-31: Enh. #144
- ini.setProperty("genExportnoConversion", String.valueOf(eod.noConversionCheckBox.isSelected()));
- // END KGU#162 2016-03-31
- // START KGU#363/KGU#395 2017-05-11: Enh. #372, #357
- ini.setProperty("genExportLicenseInfo", String.valueOf(eod.chkExportLicenseInfo.isSelected()));
- // END KGU#363/KGU#395 2017-05-11
- // START KGU#816 2020-03-17: Enh. #837
- ini.setProperty("genExportDirFromNsd", String.valueOf(eod.chkDirectoryFromNsd.isSelected()));
- // END KGU#816 2020-03-17
- // START KGU#854 2020-04-22: Enh. #855
- ini.setProperty("genExportUseArraySize", String.valueOf(eod.chkArraySize.isSelected()));
- ini.setProperty("genExportUseStringLen", String.valueOf(eod.chkStringLen.isSelected()));
- ini.setProperty("genExportArraySizeDefault", String.valueOf(eod.spnArraySize.getValue()));
- ini.setProperty("genExportStringLenDefault", String.valueOf(eod.spnStringLen.getValue()));
- // END KGU#854 2020-04-22
- // START KGU#170 2016-04-01: Enh. #144 Favourite export generator
- String prefGenName = (String) eod.cbPrefGenerator.getSelectedItem();
- // START KGU#654 2019-02-15: Enh #681 Trigger for proposing recent generator as new favourite
- if (!prefGenName.equals(this.prefGeneratorName)) {
- // If the preferred generator was changed then start new use counting
- this.generatorUseCount = 0;
- }
- // END KGU#654 2019-02-15
- this.prefGeneratorName = prefGenName;
- ini.setProperty("genExportPreferred", this.prefGeneratorName);
- this.NSDControl.doButtons();
- // END KGU#170 2016-04-01
- // START KGU#654 2019-02-15: Enh #681 Trigger for proposing recent generator as new favourite
- int generatorUseTrigger = (int) eod.spnPrefGenTrigger.getValue();
- if (generatorUseTrigger != this.generatorProposalTrigger) {
- this.generatorUseCount = 0;
- }
- this.generatorProposalTrigger = generatorUseTrigger;
- ini.setProperty("genExportPrefTrigger", this.prefGeneratorName);
- // END KGU#654 2019-02-15
- // START KGU#168 2016-04-04: Issue #149 Charset for export
- ini.setProperty("genExportCharset", (String) eod.cbCharset.getSelectedItem());
- // END KGU#168 2016-04-04
- // START KGU#351 2017-02-26: Enh. #346 / KGU#416 2017-06-20 Revised
- for (int i = 0; i < Menu.generatorPlugins.size(); i++) {
- GENPlugin plugin = Menu.generatorPlugins.get(i);
- String propertyName = "genExportIncl" + plugin.getKey();
- ini.setProperty(propertyName, eod.includeLists[i].getText().trim());
- // START KGU#416 2017-06-20: Enh. #354,#357
- for (Map.Entry entry : eod.generatorOptions.get(i).entrySet()) {
- propertyName = plugin.getKey() + "." + entry.getKey();
- ini.setProperty(propertyName, entry.getValue());
- }
- // END KGU#416 2017-06-20
- }
- // END KGU#351 2017-02-26
- ini.save();
- // START KGU#705 2019-09-23: Enh. #738
- this.updateCodePreview();
- // END KGU#705 2019-09-23
- }
- } catch (IOException ex) {
- // START KGU#484 2018-04-05: Issue #463
- //ex.printStackTrace();
- logger.log(Level.WARNING, "Trouble saving preferences.", ex);
- // END KGU#484 2018-04-05
- }
- }
-
- // START KGU#705 2019-09-24: Enh. #738
- /**
- * Sets a tooltip to the codePreview tab showing the language name plus (if
- * retrievable) the tooltip of Menu.menuFileExportCodeFavorite.
- */
- protected void setCodePreviewTooltip() {
- Component comp = codePreview;
- while (comp != null && !(comp instanceof JTabbedPane)) {
- comp = comp.getParent();
- }
- if (comp instanceof JTabbedPane) {
- //prefGenName + Menu.
- String tt = Locales.getValue("Structorizer", "Menu.menuFileExportCodeFavorite.tooltip", true);
- ((JTabbedPane) comp).setToolTipTextAt(1, prefGeneratorName + " - " + tt);
- }
- }
- // END KGU#705 2019-09-24
- // START AS 4 ARM
- /**
- * Sets the Element.ARM_VISUAL based on the menu choice
- *
- * @param _arm - true to switch in arm GNU mode (false for KEIL syntax compiler)
- */
- public void setOperationArmVisual(boolean _arm) {
- Element.ARM_GNU = _arm;
- this.resetDrawingInfo();
- NSDControl.doButtons();
- updateCodePreview();
- redraw();
- }
- //END AS 4 ARM
- // START KGU#258 2016-09-26: Enh. #253
- /**
- * Opens the import options dialog and processes configuration changes.
- */
- public void importOptions() {
- try {
- Ini ini = Ini.getInstance();
- ini.load();
- // START KGU#416 2017-06-20: Enh. #354,#357
- //ImportOptionDialog iod = new ImportOptionDialog(NSDControl.getFrame());
- this.retrieveParsers();
- ImportOptionDialog iod = new ImportOptionDialog(NSDControl.getFrame(), parserPlugins);
- // END KGU#416 2017-06-20
- // START KGU#362 2017-03-28: Issue #370 - default turned to true
- //iod.chkRefactorOnLoading.setSelected(ini.getProperty("impRefactorOnLoading", "false").equals("true"));
- iod.chkRefactorOnLoading.setSelected(!ini.getProperty("impRefactorOnLoading", "true").equals("false"));
- // END KGU#362 2017-03-28
- iod.charsetListChanged(ini.getProperty("impImportCharset", Charset.defaultCharset().name()));
- // START KGU#358 2017-03-06: Enh. #368
- iod.chkVarDeclarations.setSelected(ini.getProperty("impVarDeclarations", "false").equals("true"));
- // END KGU#358 2017-03-06
- // START KGU#407 2017-06-22: Enh. #420
- iod.chkCommentImport.setSelected(ini.getProperty("impComments", "false").equals("true"));
- // END KGU#407 2017-06-22
- // START KGU#821 2020-03-09: Issue #833
- iod.chkInsertOptKeywords.setSelected(ini.getProperty("impOptKeywords", "false").equals("true"));
- // END KGU#821 2020-03-09
- // START KGU#354 2017-03-08: Enh. #354 - new option to save the parse tree
- iod.chkSaveParseTree.setSelected(ini.getProperty("impSaveParseTree", "false").equals("true"));
- // END KGU#354 2017-03-08
- // START KGU#553 2018-07-13: Issue #557 - KGU#701 2019-03-29: Issue #718 raised from 20 to 50
- iod.spnLimit.setValue(Integer.parseUnsignedInt(ini.getProperty("impMaxRootsForDisplay", "50")));
- // END KGU#354 2018-07-13
- // START KGU#602 2018-10-25: Issue #419
- iod.spnMaxLen.setValue(Integer.parseUnsignedInt(ini.getProperty("impMaxLineLength", "0")));
- // END KGU#602 2018-10-25
- // START KGU#354 2017-04-27: Enh. #354 - new option to log to a specified directory
- iod.chkLogDir.setSelected(ini.getProperty("impLogToDir", "false").equals("true"));
- iod.txtLogDir.setText(ini.getProperty("impLogDir", ""));
- // START KGU#416 2017-06-20: Enh. #354,#357
- if (parserPlugins != null) {
- // START KGU#548 2018-07-09: Restore the last selected plugin choice
- iod.cbOptionPlugins.setSelectedItem(ini.getProperty("impPluginChoice", ""));
- // END KGU#548 2018-07-09
- for (int i = 0; i < parserPlugins.size(); i++) {
- GENPlugin plugin = parserPlugins.get(i);
- HashMap optionValues = new HashMap();
- for (HashMap optionSpec : plugin.options) {
- String optKey = optionSpec.get("name");
- String propertyName = plugin.getKey() + "." + optKey;
- optionValues.put(optKey, ini.getProperty(propertyName, ""));
- }
- iod.parserOptions.add(optionValues);
- }
- }
- // END KGU#416 2017-06-20
- iod.doLogButtons();
- // END KGU#354 2017-04-27
-
- iod.setVisible(true);
-
- if (iod.goOn == true) {
- ini.setProperty("impRefactorOnLoading", String.valueOf(iod.chkRefactorOnLoading.isSelected()));
- ini.setProperty("impImportCharset", (String) iod.cbCharset.getSelectedItem());
- // START KGU#358 2017-03-06: Enh. #368
- ini.setProperty("impVarDeclarations", String.valueOf(iod.chkVarDeclarations.isSelected()));
- // END KGU#358 2017-03-06
- // START KGU#407 2017-06-22: Enh. #420
- ini.setProperty("impComments", String.valueOf(iod.chkCommentImport.isSelected()));
- // END KGU#407 2017-06-22
- // START KGU#821 2020-03-09: Issue #833
- ini.setProperty("impOptKeywords", String.valueOf(iod.chkInsertOptKeywords.isSelected()));
- // END KGU#821 2020-03-09
- // START KGU#354 2017-03-08: Enh. #354 - new option to save the parse tree
- ini.setProperty("impSaveParseTree", String.valueOf(iod.chkSaveParseTree.isSelected()));
- // END KGU#354 2017-03-08
- // START KGU#354 2017-04-27: Enh. #354 - new option to log to a specified directory
- ini.setProperty("impLogToDir", String.valueOf(iod.chkLogDir.isSelected()));
- ini.setProperty("impLogDir", iod.txtLogDir.getText());
- // END KGU#354 2017-04-27
- // START KGU#553 2018-07-13: Issue #557
- ini.setProperty("impMaxRootsForDisplay", String.valueOf(iod.spnLimit.getValue()));
- // END KGU#553 2018-07-13
- // START KGU#602 2018-10-25: Issue #419
- ini.setProperty("impMaxLineLength", String.valueOf(iod.spnMaxLen.getValue()));
- // END KGU#602 2018-10-25
- // START KGU#416 2017-02-26: Enh. #354, #357
- for (int i = 0; i < parserPlugins.size(); i++) {
- GENPlugin plugin = parserPlugins.get(i);
- for (Map.Entry entry : iod.parserOptions.get(i).entrySet()) {
- String propertyName = plugin.getKey() + "." + entry.getKey();
- ini.setProperty(propertyName, entry.getValue());
- }
- }
- // END KGU#416 2017-06-20
- // START KGU#548 2018-07-09: Restore the last selected plugin choice
- ini.setProperty("impPluginChoice", (String) iod.cbOptionPlugins.getSelectedItem());
- // END KGU#548 2018-07-09
- ini.save();
- }
- } catch (FileNotFoundException ex) {
- // START KGU#484 2018-04-05: Issue #463
- //ex.printStackTrace();
- logger.log(Level.WARNING, "Trouble accessing import preferences.", ex);
- // END KGU#484 2018-04-05
- } catch (IOException ex) {
- // START KGU#484 2018-04-05: Issue #463
- //ex.printStackTrace();
- logger.log(Level.WARNING, "Trouble accessing import preferences.", ex);
- // END KGU#484 2018-04-05
- }
- }
- // END KGU#258 2016-09-26
-
- // START KGU#309 2016-12-15: Enh. #310
- /**
- * Opens the file saveing options dialog and processes configuration
- * changes.
- */
- public void savingOptions() {
- try {
- SaveOptionDialog sod = new SaveOptionDialog(NSDControl.getFrame());
- Ini ini = Ini.getInstance();
- sod.chkAutoSaveClose.setSelected(Element.E_AUTO_SAVE_ON_CLOSE);
- sod.chkAutoSaveExecute.setSelected(Element.E_AUTO_SAVE_ON_EXECUTE);
- sod.chkBackupFile.setSelected(Element.E_MAKE_BACKUPS);
- // START KGU#363 2017-03-12: Enh. #372 Allow user-defined author string
- sod.txtAuthorName.setText(ini.getProperty("authorName", System.getProperty("user.name")));
- sod.cbLicenseFile.setSelectedItem(ini.getProperty("licenseName", ""));
- // END KGU#363 2017-03-12
- // START KGU#630 2019-01-13: Enh. #662/4
- sod.chkRelativeCoordinates.setSelected(Arranger.A_STORE_RELATIVE_COORDS);
- // END KGU#630 2019-01-13
- // START KGU#690 2019-03-21: Enh. #707
- sod.chkArgNumbers.setSelected(Element.E_FILENAME_WITH_ARGNUMBERS);
- sod.cbSeparator.setSelectedItem(Element.E_FILENAME_SIG_SEPARATOR);
- // END KGU#690 2019-03-21
- sod.setVisible(true);
-
- if (sod.goOn == true) {
- Element.E_AUTO_SAVE_ON_CLOSE = sod.chkAutoSaveClose.isSelected();
- Element.E_AUTO_SAVE_ON_EXECUTE = sod.chkAutoSaveExecute.isSelected();
- Element.E_MAKE_BACKUPS = sod.chkBackupFile.isSelected();
- // START KGU#630 2019-01-13: Enh. #662/4
- Arranger.A_STORE_RELATIVE_COORDS = sod.chkRelativeCoordinates.isSelected();
- // END KGU#630 2019-01-13
- // START KGU#690 2019-03-21: Enh. #707
- Element.E_FILENAME_WITH_ARGNUMBERS = sod.chkArgNumbers.isSelected();
- Element.E_FILENAME_SIG_SEPARATOR = (Character) sod.cbSeparator.getSelectedItem();
- // END KGU#690 2019-03-21
- // START KGU#363 2017-03-12: Enh. #372 Allow user-defined author string
- ini.setProperty("authorName", sod.txtAuthorName.getText());
- String licName = (String) sod.cbLicenseFile.getSelectedItem();
- if (licName == null) {
- ini.setProperty("licenseName", "");
- } else {
- ini.setProperty("licenseName", licName);
- }
- // END KGU#363 2017-03-12
- ini.save();
- }
- } catch (FileNotFoundException e) {
- // START KGU#484 2018-04-05: Issue #463
- //e.printStackTrace();
- logger.log(Level.WARNING, "Trouble accessing preferences.", e);
- // END KGU#484 2018-04-05
- } catch (IOException e) {
- // START KGU#484 2018-04-05: Issue #463
- //e.printStackTrace();
- logger.log(Level.WARNING, "Trouble accessing saving preferences.", e);
- // END KGU#484 2018-04-05
- }
- }
- // END KGU#258 2016-09-26
-
- /*========================================
+ /**
+ * Opens the colour configuration dialog and processes configuration
+ * changes.
+ */
+ public void colorsNSD() {
+ Colors colors = new Colors(NSDControl.getFrame(), Element.colors.length);
+ Point p = getLocationOnScreen();
+ colors.setLocation(Math.round(p.x + (getVisibleRect().width - colors.getWidth()) / 2 + this.getVisibleRect().x),
+ Math.round(p.y + (getVisibleRect().height - colors.getHeight()) / 2 + this.getVisibleRect().y));
+
+ // set fields
+ for (int i = 0; i < Element.colors.length; i++) {
+ colors.colors[i].setBackground(Element.colors[i]);
+ }
+
+ colors.pack();
+ colors.setVisible(true);
+
+ // START KGU#393 2017-05-09: Issue #400 - check whether changes were committed
+ if (colors.OK) {
+ // END KGU#393 2017-05-09
+ // get fields
+ for (int i = 0; i < Element.colors.length; i++) {
+ Element.colors[i] = colors.colors[i].getBackground();
+ }
+
+ NSDControl.updateColors();
+
+ // save fields to ini-file
+ Element.saveToINI();
+ // START KGU#393 2017-05-09: Issue #400
+ }
+ // END KGU#393 2017-05-09
+
+ }
+
+ /**
+ * Opens the structure prefereneces dialog and processes configuration
+ * changes.
+ */
+ public void preferencesNSD() {
+ Preferences preferences = new Preferences(NSDControl.getFrame());
+ Point p = getLocationOnScreen();
+ preferences.setLocation(Math.round(p.x + (getVisibleRect().width - preferences.getWidth()) / 2 + this.getVisibleRect().x),
+ Math.round(p.y + (getVisibleRect().height - preferences.getHeight()) / 2 + this.getVisibleRect().y));
+
+ // set fields
+ preferences.edtAltT.setText(Element.preAltT);
+ preferences.edtAltF.setText(Element.preAltF);
+ preferences.edtAlt.setText(Element.preAlt);
+ preferences.txtCase.setText(Element.preCase);
+ preferences.edtFor.setText(Element.preFor);
+ preferences.edtWhile.setText(Element.preWhile);
+ preferences.edtRepeat.setText(Element.preRepeat);
+
+ preferences.altPadRight.setSelected(Element.altPadRight);
+
+ // START KGU#401 2017-05-18: Issue #405 - allow to reduce CASE width by branch element rotation
+ preferences.spnCaseRot.setValue(Element.caseShrinkByRot);
+ // END KGU#401 2017-05-18
+ // START KGU#376 2017-07-02: Enh. #389
+ preferences.edtRoot.setText(Element.preImport);
+ // END KGU#376 2017-07-02
+ // START KGU#916 2021-01-25: Enh. #915
+ preferences.chkCaseEditor.setSelected(Element.useInputBoxCase);
+ // END KGU#916 2021-01-25
+
+ // START KGU#686 2019-03-22: Enh. #56
+ preferences.edtTry.setText(Element.preTry);
+ preferences.edtCatch.setText(Element.preCatch);
+ preferences.edtFinal.setText(Element.preFinally);
+ // END KGU#686 2019-03-22
+
+ preferences.pack();
+ preferences.setVisible(true);
+
+ // START KGU#393 2017-05-09: Issue #400 - check whether changes were committed
+ if (preferences.OK) {
+ // END KGU#393 2017-05-09
+ // START KGU#491 2018-02-09: Bugfix #507 - if branch labels change we force reshaping
+ boolean mustInvalidateAlt
+ = !Element.preAltT.equals(preferences.edtAltT.getText())
+ || !Element.preAltF.equals(preferences.edtAltF.getText());
+ // END KGU#491 2018-02-09
+ // get fields
+ Element.preAltT = preferences.edtAltT.getText();
+ Element.preAltF = preferences.edtAltF.getText();
+ Element.preAlt = preferences.edtAlt.getText();
+ Element.preCase = preferences.txtCase.getText();
+ Element.preFor = preferences.edtFor.getText();
+ Element.preWhile = preferences.edtWhile.getText();
+ Element.preRepeat = preferences.edtRepeat.getText();
+ Element.altPadRight = preferences.altPadRight.isSelected();
+ // START KGU#686 2019-03-22: Enh. #56
+ Element.preTry = preferences.edtTry.getText();
+ Element.preCatch = preferences.edtCatch.getText();
+ Element.preFinally = preferences.edtFinal.getText();
+ // END KGU#686 2019-03-22
+ // START KGU#376 2017-07-02: Enh. #389
+ String newImportCaption = preferences.edtRoot.getText();
+ // END KGU#376 2017-07-02
+ // START KGU#401 2017-05-18: Issue #405 - allow to reduce CASE width by branch element rotation
+ int newShrinkThreshold = (Integer) preferences.spnCaseRot.getModel().getValue();
+ //if (newShrinkThreshold != Element.caseShrinkByRot) {
+ if (newShrinkThreshold != Element.caseShrinkByRot
+ // START KGU#491 2019-02-09: Bugfix #507
+ || mustInvalidateAlt
+ // END KGU#491 2019-02-09
+ || !newImportCaption.equals(Element.preImport)) {
+ root.resetDrawingInfoDown();
+ }
+ Element.caseShrinkByRot = newShrinkThreshold;
+ // END KGU#401 2017-05-18
+ // START KGU#916 2021-01-25: Enh. #915
+ Element.useInputBoxCase = preferences.chkCaseEditor.isSelected();
+ // END KGU#916 2021-01-25
+ // START KGU#376 2017-07-02: Enh. #389
+ Element.preImport = preferences.edtRoot.getText();
+ // END KGU#376 2017-07-02
+
+ // save fields to ini-file
+ Element.saveToINI();
+ redraw();
+ // START KGU#393 2017-05-09: Issue #400
+ }
+ // END KGU#393 2017-05-09
+ }
+
+ /**
+ * Opens the parser preferences dialog and processes configuration changes.
+ */
+ public void parserNSD() {
+ ParserPreferences parserPreferences = new ParserPreferences(NSDControl.getFrame());
+ Point p = getLocationOnScreen();
+ parserPreferences.setLocation(Math.round(p.x + (getVisibleRect().width - parserPreferences.getWidth()) / 2 + this.getVisibleRect().x),
+ Math.round(p.y + (getVisibleRect().height - parserPreferences.getHeight()) / 2 + this.getVisibleRect().y));
+
+ // set fields
+ parserPreferences.edtAltPre.setText(CodeParser.getKeyword("preAlt"));
+ parserPreferences.edtAltPost.setText(CodeParser.getKeyword("postAlt"));
+ parserPreferences.edtCasePre.setText(CodeParser.getKeyword("preCase"));
+ parserPreferences.edtCasePost.setText(CodeParser.getKeyword("postCase"));
+ parserPreferences.edtForPre.setText(CodeParser.getKeyword("preFor"));
+ parserPreferences.edtForPost.setText(CodeParser.getKeyword("postFor"));
+ // START KGU#3 2015-11-08: New configurable separator for FOR loop step const
+ parserPreferences.edtForStep.setText(CodeParser.getKeyword("stepFor"));
+ // END KGU#3 2015-11-08
+ // START KGU#61 2016-03-21: New configurable keywords for FOR-IN loop
+ parserPreferences.edtForInPre.setText(CodeParser.getKeyword("preForIn"));
+ parserPreferences.edtForInPost.setText(CodeParser.getKeyword("postForIn"));
+ // END KGU#61 2016-03-21
+ parserPreferences.edtWhilePre.setText(CodeParser.getKeyword("preWhile"));
+ parserPreferences.edtWhilePost.setText(CodeParser.getKeyword("postWhile"));
+ parserPreferences.edtRepeatPre.setText(CodeParser.getKeyword("preRepeat"));
+ parserPreferences.edtRepeatPost.setText(CodeParser.getKeyword("postRepeat"));
+ // START KGU#78 2016-03-25: Enh. #23 - Jump configurability introduced
+ parserPreferences.edtJumpLeave.setText(CodeParser.getKeyword("preLeave"));
+ parserPreferences.edtJumpReturn.setText(CodeParser.getKeyword("preReturn"));
+ parserPreferences.edtJumpExit.setText(CodeParser.getKeyword("preExit"));
+ // END KGU#78 2016-03-25
+ // START KGU#686 2019-03-18: Enh. #56 - Try / Carch / Throw mechanism implemented
+ parserPreferences.edtJumpThrow.setText(CodeParser.getKeyword("preThrow"));
+ // END KGU#686 2019-03-18
+ parserPreferences.edtInput.setText(CodeParser.getKeyword("input"));
+ parserPreferences.edtOutput.setText(CodeParser.getKeyword("output"));
+ // START KGU#165 2016-03-25: We need a transparent decision here
+ parserPreferences.chkIgnoreCase.setSelected(CodeParser.ignoreCase);
+ // END KGU#165 2016-03-25
+
+ parserPreferences.pack();
+ parserPreferences.setVisible(true);
+
+ if (parserPreferences.OK) {
+ // START KGU#258 2016-09-26: Enh. #253 - prepare the old settings for a refactoring
+ HashMap oldKeywordMap = null;
+ boolean wasCaseIgnored = CodeParser.ignoreCase;
+ boolean considerRefactoring = root.children.getSize() > 0
+ || isArrangerOpen() && Arranger.getInstance().getAllRoots().size() > 0;
+ // if (considerRefactoring)
+ // {
+ oldKeywordMap = new LinkedHashMap();
+ for (String key : CodeParser.keywordSet()) {
+ // START KGU#288 2016-11-06: Issue #279 - method getOrDefault may not be available
+ //String keyword = CodeParser.keywordMap.getOrDefault(key, "");
+ //if (!keyword.trim().isEmpty())
+ String keyword = CodeParser.getKeyword(key);
+ if (keyword != null && !keyword.trim().isEmpty()) // END KGU#288 2016-11-06
+ {
+ // Complete strings aren't likely to be found in a key, so don't bother
+ oldKeywordMap.put(key, Element.splitLexically(keyword, false));
+ }
+ }
+ // }
+ // END KGU#258 2016-09-26
+
+ // get fields
+ CodeParser.setKeyword("preAlt", parserPreferences.edtAltPre.getText());
+ CodeParser.setKeyword("postAlt", parserPreferences.edtAltPost.getText());
+ CodeParser.setKeyword("preCase", parserPreferences.edtCasePre.getText());
+ CodeParser.setKeyword("postCase", parserPreferences.edtCasePost.getText());
+ CodeParser.setKeyword("preFor", parserPreferences.edtForPre.getText());
+ CodeParser.setKeyword("postFor", parserPreferences.edtForPost.getText());
+ // START KGU#3 2015-11-08: New configurable separator for FOR loop step const
+ CodeParser.setKeyword("stepFor", parserPreferences.edtForStep.getText());
+ // END KGU#3 2015-11-08
+ // START KGU#61 2016-03-21: New configurable keywords for FOR-IN loop
+ CodeParser.setKeyword("preForIn", parserPreferences.edtForInPre.getText());
+ CodeParser.setKeyword("postForIn", parserPreferences.edtForInPost.getText());
+ // END KGU#61 2016-03-21
+ CodeParser.setKeyword("preWhile", parserPreferences.edtWhilePre.getText());
+ CodeParser.setKeyword("postWhile", parserPreferences.edtWhilePost.getText());
+ CodeParser.setKeyword("preRepeat", parserPreferences.edtRepeatPre.getText());
+ CodeParser.setKeyword("postRepeat", parserPreferences.edtRepeatPost.getText());
+ // START KGU#78 2016-03-25: Enh. #23 - Jump configurability introduced
+ CodeParser.setKeyword("preLeave", parserPreferences.edtJumpLeave.getText());
+ CodeParser.setKeyword("preReturn", parserPreferences.edtJumpReturn.getText());
+ CodeParser.setKeyword("preExit", parserPreferences.edtJumpExit.getText());
+ // END KGU#78 2016-03-25
+ // START KGU#686 2019-03-18: Enh. #56 - Try / Carch / Throw mechanism implemented
+ CodeParser.setKeyword("preThrow", parserPreferences.edtJumpThrow.getText());
+ // END KGU#686 2019-03-18
+ CodeParser.setKeyword("input", parserPreferences.edtInput.getText());
+ CodeParser.setKeyword("output", parserPreferences.edtOutput.getText());
+ // START KGU#165 2016-03-25: We need a transparent decision here
+ CodeParser.ignoreCase = parserPreferences.chkIgnoreCase.isSelected();
+ // END KGU#165 2016-03-25
+
+ // save fields to ini-file
+ CodeParser.saveToINI();
+
+ // START KGU#258 2016-09-26: Enh. #253 - now try a refactoring if specified
+ boolean redrawn = false;
+ if (considerRefactoring && offerRefactoring(oldKeywordMap)) {
+ boolean refactorAll = oldKeywordMap.containsKey("refactorAll");
+ redrawn = refactorDiagrams(oldKeywordMap, refactorAll, wasCaseIgnored);
+ }
+ // END KGU#258 2016-09-26
+
+ // START KGU#362 2017-03-28: Issue #370
+ offerStructPrefAdaptation(oldKeywordMap);
+ // END KGU#362 2017-03-28
+
+ // START KGU#136 2016-03-31: Bugfix #97 - cached bounds may have to be invalidated
+ if (Element.E_VARHIGHLIGHT && !redrawn) {
+ // Parser keyword changes may have an impact on the text width ...
+ this.resetDrawingInfo();
+
+ // START KGU#258 2016-09-26: Bugfix #253 ... and Jumps and loops
+ analyse();
+ // END KGU#258 2016-09-26
+
+ // redraw diagram
+ redraw();
+ }
+ // END KGU#136 2016-03-31
+
+ // STAR KGU#705 2019-09-29: Enh. #738
+ updateCodePreview();
+ // END KGU#705 2019-09-29
+ }
+ }
+
+ // START KGU#258 2016-09-26: Enh. #253: A set of helper methods for refactoring
+ /**
+ * (To be called after a preference file has been loaded explicitly on user
+ * demand.) Based on the refactoringData collected before the loading, a
+ * difference analysis between the old and new parser preferences will be
+ * done. If changes are detected and there are non-trivial Roots then a
+ * dialog box will be popped up showing the changes and offering to refactor
+ * the current or all diagrams. If the user agrees then the respective code
+ * will be added to the refactoringData and true will be returned, otherwise
+ * false. If the user cancels then the original parser preferences will be
+ * restored and false will be returned.
+ *
+ * @param refactoringData - tokenized previous non-empty parser preferences
+ * @return true if a refactoring makes sense, false otherwise
+ */
+ public boolean offerRefactoring(HashMap refactoringData) {
+ // Since this method is always called after a preference file has been loaded,
+ // we update the preferred export code for the doButtons() call, though it
+ // has nothing to do with refactoring
+ this.prefGeneratorName = Ini.getInstance().getProperty("genExportPreferred", this.prefGeneratorName);
+
+ // No refectoring data was collected then we are done here ...
+ if (refactoringData == null) {
+ return false;
+ }
+
+ // Otherwise we look for differences between old and new parser preferences
+ // START KGU#719 2019-08-01: New layout for the refactoring dialog
+ //StringList replacements = new StringList();
+ List replacements = new LinkedList();
+ // END KGU#719 2019-08-1
+ for (HashMap.Entry entry : refactoringData.entrySet()) {
+ String oldValue = entry.getValue().concatenate();
+ // START KGU#288 2016-11-06: Issue #279 - Method getOrDefault() missing in OpenJDK
+ //String newValue = CodeParser.getKeywordOrDefault(entry.getKey(), "");
+ String newValue = CodeParser.getKeywordOrDefault(entry.getKey(), "");
+ // END KGU#288 2016-11-06
+ if (!oldValue.equals(newValue)) {
+ // START KGU#719 2019-08-01: New layout for the refactoring dialog
+ //replacements.add(" " + entry.getKey() + ": \"" + oldValue + "\" -> \"" + newValue + "\"");
+ replacements.add(new String[]{entry.getKey(), "\"" + oldValue + "\"", "\"" + newValue + "\""});
+ // END KGU#719 2019-08-01
+ }
+ }
+ // Only offer the question if there are relevant replacements and at least one non-empty or parked Root
+ // START KGU#719 2019-08-01
+ if (!replacements.isEmpty() && (root.children.getSize() > 0 || isArrangerOpen() && !Arranger.getInstance().getAllRoots().isEmpty())) // END KGU#719 2019-08-01
+ {
+ String[] options = {
+ Menu.lblRefactorNone.getText(),
+ Menu.lblRefactorCurrent.getText(),
+ Menu.lblRefactorAll.getText()
+ };
+ // START KGU#719 2019-08-01: New layout
+ JTable replTable = new JTable(0, 3);
+ for (String[] tupel : replacements) {
+ ((DefaultTableModel) replTable.getModel()).addRow(tupel);
+ }
+ for (int col = 0; col < Math.min(replTable.getColumnCount(), Menu.hdrRefactoringTable.length); col++) {
+ replTable.getColumnModel().getColumn(col).setHeaderValue(Menu.hdrRefactoringTable[col].getText());
+ }
+ Box box = Box.createVerticalBox();
+ Box box1 = Box.createHorizontalBox();
+ Box box2 = Box.createHorizontalBox();
+ box1.add(new JLabel(Menu.msgRefactoringOffer1.getText()));
+ box1.add(Box.createHorizontalGlue());
+ box2.add(new JLabel(Menu.msgRefactoringOffer2.getText()));
+ box2.add(Box.createHorizontalGlue());
+ box.add(box1);
+ box.add(Box.createVerticalStrut(5));
+ box.add(replTable.getTableHeader());
+ box.add(replTable);
+ box.add(Box.createVerticalStrut(10));
+ box.add(box2);
+ replTable.setEnabled(false);
+ replTable.setRowHeight((int) (replTable.getRowHeight() * Double.valueOf(Ini.getInstance().getProperty("scaleFactor", "1"))));
+ // END KGU#719 2019-08-01
+ // START KGU#362 2017-03-28: Issue #370: Restore old settings if user backed off
+ //int answer = JOptionPane.showOptionDialog(this,
+ // Menu.msgRefactoringOffer.getText().replace("%", "\n" + replacements.getText() + "\n"),
+ // Menu.msgTitleQuestion.getText(), JOptionPane.OK_CANCEL_OPTION,
+ // JOptionPane.QUESTION_MESSAGE,
+ // null,
+ // options, options[0]);
+ //if (answer != 0 && answer != JOptionPane.CLOSED_OPTION)
+ int answer = JOptionPane.CLOSED_OPTION;
+ do {
+ answer = JOptionPane.showOptionDialog(this.getFrame(),
+ // START KGU#719 2019-08-01
+ //Menu.msgRefactoringOffer.getText().replace("%", "\n" + replacements.getText() + "\n"),
+ box,
+ // END KGU#719 2019-08-01
+ Menu.msgTitleQuestion.getText(), JOptionPane.OK_CANCEL_OPTION,
+ JOptionPane.QUESTION_MESSAGE,
+ null,
+ options, options[2]);
+ if (answer == JOptionPane.CLOSED_OPTION && JOptionPane.showConfirmDialog(this.getFrame(),
+ Menu.msgDiscardParserPrefs.getText()) == JOptionPane.OK_OPTION) {
+ // Revert the changes
+ for (Map.Entry refEntry : refactoringData.entrySet()) {
+ CodeParser.setKeyword(refEntry.getKey(), refEntry.getValue().concatenate());
+ }
+ answer = 2;
+ }
+ } while (answer == JOptionPane.CLOSED_OPTION);
+ if (answer != 0) // END KGU#362 2017-03-28
+ {
+ if (CodeParser.ignoreCase) {
+ refactoringData.put("ignoreCase", StringList.getNew("true"));
+ }
+ if (answer == 2) {
+ refactoringData.put("refactorAll", StringList.getNew("true"));
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // START KGU#362 2017-03-28: Issue #370 - helper methods for preference consistency
+ private void offerStructPrefAdaptation(HashMap refactoringData) {
+ // START KGU#735 2019-09-29: Issue #753 - first do a check to avoid puzzling questions
+ //if (JOptionPane.showConfirmDialog(this.NSDControl.getFrame(),
+ // Menu.msgAdaptStructPrefs.getText(), Menu.msgTitleQuestion.getText(),
+ // JOptionPane.YES_NO_OPTION) == JOptionPane.OK_OPTION) {
+ String updateNeed = null;
+ if (((updateNeed = checkPref(Element.preAlt, refactoringData, "preAlt", "postAlt")) != null
+ || (updateNeed = checkPref(Element.preWhile, refactoringData, "preWhile", "postWhile")) != null
+ || (updateNeed = checkPref(Element.preRepeat, refactoringData, "preRepeat", "postRepeat")) != null
+ || (updateNeed = checkPrefCase(Element.preCase, refactoringData)) != null
+ || (updateNeed = checkPrefFor(Element.preFor, refactoringData)) != null)
+ && JOptionPane.showConfirmDialog(this.getFrame(),
+ Menu.msgAdaptStructPrefs.getText().replace("%", updateNeed), Menu.msgTitleQuestion.getText(),
+ JOptionPane.YES_NO_OPTION) == JOptionPane.OK_OPTION) {
+ // END KGU#735 2019-09-29
+ Element.preAlt = replacePref(Element.preAlt,
+ refactoringData, "preAlt", "postAlt");
+ Element.preWhile = replacePref(Element.preWhile,
+ refactoringData, "preWhile", "postWhile");
+ Element.preRepeat = replacePref(Element.preRepeat,
+ refactoringData, "preRepeat", "postRepeat");
+ Element.preCase = replacePrefCase(Element.preCase,
+ refactoringData);
+ Element.preFor = replacePrefFor(Element.preFor,
+ refactoringData);
+ }
+ }
+
+ private String replacePref(String structPref, HashMap refactoringData,
+ String prefixKey, String postfixKey) {
+ StringList old = refactoringData.get(prefixKey);
+ int startPos = 0;
+ if (old != null) {
+ String oldPrefix = old.concatenate();
+ String newPrefix = CodeParser.getKeywordOrDefault(prefixKey, "");
+ if (!oldPrefix.trim().isEmpty() && structPref.startsWith(oldPrefix)) {
+ structPref = newPrefix + structPref.substring(oldPrefix.length());
+ startPos = newPrefix.length();
+ }
+ }
+ old = refactoringData.get(postfixKey);
+ if (old != null) {
+ String oldPostfix = old.concatenate();
+ String newPostfix = CodeParser.getKeywordOrDefault(postfixKey, "");
+ if (!oldPostfix.trim().isEmpty() && structPref.substring(startPos).endsWith(oldPostfix)) {
+ structPref = structPref.substring(0, structPref.length() - oldPostfix.length()) + newPostfix;
+ }
+ }
+ return structPref;
+ }
+
+ private String replacePrefCase(String preCase, HashMap refactoringData) {
+ StringList structPrefLines = StringList.explode(preCase, "\n");
+ String oldPrefix = "";
+ String oldPostfix = "";
+ String newPrefix = CodeParser.getKeywordOrDefault("preCase", "");
+ String newPostfix = CodeParser.getKeywordOrDefault("postCase", "");
+ StringList old = refactoringData.get("preCase");
+ if (old != null) {
+ oldPrefix = old.concatenate();
+ }
+ old = refactoringData.get("postCase");
+ if (old != null) {
+ oldPostfix = old.concatenate();
+ }
+ for (int i = 0; i < structPrefLines.count() - 1; i++) {
+ String structPref = structPrefLines.get(i);
+ if (!oldPrefix.trim().isEmpty() && structPref.startsWith(oldPrefix)) {
+ structPref = newPrefix + structPref.substring(oldPrefix.length());
+ }
+ if (!oldPostfix.trim().isEmpty() && structPref.endsWith(oldPostfix)) {
+ structPref = structPref.trim().substring(0, structPref.length() - oldPostfix.length()) + newPostfix;
+ }
+ structPrefLines.set(i, structPref);
+ }
+ return structPrefLines.getText();
+ }
+
+ private String replacePrefFor(String structPref, HashMap refactoringData) {
+ String oldPrefix1 = "";
+ String oldPrefix2 = "";
+ String oldInfix1 = "";
+ String oldInfix1a = "";
+ String oldInfix2 = "";
+ String newPrefix1 = CodeParser.getKeywordOrDefault("preFor", "");
+ String newPrefix2 = CodeParser.getKeywordOrDefault("preForIn", "");
+ String newInfix1 = CodeParser.getKeywordOrDefault("postFor", "");
+ String newInfix1a = CodeParser.getKeywordOrDefault("stepFor", "");
+ String newInfix2 = CodeParser.getKeywordOrDefault("postForIn", "");
+ StringList old = null;
+ if ((old = refactoringData.get("preFor")) != null) {
+ oldPrefix1 = old.concatenate();
+ }
+ if ((old = refactoringData.get("preForIn")) != null) {
+ oldPrefix2 = old.concatenate();
+ }
+ if ((old = refactoringData.get("postFor")) != null) {
+ oldInfix1 = old.concatenate();
+ }
+ if ((old = refactoringData.get("stepFor")) != null) {
+ oldInfix1a = old.concatenate();
+ }
+ if ((old = refactoringData.get("postForIn")) != null) {
+ oldInfix2 = old.concatenate();
+ }
+ String tail = "";
+ if (!oldPrefix1.trim().isEmpty() && !oldInfix1.trim().isEmpty()
+ && structPref.startsWith(oldPrefix1) && (tail = structPref.substring(oldPrefix1.length())).contains(oldInfix1)) {
+ if (tail.matches(".*?\\W+" + oldInfix1 + "\\W+.*?")) {
+ tail = tail.replaceFirst("(.*?\\W+)" + oldInfix1 + "(\\W+.*?)",
+ "$1" + Matcher.quoteReplacement(newInfix1) + "$2");
+ }
+ if (tail.matches(".*?\\W+" + oldInfix1a + "\\W+.*?")) {
+ tail = tail.replaceFirst("(.*?\\W+)" + oldInfix1a + "(\\W+.*?)",
+ "$1" + Matcher.quoteReplacement(newInfix1a) + "$2");
+ }
+ structPref = newPrefix1 + tail;
+ } else if (!oldPrefix2.trim().isEmpty() && !oldInfix2.trim().isEmpty()
+ && structPref.startsWith(oldPrefix2) && (tail = structPref.substring(oldPrefix2.length())).contains(oldInfix2)) {
+ if (tail.matches(".*?\\W+" + oldInfix2 + "\\W+.*?")) {
+ tail = tail.replaceFirst("(.*?\\W+)" + oldInfix2 + "(\\W+.*?)",
+ "$1" + Matcher.quoteReplacement(newInfix2) + "$2");
+ }
+ structPref = newPrefix2 + tail;
+ }
+ return structPref;
+ }
+ // END KGU#362 2017-03-28
+
+ // START KGU#735 2019-09-29: Issue #753 - check methods for preference consistency
+ private String checkPref(String structPref, HashMap refactoringData,
+ String prefixKey, String postfixKey) {
+ String newPref = replacePref(structPref, refactoringData, prefixKey, postfixKey);
+ if (!newPref.equals(structPref)) {
+ return structPref + " --> " + newPref;
+ }
+ return null;
+ }
+
+ private String checkPrefCase(String structPref, HashMap refactoringData) {
+ String newPref = replacePrefCase(structPref, refactoringData);
+ if (!newPref.equals(structPref)) {
+ return structPref + " --> " + newPref;
+ }
+ return null;
+ }
+
+ private String checkPrefFor(String structPref, HashMap refactoringData) {
+ String newPref = replacePrefFor(structPref, refactoringData);
+ if (!newPref.equals(structPref)) {
+ return structPref + " --> " + newPref;
+ }
+ return null;
+ }
+ // END KGU#735 2019-09-29
+
+ /**
+ * Replaces used parser keywords in the specified diagrams by the keywords
+ * associated to them in the keyword map {@code refactoringData}, which also
+ * contains the specification whether all open diagrams are to be refactored
+ * in this way or just {@link #root}.
+ *
+ * @param refactoringData - maps old keywords to new keywords and may
+ * contain keys "refactorAll" and "ignoreCase" as mere flags.
+ */
+ public void refactorNSD(HashMap refactoringData) {
+ if (refactoringData != null) {
+ refactorDiagrams(refactoringData,
+ refactoringData.containsKey("refactorAll"),
+ refactoringData.containsKey("ignoreCase")
+ );
+ }
+ }
+
+ private boolean refactorDiagrams(HashMap oldKeywordMap, boolean refactorAll, boolean wasCaseIgnored) {
+ boolean redrawn = false;
+ if (oldKeywordMap != null && !oldKeywordMap.isEmpty()) {
+ final class Refactorer implements IElementVisitor {
+
+ public HashMap oldMap = null;
+ boolean ignoreCase = false;
+
+ @Override
+ public boolean visitPreOrder(Element _ele) {
+ _ele.refactorKeywords(oldMap, ignoreCase);
+ return true;
+ }
+
+ @Override
+ public boolean visitPostOrder(Element _ele) {
+ return true;
+ }
+
+ Refactorer(HashMap _keyMap, boolean _caseIndifferent) {
+ oldMap = _keyMap;
+ ignoreCase = _caseIndifferent;
+ }
+ };
+ // START KGU#362 2017-03-28: Issue #370 avoid frozen diagrams
+ //root.addUndo();
+ //root.traverse(new Refactorer(oldKeywordMap, wasCaseIgnored));
+ if (root.storedParserPrefs == null) {
+ root.addUndo();
+ root.traverse(new Refactorer(oldKeywordMap, wasCaseIgnored));
+ }
+ // END KGU#362 2017-03-28
+ if (refactorAll && isArrangerOpen()) {
+ // Well, we hope that the roots won't change the hash code on refactoring...
+ for (Root aRoot : Arranger.getInstance().getAllRoots()) {
+ // START KGU#362 2017-03-28: Issue #370 avoid frozen diagrams
+ //if (root != aRoot) {
+ if (root != aRoot && aRoot.storedParserPrefs == null) {
+ // END KGU#362 2017-03-28
+ aRoot.addUndo();
+ aRoot.traverse(new Refactorer(oldKeywordMap, wasCaseIgnored));
+ }
+ }
+ }
+
+ // Parser keyword changes may have an impact on the text width ...
+ this.resetDrawingInfo();
+
+ // START KGU#258 2016-09-26: Bugfix #253 ... and Jumps and loops
+ analyse();
+ // END KGU#258 2016-09-26
+
+ doButtons();
+
+ // redraw diagram
+ redraw();
+
+ redrawn = true;
+ }
+ return redrawn;
+ }
+ // END KGU#258 2016-09-26
+
+ /**
+ * Opens the Arranger Preferences dialog and processes configuration changes
+ */
+ public void analyserNSD() {
+ AnalyserPreferences analyserPreferences = new AnalyserPreferences(NSDControl.getFrame());
+ Point p = getLocationOnScreen();
+ analyserPreferences.setLocation(Math.round(p.x + (getVisibleRect().width - analyserPreferences.getWidth()) / 2 + this.getVisibleRect().x),
+ Math.round(p.y + (getVisibleRect().height - analyserPreferences.getHeight()) / 2 + this.getVisibleRect().y));
+
+ // set fields
+ // START KGU#239 2016-08-12: Code redesign (2016-09-22: index mapping modified)
+ for (int i = 1; i < analyserPreferences.checkboxes.length; i++) {
+ analyserPreferences.checkboxes[i].setSelected(Root.check(i));
+ }
+ // END KGU#239 2016-08-12
+ // START KGU#906 2021-01-02: Enh. #905
+ analyserPreferences.chkDrawWarningSign.setSelected(Element.E_ANALYSER_MARKER);
+ // END KGU#906 2021-01-02
+ // START KGU#459 2017-11-15: Enh. #459-1
+ boolean hadActiveTutorials = false;
+ for (int code : AnalyserPreferences.getOrderedGuideCodes()) {
+ if (hadActiveTutorials = Root.check(code)) {
+ break;
+ }
+ }
+ // END KGU#459 2017-11-15
+
+ analyserPreferences.pack();
+ analyserPreferences.setVisible(true);
+
+ // get fields
+ // START KGU#393 2017-05-09: Issue #400 - check whether changes were actually committed
+ if (analyserPreferences.OK) {
+ // END KGU#393 2017-05-09
+ // START KGU#239 2016-08-12: Code redesign (2016-09-22: index mapping modified)
+ for (int i = 1; i < analyserPreferences.checkboxes.length; i++) {
+ Root.setCheck(i, analyserPreferences.checkboxes[i].isSelected());
+ }
+ // END KGU#239 2016-08-12
+ // START KGU#906 2021-01-02: Enh. #905
+ boolean markersWereOn = Element.E_ANALYSER_MARKER;
+ Element.E_ANALYSER_MARKER = analyserPreferences.chkDrawWarningSign.isSelected();
+ // END KGU#906 2021-01-02
+
+ // save fields to ini-file
+ Root.saveToINI();
+
+ // START KGU#456/KGU#459 2017-11-15: Enh. #452, #459-1
+ updateTutorialQueues();
+ if (!hadActiveTutorials) {
+ for (int code : AnalyserPreferences.getOrderedGuideCodes()) {
+ if (Root.check(code)) {
+ showTutorialHint();
+ break;
+ }
+ }
+ }
+ // END KGU#456 2017-11-15
+ // re-analyse
+ //root.getVarNames(); // Is done by root.analyse() itself
+ analyse();
+ // START KGU#906 2021-01-02: Enh. #905
+ // START KGU#906 2021-02-28: Issue #905 We have to redraw on test set modifications, too
+ //if (markersWereOn != Element.E_ANALYSER_MARKER) {
+ if (markersWereOn || (markersWereOn != Element.E_ANALYSER_MARKER)) {
+ // END KGU#906 2021-02-28
+ redraw();
+ }
+ // END KGU#906 2021-01-02
+ // START KGU#393 2017-05-09: Issue #400
+ }
+ // END KGU#393 2017-05-09
+ }
+
+ // START KGU#456 2017-11-15: Enh. #452
+ protected void updateTutorialQueues() {
+ int[] guideCodes = AnalyserPreferences.getOrderedGuideCodes();
+ root.updateTutorialQueue(guideCodes);
+ if (Arranger.hasInstance()) {
+ for (Root aRoot : Arranger.getInstance().getAllRoots()) {
+ aRoot.updateTutorialQueue(guideCodes);
+ }
+ }
+ }
+ // END KGU#456 2017-11-15
+
+ /**
+ * Opens the export options dialog and processes configuration changes.
+ */
+ public void exportOptions() {
+ try {
+ Ini ini = Ini.getInstance();
+ ini.load();
+ ExportOptionDialoge eod = new ExportOptionDialoge(NSDControl.getFrame(), Menu.generatorPlugins);
+ if (ini.getProperty("genExportComments", "false").equals("true")) {
+ eod.commentsCheckBox.setSelected(true);
+ } else {
+ eod.commentsCheckBox.setSelected(false);
+ }
+ // START KGU#16/KGU#113 2015-12-18: Enh. #66, #67
+ eod.bracesCheckBox.setSelected(ini.getProperty("genExportBraces", "false").equals("true"));
+ eod.lineNumbersCheckBox.setSelected(ini.getProperty("genExportLineNumbers", "false").equals("true"));
+ // END KGU#16/KGU#113 2015-12-18
+ // START KGU#178 2016-07-20: Enh. #160
+ eod.chkExportSubroutines.setSelected(ini.getProperty("genExportSubroutines", "false").equals("true"));
+ // END #178 2016-07-20
+ // START KGU#162 2016-03-31: Enh. #144
+ eod.noConversionCheckBox.setSelected(ini.getProperty("genExportnoConversion", "false").equals("true"));
+ // END KGU#162 2016-03-31
+ // START KGU#363/KGU#395 2017-05-11: Enh. #372, #357
+ eod.chkExportLicenseInfo.setSelected(ini.getProperty("genExportLicenseInfo", "false").equals("true"));
+ // END KGU#363/KGU#395 2017-05-11
+ // START KGU#816 2020-03-17: Enh. #837
+ eod.chkDirectoryFromNsd.setSelected(ini.getProperty("genExportDirFromNsd", "true").equals("true"));
+ // END KGU#816 2020-03-17
+ // START KGU#854 2020-04-22: Enh. #855
+ eod.chkArraySize.setSelected(ini.getProperty("genExportUseArraySize", "false").equals("true"));
+ eod.chkStringLen.setSelected(ini.getProperty("genExportUseStringLen", "false").equals("true"));
+ eod.spnArraySize.setValue(Integer.parseUnsignedInt(ini.getProperty("genExportArraySizeDefault", "100")));
+ eod.spnStringLen.setValue(Integer.parseUnsignedInt(ini.getProperty("genExportStringLenDefault", "256")));
+ // END KGU#854 2020-04-22
+ // START KGU#170 2016-04-01: Enh. #144 Favourite export generator
+ eod.cbPrefGenerator.setSelectedItem(ini.getProperty("genExportPreferred", "Java"));
+ // END KGU#170 2016-04-01
+ // START KGU#654 2019-02-15: Enh #681 Trigger for proposing recent generator as new favourite
+ eod.spnPrefGenTrigger.setValue(generatorProposalTrigger);
+ // END KGU#654 2019-02-15
+ // START KGU#168 2016-04-04: Issue #149 Charsets for export
+ eod.charsetListChanged(ini.getProperty("genExportCharset", Charset.defaultCharset().name()));
+ // END KGU#168 2016-04-04
+ // START KGU#351 2017-02-26: Enh. #346 / KGU#416 2017-06-20 Revised
+ for (int i = 0; i < Menu.generatorPlugins.size(); i++) {
+ GENPlugin plugin = Menu.generatorPlugins.get(i);
+ String propertyName = "genExportIncl" + plugin.getKey();
+ eod.includeLists[i].setText(ini.getProperty(propertyName, ""));
+ // START KGU#416 2017-06-20: Enh. #354,#357
+ HashMap optionValues = new HashMap();
+ for (HashMap optionSpec : plugin.options) {
+ String optKey = optionSpec.get("name");
+ propertyName = plugin.getKey() + "." + optKey;
+ optionValues.put(optKey, ini.getProperty(propertyName, ""));
+ }
+ eod.generatorOptions.add(optionValues);
+ // END KGU#416 2017-06-20
+ }
+ // END KGU#351 2017-02-26
+
+ eod.setVisible(true);
+
+ if (eod.goOn == true) {
+ ini.setProperty("genExportComments", String.valueOf(eod.commentsCheckBox.isSelected()));
+ // START KGU#16/KGU#113 2015-12-18: Enh. #66, #67
+ ini.setProperty("genExportBraces", String.valueOf(eod.bracesCheckBox.isSelected()));
+ ini.setProperty("genExportLineNumbers", String.valueOf(eod.lineNumbersCheckBox.isSelected()));
+ // END KGU#16/KGU#113 2015-12-18
+ // START KGU#178 2016-07-20: Enh. #160
+ ini.setProperty("genExportSubroutines", String.valueOf(eod.chkExportSubroutines.isSelected()));
+ // END #178 2016-07-20
+ // START KGU#162 2016-03-31: Enh. #144
+ ini.setProperty("genExportnoConversion", String.valueOf(eod.noConversionCheckBox.isSelected()));
+ // END KGU#162 2016-03-31
+ // START KGU#363/KGU#395 2017-05-11: Enh. #372, #357
+ ini.setProperty("genExportLicenseInfo", String.valueOf(eod.chkExportLicenseInfo.isSelected()));
+ // END KGU#363/KGU#395 2017-05-11
+ // START KGU#816 2020-03-17: Enh. #837
+ ini.setProperty("genExportDirFromNsd", String.valueOf(eod.chkDirectoryFromNsd.isSelected()));
+ // END KGU#816 2020-03-17
+ // START KGU#854 2020-04-22: Enh. #855
+ ini.setProperty("genExportUseArraySize", String.valueOf(eod.chkArraySize.isSelected()));
+ ini.setProperty("genExportUseStringLen", String.valueOf(eod.chkStringLen.isSelected()));
+ ini.setProperty("genExportArraySizeDefault", String.valueOf(eod.spnArraySize.getValue()));
+ ini.setProperty("genExportStringLenDefault", String.valueOf(eod.spnStringLen.getValue()));
+ // END KGU#854 2020-04-22
+ // START KGU#170 2016-04-01: Enh. #144 Favourite export generator
+ String prefGenName = (String) eod.cbPrefGenerator.getSelectedItem();
+ // START KGU#654 2019-02-15: Enh #681 Trigger for proposing recent generator as new favourite
+ if (!prefGenName.equals(this.prefGeneratorName)) {
+ // If the preferred generator was changed then start new use counting
+ this.generatorUseCount = 0;
+ }
+ // END KGU#654 2019-02-15
+ this.prefGeneratorName = prefGenName;
+ ini.setProperty("genExportPreferred", this.prefGeneratorName);
+ this.NSDControl.doButtons();
+ // END KGU#170 2016-04-01
+ // START KGU#654 2019-02-15: Enh #681 Trigger for proposing recent generator as new favourite
+ int generatorUseTrigger = (int) eod.spnPrefGenTrigger.getValue();
+ if (generatorUseTrigger != this.generatorProposalTrigger) {
+ this.generatorUseCount = 0;
+ }
+ this.generatorProposalTrigger = generatorUseTrigger;
+ ini.setProperty("genExportPrefTrigger", this.prefGeneratorName);
+ // END KGU#654 2019-02-15
+ // START KGU#168 2016-04-04: Issue #149 Charset for export
+ ini.setProperty("genExportCharset", (String) eod.cbCharset.getSelectedItem());
+ // END KGU#168 2016-04-04
+ // START KGU#351 2017-02-26: Enh. #346 / KGU#416 2017-06-20 Revised
+ for (int i = 0; i < Menu.generatorPlugins.size(); i++) {
+ GENPlugin plugin = Menu.generatorPlugins.get(i);
+ String propertyName = "genExportIncl" + plugin.getKey();
+ ini.setProperty(propertyName, eod.includeLists[i].getText().trim());
+ // START KGU#416 2017-06-20: Enh. #354,#357
+ for (Map.Entry entry : eod.generatorOptions.get(i).entrySet()) {
+ propertyName = plugin.getKey() + "." + entry.getKey();
+ ini.setProperty(propertyName, entry.getValue());
+ }
+ // END KGU#416 2017-06-20
+ }
+ // END KGU#351 2017-02-26
+ ini.save();
+ // START KGU#705 2019-09-23: Enh. #738
+ this.updateCodePreview();
+ // END KGU#705 2019-09-23
+ }
+ } catch (IOException ex) {
+ // START KGU#484 2018-04-05: Issue #463
+ //ex.printStackTrace();
+ logger.log(Level.WARNING, "Trouble saving preferences.", ex);
+ // END KGU#484 2018-04-05
+ }
+ }
+
+ // START KGU#705 2019-09-24: Enh. #738
+ /**
+ * Sets a tooltip to the codePreview tab showing the language name plus (if
+ * retrievable) the tooltip of Menu.menuFileExportCodeFavorite.
+ */
+ protected void setCodePreviewTooltip() {
+ Component comp = codePreview;
+ while (comp != null && !(comp instanceof JTabbedPane)) {
+ comp = comp.getParent();
+ }
+ if (comp instanceof JTabbedPane) {
+ //prefGenName + Menu.
+ String tt = Locales.getValue("Structorizer", "Menu.menuFileExportCodeFavorite.tooltip", true);
+ ((JTabbedPane) comp).setToolTipTextAt(1, prefGeneratorName + " - " + tt);
+ }
+ }
+ // END KGU#705 2019-09-24
+ // START AS 4 ARM
+ /**
+ * Sets the Element.ARM_VISUAL based on the menu choice
+ *
+ * @param _arm - true to switch in arm GNU mode (false for KEIL syntax compiler)
+ */
+ public void setOperationArmVisual(boolean _arm) {
+ Element.ARM_GNU = _arm;
+ this.resetDrawingInfo();
+ NSDControl.doButtons();
+ updateCodePreview();
+ redraw();
+ }
+ //END AS 4 ARM
+ // START KGU#258 2016-09-26: Enh. #253
+ /**
+ * Opens the import options dialog and processes configuration changes.
+ */
+ public void importOptions() {
+ try {
+ Ini ini = Ini.getInstance();
+ ini.load();
+ // START KGU#416 2017-06-20: Enh. #354,#357
+ //ImportOptionDialog iod = new ImportOptionDialog(NSDControl.getFrame());
+ this.retrieveParsers();
+ ImportOptionDialog iod = new ImportOptionDialog(NSDControl.getFrame(), parserPlugins);
+ // END KGU#416 2017-06-20
+ // START KGU#362 2017-03-28: Issue #370 - default turned to true
+ //iod.chkRefactorOnLoading.setSelected(ini.getProperty("impRefactorOnLoading", "false").equals("true"));
+ iod.chkRefactorOnLoading.setSelected(!ini.getProperty("impRefactorOnLoading", "true").equals("false"));
+ // END KGU#362 2017-03-28
+ iod.charsetListChanged(ini.getProperty("impImportCharset", Charset.defaultCharset().name()));
+ // START KGU#358 2017-03-06: Enh. #368
+ iod.chkVarDeclarations.setSelected(ini.getProperty("impVarDeclarations", "false").equals("true"));
+ // END KGU#358 2017-03-06
+ // START KGU#407 2017-06-22: Enh. #420
+ iod.chkCommentImport.setSelected(ini.getProperty("impComments", "false").equals("true"));
+ // END KGU#407 2017-06-22
+ // START KGU#821 2020-03-09: Issue #833
+ iod.chkInsertOptKeywords.setSelected(ini.getProperty("impOptKeywords", "false").equals("true"));
+ // END KGU#821 2020-03-09
+ // START KGU#354 2017-03-08: Enh. #354 - new option to save the parse tree
+ iod.chkSaveParseTree.setSelected(ini.getProperty("impSaveParseTree", "false").equals("true"));
+ // END KGU#354 2017-03-08
+ // START KGU#553 2018-07-13: Issue #557 - KGU#701 2019-03-29: Issue #718 raised from 20 to 50
+ iod.spnLimit.setValue(Integer.parseUnsignedInt(ini.getProperty("impMaxRootsForDisplay", "50")));
+ // END KGU#354 2018-07-13
+ // START KGU#602 2018-10-25: Issue #419
+ iod.spnMaxLen.setValue(Integer.parseUnsignedInt(ini.getProperty("impMaxLineLength", "0")));
+ // END KGU#602 2018-10-25
+ // START KGU#354 2017-04-27: Enh. #354 - new option to log to a specified directory
+ iod.chkLogDir.setSelected(ini.getProperty("impLogToDir", "false").equals("true"));
+ iod.txtLogDir.setText(ini.getProperty("impLogDir", ""));
+ // START KGU#416 2017-06-20: Enh. #354,#357
+ if (parserPlugins != null) {
+ // START KGU#548 2018-07-09: Restore the last selected plugin choice
+ iod.cbOptionPlugins.setSelectedItem(ini.getProperty("impPluginChoice", ""));
+ // END KGU#548 2018-07-09
+ for (int i = 0; i < parserPlugins.size(); i++) {
+ GENPlugin plugin = parserPlugins.get(i);
+ HashMap optionValues = new HashMap();
+ for (HashMap optionSpec : plugin.options) {
+ String optKey = optionSpec.get("name");
+ String propertyName = plugin.getKey() + "." + optKey;
+ optionValues.put(optKey, ini.getProperty(propertyName, ""));
+ }
+ iod.parserOptions.add(optionValues);
+ }
+ }
+ // END KGU#416 2017-06-20
+ iod.doLogButtons();
+ // END KGU#354 2017-04-27
+
+ iod.setVisible(true);
+
+ if (iod.goOn == true) {
+ ini.setProperty("impRefactorOnLoading", String.valueOf(iod.chkRefactorOnLoading.isSelected()));
+ ini.setProperty("impImportCharset", (String) iod.cbCharset.getSelectedItem());
+ // START KGU#358 2017-03-06: Enh. #368
+ ini.setProperty("impVarDeclarations", String.valueOf(iod.chkVarDeclarations.isSelected()));
+ // END KGU#358 2017-03-06
+ // START KGU#407 2017-06-22: Enh. #420
+ ini.setProperty("impComments", String.valueOf(iod.chkCommentImport.isSelected()));
+ // END KGU#407 2017-06-22
+ // START KGU#821 2020-03-09: Issue #833
+ ini.setProperty("impOptKeywords", String.valueOf(iod.chkInsertOptKeywords.isSelected()));
+ // END KGU#821 2020-03-09
+ // START KGU#354 2017-03-08: Enh. #354 - new option to save the parse tree
+ ini.setProperty("impSaveParseTree", String.valueOf(iod.chkSaveParseTree.isSelected()));
+ // END KGU#354 2017-03-08
+ // START KGU#354 2017-04-27: Enh. #354 - new option to log to a specified directory
+ ini.setProperty("impLogToDir", String.valueOf(iod.chkLogDir.isSelected()));
+ ini.setProperty("impLogDir", iod.txtLogDir.getText());
+ // END KGU#354 2017-04-27
+ // START KGU#553 2018-07-13: Issue #557
+ ini.setProperty("impMaxRootsForDisplay", String.valueOf(iod.spnLimit.getValue()));
+ // END KGU#553 2018-07-13
+ // START KGU#602 2018-10-25: Issue #419
+ ini.setProperty("impMaxLineLength", String.valueOf(iod.spnMaxLen.getValue()));
+ // END KGU#602 2018-10-25
+ // START KGU#416 2017-02-26: Enh. #354, #357
+ for (int i = 0; i < parserPlugins.size(); i++) {
+ GENPlugin plugin = parserPlugins.get(i);
+ for (Map.Entry entry : iod.parserOptions.get(i).entrySet()) {
+ String propertyName = plugin.getKey() + "." + entry.getKey();
+ ini.setProperty(propertyName, entry.getValue());
+ }
+ }
+ // END KGU#416 2017-06-20
+ // START KGU#548 2018-07-09: Restore the last selected plugin choice
+ ini.setProperty("impPluginChoice", (String) iod.cbOptionPlugins.getSelectedItem());
+ // END KGU#548 2018-07-09
+ ini.save();
+ }
+ } catch (FileNotFoundException ex) {
+ // START KGU#484 2018-04-05: Issue #463
+ //ex.printStackTrace();
+ logger.log(Level.WARNING, "Trouble accessing import preferences.", ex);
+ // END KGU#484 2018-04-05
+ } catch (IOException ex) {
+ // START KGU#484 2018-04-05: Issue #463
+ //ex.printStackTrace();
+ logger.log(Level.WARNING, "Trouble accessing import preferences.", ex);
+ // END KGU#484 2018-04-05
+ }
+ }
+ // END KGU#258 2016-09-26
+
+ // START KGU#309 2016-12-15: Enh. #310
+ /**
+ * Opens the file saveing options dialog and processes configuration
+ * changes.
+ */
+ public void savingOptions() {
+ try {
+ SaveOptionDialog sod = new SaveOptionDialog(NSDControl.getFrame());
+ Ini ini = Ini.getInstance();
+ sod.chkAutoSaveClose.setSelected(Element.E_AUTO_SAVE_ON_CLOSE);
+ sod.chkAutoSaveExecute.setSelected(Element.E_AUTO_SAVE_ON_EXECUTE);
+ sod.chkBackupFile.setSelected(Element.E_MAKE_BACKUPS);
+ // START KGU#363 2017-03-12: Enh. #372 Allow user-defined author string
+ sod.txtAuthorName.setText(ini.getProperty("authorName", System.getProperty("user.name")));
+ sod.cbLicenseFile.setSelectedItem(ini.getProperty("licenseName", ""));
+ // END KGU#363 2017-03-12
+ // START KGU#630 2019-01-13: Enh. #662/4
+ sod.chkRelativeCoordinates.setSelected(Arranger.A_STORE_RELATIVE_COORDS);
+ // END KGU#630 2019-01-13
+ // START KGU#690 2019-03-21: Enh. #707
+ sod.chkArgNumbers.setSelected(Element.E_FILENAME_WITH_ARGNUMBERS);
+ sod.cbSeparator.setSelectedItem(Element.E_FILENAME_SIG_SEPARATOR);
+ // END KGU#690 2019-03-21
+ sod.setVisible(true);
+
+ if (sod.goOn == true) {
+ Element.E_AUTO_SAVE_ON_CLOSE = sod.chkAutoSaveClose.isSelected();
+ Element.E_AUTO_SAVE_ON_EXECUTE = sod.chkAutoSaveExecute.isSelected();
+ Element.E_MAKE_BACKUPS = sod.chkBackupFile.isSelected();
+ // START KGU#630 2019-01-13: Enh. #662/4
+ Arranger.A_STORE_RELATIVE_COORDS = sod.chkRelativeCoordinates.isSelected();
+ // END KGU#630 2019-01-13
+ // START KGU#690 2019-03-21: Enh. #707
+ Element.E_FILENAME_WITH_ARGNUMBERS = sod.chkArgNumbers.isSelected();
+ Element.E_FILENAME_SIG_SEPARATOR = (Character) sod.cbSeparator.getSelectedItem();
+ // END KGU#690 2019-03-21
+ // START KGU#363 2017-03-12: Enh. #372 Allow user-defined author string
+ ini.setProperty("authorName", sod.txtAuthorName.getText());
+ String licName = (String) sod.cbLicenseFile.getSelectedItem();
+ if (licName == null) {
+ ini.setProperty("licenseName", "");
+ } else {
+ ini.setProperty("licenseName", licName);
+ }
+ // END KGU#363 2017-03-12
+ ini.save();
+ }
+ } catch (FileNotFoundException e) {
+ // START KGU#484 2018-04-05: Issue #463
+ //e.printStackTrace();
+ logger.log(Level.WARNING, "Trouble accessing preferences.", e);
+ // END KGU#484 2018-04-05
+ } catch (IOException e) {
+ // START KGU#484 2018-04-05: Issue #463
+ //e.printStackTrace();
+ logger.log(Level.WARNING, "Trouble accessing saving preferences.", e);
+ // END KGU#484 2018-04-05
+ }
+ }
+ // END KGU#258 2016-09-26
+
+ /*========================================
* font control
*========================================*/
- /**
- * Opens the font configration dialog and processes configuration changes.
- */
- public void fontNSD() {
- // START KGU#494 2018-09-10: Issue #508 - support option among fix / proportional padding
- //FontChooser fontChooser = new FontChooser(NSDControl.getFrame());
- FontChooser fontChooser = new FontChooser(NSDControl.getFrame(), true);
- // END KGU#494 2018-09-10
- Point p = getLocationOnScreen();
- fontChooser.setLocation(Math.round(p.x + (getVisibleRect().width - fontChooser.getWidth()) / 2 + this.getVisibleRect().x),
- Math.round(p.y + (getVisibleRect().height - fontChooser.getHeight()) / 2 + this.getVisibleRect().y));
-
- // set fields
- // START KGU#494 2018-09-10: Issue #508
- fontChooser.setFixPadding(Element.E_PADDING_FIX);
- // END KGU#494 2018-09-10
- fontChooser.setFont(Element.getFont());
- fontChooser.setVisible(true);
-
- // START KGU#393 2017-05-09: Issue #400 - make sure the changes were committed
- if (fontChooser.OK) {
- // END KGU#393 2017-05-09
- // get fields
- // START KGU#494 2018-09-10: Issue #508
- Element.E_PADDING_FIX = fontChooser.getFixPadding();
- // END KGU#494 2018-09-10
- Element.setFont(fontChooser.getCurrentFont());
-
- // save fields to ini-file
- Element.saveToINI();
-
- // START KGU#136 2016-03-02: Bugfix #97 - cached bounds must be invalidated
- this.resetDrawingInfo();
- // END KGU#136 2016-03-02
-
- // redraw diagram
- redraw();
- // START KGU#444/KGU#618 2018-12-18: Issue #417, #649
- this.adaptScrollUnits(); // May be too early to get new draw rectangle but try at least
- // END KGU#444/KGU#618 2018-12-18
- // START KGU#393 2017-05-09: Issue #400
- }
- // END KGU#393 2017-05-09
-
- }
-
- /**
- * Enlarges the diagram font by two points
- */
- public void fontUpNSD() {
- // change font size
- Element.setFont(new Font(Element.getFont().getFamily(), Font.PLAIN, Element.getFont().getSize() + 2));
-
- // save size
- Element.saveToINI();
-
- // START KGU#136 2016-03-02: Bugfix #97 - cached bounds must be invalidated
- this.resetDrawingInfo();
- // END KGU#136 2016-03-02
-
- // redraw diagram
- redraw();
- // START KGU#444/KGU#618 2018-12-18: Issue #417, #649
- this.adaptScrollUnits(); // May be too early to get new draw rectangle but try at least
- // END KGU#444/KGU#618 2018-12-18
- }
-
- /**
- * Diminishes the diagram font by two points.
- */
- public void fontDownNSD() {
- if (Element.getFont().getSize() - 2 >= 4) {
- // change font size
- Element.setFont(new Font(Element.getFont().getFamily(), Font.PLAIN, Element.getFont().getSize() - 2));
-
- // save size
- Element.saveToINI();
-
- // START KGU#136 2016-03-02: Bugfix #97 - cached bounds must be invalidated
- this.resetDrawingInfo();
- // END KGU#136 2016-03-02
-
- // redraw diagram
- redraw();
- }
- // START KGU#444/KGU#618 2018-12-18: Issue #417, #649
- this.adaptScrollUnits(); // May be too early to get new draw rectangle but try at least
- // END KGU#444/KGU#618 2018-12-18
- }
-
- /*========================================
+ /**
+ * Opens the font configration dialog and processes configuration changes.
+ */
+ public void fontNSD() {
+ // START KGU#494 2018-09-10: Issue #508 - support option among fix / proportional padding
+ //FontChooser fontChooser = new FontChooser(NSDControl.getFrame());
+ FontChooser fontChooser = new FontChooser(NSDControl.getFrame(), true);
+ // END KGU#494 2018-09-10
+ Point p = getLocationOnScreen();
+ fontChooser.setLocation(Math.round(p.x + (getVisibleRect().width - fontChooser.getWidth()) / 2 + this.getVisibleRect().x),
+ Math.round(p.y + (getVisibleRect().height - fontChooser.getHeight()) / 2 + this.getVisibleRect().y));
+
+ // set fields
+ // START KGU#494 2018-09-10: Issue #508
+ fontChooser.setFixPadding(Element.E_PADDING_FIX);
+ // END KGU#494 2018-09-10
+ fontChooser.setFont(Element.getFont());
+ fontChooser.setVisible(true);
+
+ // START KGU#393 2017-05-09: Issue #400 - make sure the changes were committed
+ if (fontChooser.OK) {
+ // END KGU#393 2017-05-09
+ // get fields
+ // START KGU#494 2018-09-10: Issue #508
+ Element.E_PADDING_FIX = fontChooser.getFixPadding();
+ // END KGU#494 2018-09-10
+ Element.setFont(fontChooser.getCurrentFont());
+
+ // save fields to ini-file
+ Element.saveToINI();
+
+ // START KGU#136 2016-03-02: Bugfix #97 - cached bounds must be invalidated
+ this.resetDrawingInfo();
+ // END KGU#136 2016-03-02
+
+ // redraw diagram
+ redraw();
+ // START KGU#444/KGU#618 2018-12-18: Issue #417, #649
+ this.adaptScrollUnits(); // May be too early to get new draw rectangle but try at least
+ // END KGU#444/KGU#618 2018-12-18
+ // START KGU#393 2017-05-09: Issue #400
+ }
+ // END KGU#393 2017-05-09
+
+ }
+
+ /**
+ * Enlarges the diagram font by two points
+ */
+ public void fontUpNSD() {
+ // change font size
+ Element.setFont(new Font(Element.getFont().getFamily(), Font.PLAIN, Element.getFont().getSize() + 2));
+
+ // save size
+ Element.saveToINI();
+
+ // START KGU#136 2016-03-02: Bugfix #97 - cached bounds must be invalidated
+ this.resetDrawingInfo();
+ // END KGU#136 2016-03-02
+
+ // redraw diagram
+ redraw();
+ // START KGU#444/KGU#618 2018-12-18: Issue #417, #649
+ this.adaptScrollUnits(); // May be too early to get new draw rectangle but try at least
+ // END KGU#444/KGU#618 2018-12-18
+ }
+
+ /**
+ * Diminishes the diagram font by two points.
+ */
+ public void fontDownNSD() {
+ if (Element.getFont().getSize() - 2 >= 4) {
+ // change font size
+ Element.setFont(new Font(Element.getFont().getFamily(), Font.PLAIN, Element.getFont().getSize() - 2));
+
+ // save size
+ Element.saveToINI();
+
+ // START KGU#136 2016-03-02: Bugfix #97 - cached bounds must be invalidated
+ this.resetDrawingInfo();
+ // END KGU#136 2016-03-02
+
+ // redraw diagram
+ redraw();
+ }
+ // START KGU#444/KGU#618 2018-12-18: Issue #417, #649
+ this.adaptScrollUnits(); // May be too early to get new draw rectangle but try at least
+ // END KGU#444/KGU#618 2018-12-18
+ }
+
+ /*========================================
* DIN conformity
*========================================*/
- /**
- * Flips the graphical representation of FOR loops between DIN 66261 and
- * ENDLESS design
- *
- * @see #setDIN()
- * @see #getDIN()
- */
- public void toggleDIN() {
- Element.E_DIN = !(Element.E_DIN);
- NSDControl.doButtons();
- // START KGU#136 2016-03-02: Bugfix #97 - cached bounds must be invalidated
- this.resetDrawingInfo();
- // END KGU#136 2016-03-02
- redraw();
- }
-
- /**
- * Switches the graphical representation of FOR loops to DIN 66261 design
- *
- * @see #toggleDIN()
- * @see #getDIN()
- */
- public void setDIN() {
- Element.E_DIN = true;
- NSDControl.doButtons();
- // START KGU#136 2016-03-02: Bugfix #97 - cached bounds must be invalidated
- this.resetDrawingInfo();
- // END KGU#136 2016-03-02
- redraw();
- }
-
- /**
- * @return true if the representation of FOR loops is currently conform to
- * DIN-66261.
- * @see #toggleDIN()
- * @see #setDIN()
- */
- public boolean getDIN() {
- return Element.E_DIN;
- }
-
- /*========================================
+ /**
+ * Flips the graphical representation of FOR loops between DIN 66261 and
+ * ENDLESS design
+ *
+ * @see #setDIN()
+ * @see #getDIN()
+ */
+ public void toggleDIN() {
+ Element.E_DIN = !(Element.E_DIN);
+ NSDControl.doButtons();
+ // START KGU#136 2016-03-02: Bugfix #97 - cached bounds must be invalidated
+ this.resetDrawingInfo();
+ // END KGU#136 2016-03-02
+ redraw();
+ }
+
+ /**
+ * Switches the graphical representation of FOR loops to DIN 66261 design
+ *
+ * @see #toggleDIN()
+ * @see #getDIN()
+ */
+ public void setDIN() {
+ Element.E_DIN = true;
+ NSDControl.doButtons();
+ // START KGU#136 2016-03-02: Bugfix #97 - cached bounds must be invalidated
+ this.resetDrawingInfo();
+ // END KGU#136 2016-03-02
+ redraw();
+ }
+
+ /**
+ * @return true if the representation of FOR loops is currently conform to
+ * DIN-66261.
+ * @see #toggleDIN()
+ * @see #setDIN()
+ */
+ public boolean getDIN() {
+ return Element.E_DIN;
+ }
+
+ /*========================================
* diagram type and shape
*========================================*/
- /**
- * Reduces the frame of the current diagram to a very frugal shape if
- * {@code _unboxed} is true or switches it to a complete box otherwise.
- *
- * @see #isUnboxed()
- */
- public void setUnboxed(boolean _unboxed) {
- root.isBoxed = !_unboxed;
- // START KGU#137 2016-01-11: Record this change in addition to the undoable ones
- //root.hasChanged=true;
- root.setChanged(true);
- // END KGU#137 2016-01-11
- // START KGU#136 2016-03-01: Bugfix #97
- root.resetDrawingInfoUp(); // Only affects Root
- // END KGU#136 2016-03-01
- redraw();
- }
-
- /**
- * @return true if the frame of this diagram is reduced to a frugal shape.
- * @see #setUnboxed(boolean)
- */
- public boolean isUnboxed() {
- return !root.isBoxed;
- }
-
- /**
- * Changes the type of {@link #root} to a Subroutine diagram.
- *
- * @see #setProgram()
- * @see #setInclude()
- * @see #isSubroutine()
- */
- public void setFunction() {
- // Syntax highlighting must be renewed, outer dimensions may change for unboxed diagrams
- root.resetDrawingInfoDown();
- root.setProgram(false);
- // START KGU#902 2021-01-01: Enh. #903
- poppedElement = null;
- // END KGU#902 2021-01-01
- // START KGU#137 2016-01-11: Record this change in addition to the undoable ones
- //root.hasChanged=true;
- root.setChanged(true);
- // END KGU#137 2016-01-11
- // START KGU#253 2016-09-22: Enh. #249 - (un)check parameter list
- analyse();
- // END KGU#253 2016-09-22
- redraw();
- // START KGU#705 2019-10-01: Enh. #738
- updateCodePreview();
- // END KGU#705 2019-10-01
- }
-
- /**
- * Changes the type of {@link #root} to Main program.
- *
- * @see #setFunction()
- * @see #setInclude()
- * @see #isProgram()
- */
- public void setProgram() {
- // Syntax highlighting must be renewed, outer dimensions may change for unboxed diagrams
- root.resetDrawingInfoDown();
- // START KGU#703 2019-03-30: Issue #720
- // START KGU#902 2021-01-01: Enh. #903
- poppedElement = null;
- // END KGU#902 2021-01-01
- boolean poolModified = false;
- if (root.isInclude() && Arranger.hasInstance()) {
- for (Root root : Arranger.getInstance().findIncludingRoots(root.getMethodName(), true)) {
- root.clearVarAndTypeInfo(false);
- poolModified = true;
- }
- }
- // END KGU#703 2019-03-30
- root.setProgram(true);
- // START KGU#137 2016-01-11: Record this change in addition to the undoable ones
- //root.hasChanged=true;
- root.setChanged(true);
- // END KGU#137 2016-01-11
- // START KGU#253 2016-09-22: Enh. #249 - (un)check parameter list
- analyse();
- // END KGU#253 2016-09-22
- redraw();
- // START KGU#701 2019-03-30: Issue #720
- if (poolModified) {
- Arranger.getInstance().redraw();
- }
- // END KGU#701 2019-03-30
- // START KGU#705 2019-10-01: Enh. #738
- updateCodePreview();
- // END KGU#705 2019-10-01
- }
-
- // START KGU#376 2017-05-16: Enh. #389
- /**
- * Changes the type of {@link #root} to Includable.
- *
- * @see #setFunction()
- * @see #setProgram()
- * @see #isInclude()
- */
- public void setInclude() {
- // Syntax highlighting must be renewed, outer dimensions may change for unboxed diagrams
- root.resetDrawingInfoDown();
- root.setInclude(true);
- // START KGU#902 2021-01-01: Enh. #903
- poppedElement = null;
- // END KGU#902 2021-01-01
- // START KGU#703 2019-03-30: Issue #720
- boolean poolModified = false;
- if (Arranger.hasInstance()) {
- for (Root root : Arranger.getInstance().findIncludingRoots(root.getMethodName(), true)) {
- root.clearVarAndTypeInfo(false);
- poolModified = true;
- }
- }
- // END KGU#703 2019-03-30
- // Record this change in addition to the undoable ones
- root.setChanged(true);
- // check absense of parameter list
- analyse();
- redraw();
- // START KGU#701 2019-03-30: Issue #720
- if (poolModified) {
- Arranger.getInstance().redraw();
- }
- // END KGU#701 2019-03-30
- // START KGU#705 2019-10-01: Enh. #738
- updateCodePreview();
- // END KGU#705 2019-10-01
- }
- // END KGU #376 2017-05-16
-
- /**
- * @return true if the diagram is of type Main program
- * @see #isSubroutine()
- * @see #isInclude()
- * @see #setProgram()
- */
- public boolean isProgram() {
- return root.isProgram();
- }
-
- /**
- * @return true if the diagram is of type Function
- * @see #isProgram()
- * @see #isInclude()
- * @see #setFunction()
- */
- public boolean isSubroutine() {
- return root.isSubroutine();
- }
-
- /**
- * @return true if the diagram is of type Includable
- * @see #isSubroutine()
- * @see #isProgram()
- * @see #setInclude()
- */
- public boolean isInclude() {
- return root.isInclude();
- }
-
- /*========================================
+ /**
+ * Reduces the frame of the current diagram to a very frugal shape if
+ * {@code _unboxed} is true or switches it to a complete box otherwise.
+ *
+ * @see #isUnboxed()
+ */
+ public void setUnboxed(boolean _unboxed) {
+ root.isBoxed = !_unboxed;
+ // START KGU#137 2016-01-11: Record this change in addition to the undoable ones
+ //root.hasChanged=true;
+ root.setChanged(true);
+ // END KGU#137 2016-01-11
+ // START KGU#136 2016-03-01: Bugfix #97
+ root.resetDrawingInfoUp(); // Only affects Root
+ // END KGU#136 2016-03-01
+ redraw();
+ }
+
+ /**
+ * @return true if the frame of this diagram is reduced to a frugal shape.
+ * @see #setUnboxed(boolean)
+ */
+ public boolean isUnboxed() {
+ return !root.isBoxed;
+ }
+
+ /**
+ * Changes the type of {@link #root} to a Subroutine diagram.
+ *
+ * @see #setProgram()
+ * @see #setInclude()
+ * @see #isSubroutine()
+ */
+ public void setFunction() {
+ // Syntax highlighting must be renewed, outer dimensions may change for unboxed diagrams
+ root.resetDrawingInfoDown();
+ root.setProgram(false);
+ // START KGU#902 2021-01-01: Enh. #903
+ poppedElement = null;
+ // END KGU#902 2021-01-01
+ // START KGU#137 2016-01-11: Record this change in addition to the undoable ones
+ //root.hasChanged=true;
+ root.setChanged(true);
+ // END KGU#137 2016-01-11
+ // START KGU#253 2016-09-22: Enh. #249 - (un)check parameter list
+ analyse();
+ // END KGU#253 2016-09-22
+ redraw();
+ // START KGU#705 2019-10-01: Enh. #738
+ updateCodePreview();
+ // END KGU#705 2019-10-01
+ }
+
+ /**
+ * Changes the type of {@link #root} to Main program.
+ *
+ * @see #setFunction()
+ * @see #setInclude()
+ * @see #isProgram()
+ */
+ public void setProgram() {
+ // Syntax highlighting must be renewed, outer dimensions may change for unboxed diagrams
+ root.resetDrawingInfoDown();
+ // START KGU#703 2019-03-30: Issue #720
+ // START KGU#902 2021-01-01: Enh. #903
+ poppedElement = null;
+ // END KGU#902 2021-01-01
+ boolean poolModified = false;
+ if (root.isInclude() && Arranger.hasInstance()) {
+ for (Root root : Arranger.getInstance().findIncludingRoots(root.getMethodName(), true)) {
+ root.clearVarAndTypeInfo(false);
+ poolModified = true;
+ }
+ }
+ // END KGU#703 2019-03-30
+ root.setProgram(true);
+ // START KGU#137 2016-01-11: Record this change in addition to the undoable ones
+ //root.hasChanged=true;
+ root.setChanged(true);
+ // END KGU#137 2016-01-11
+ // START KGU#253 2016-09-22: Enh. #249 - (un)check parameter list
+ analyse();
+ // END KGU#253 2016-09-22
+ redraw();
+ // START KGU#701 2019-03-30: Issue #720
+ if (poolModified) {
+ Arranger.getInstance().redraw();
+ }
+ // END KGU#701 2019-03-30
+ // START KGU#705 2019-10-01: Enh. #738
+ updateCodePreview();
+ // END KGU#705 2019-10-01
+ }
+
+ // START KGU#376 2017-05-16: Enh. #389
+ /**
+ * Changes the type of {@link #root} to Includable.
+ *
+ * @see #setFunction()
+ * @see #setProgram()
+ * @see #isInclude()
+ */
+ public void setInclude() {
+ // Syntax highlighting must be renewed, outer dimensions may change for unboxed diagrams
+ root.resetDrawingInfoDown();
+ root.setInclude(true);
+ // START KGU#902 2021-01-01: Enh. #903
+ poppedElement = null;
+ // END KGU#902 2021-01-01
+ // START KGU#703 2019-03-30: Issue #720
+ boolean poolModified = false;
+ if (Arranger.hasInstance()) {
+ for (Root root : Arranger.getInstance().findIncludingRoots(root.getMethodName(), true)) {
+ root.clearVarAndTypeInfo(false);
+ poolModified = true;
+ }
+ }
+ // END KGU#703 2019-03-30
+ // Record this change in addition to the undoable ones
+ root.setChanged(true);
+ // check absense of parameter list
+ analyse();
+ redraw();
+ // START KGU#701 2019-03-30: Issue #720
+ if (poolModified) {
+ Arranger.getInstance().redraw();
+ }
+ // END KGU#701 2019-03-30
+ // START KGU#705 2019-10-01: Enh. #738
+ updateCodePreview();
+ // END KGU#705 2019-10-01
+ }
+ // END KGU #376 2017-05-16
+
+ /**
+ * @return true if the diagram is of type Main program
+ * @see #isSubroutine()
+ * @see #isInclude()
+ * @see #setProgram()
+ */
+ public boolean isProgram() {
+ return root.isProgram();
+ }
+
+ /**
+ * @return true if the diagram is of type Function
+ * @see #isProgram()
+ * @see #isInclude()
+ * @see #setFunction()
+ */
+ public boolean isSubroutine() {
+ return root.isSubroutine();
+ }
+
+ /**
+ * @return true if the diagram is of type Includable
+ * @see #isSubroutine()
+ * @see #isProgram()
+ * @see #setInclude()
+ */
+ public boolean isInclude() {
+ return root.isInclude();
+ }
+
+ /*========================================
* comment modes
*========================================*/
- public void setComments(boolean _comments) {
- Element.E_SHOWCOMMENTS = _comments;
- NSDControl.doButtons();
- redraw();
- }
-
- // START KGU#227 2016-07-31: Enh. #128
- void setCommentsPlusText(boolean _activate) {
- Element.E_COMMENTSPLUSTEXT = _activate;
- this.resetDrawingInfo();
- analyse();
- // START KGU#904 2021-01-01: Repaint allone did not adjust the scroll area
- //repaint();
- redraw();
- // END KGU#904 2021-01-01
- }
- // END KGU#227 2016-07-31
-
- public void setToggleTC(boolean _tc) {
- Element.E_TOGGLETC = _tc;
- // START KGU#136 2016-03-01: Bugfix #97
- this.resetDrawingInfo();
- // END KGU#136 2016-03-01
- NSDControl.doButtons();
- redraw();
- }
-
- void toggleTextComments() {
- Element.E_TOGGLETC = !Element.E_TOGGLETC;
- // START KGU#136 2016-03-01: Bugfix #97
- this.resetDrawingInfo();
- // END KGU#136 2016-03-01
- // START KGU#220 2016-07-27: Enh. #207
- analyse();
- // END KGU#220 2016-07-27
- repaint();
- }
-
- /*========================================
+ public void setComments(boolean _comments) {
+ Element.E_SHOWCOMMENTS = _comments;
+ NSDControl.doButtons();
+ redraw();
+ }
+
+ // START KGU#227 2016-07-31: Enh. #128
+ void setCommentsPlusText(boolean _activate) {
+ Element.E_COMMENTSPLUSTEXT = _activate;
+ this.resetDrawingInfo();
+ analyse();
+ // START KGU#904 2021-01-01: Repaint allone did not adjust the scroll area
+ //repaint();
+ redraw();
+ // END KGU#904 2021-01-01
+ }
+ // END KGU#227 2016-07-31
+
+ public void setToggleTC(boolean _tc) {
+ Element.E_TOGGLETC = _tc;
+ // START KGU#136 2016-03-01: Bugfix #97
+ this.resetDrawingInfo();
+ // END KGU#136 2016-03-01
+ NSDControl.doButtons();
+ redraw();
+ }
+
+ void toggleTextComments() {
+ Element.E_TOGGLETC = !Element.E_TOGGLETC;
+ // START KGU#136 2016-03-01: Bugfix #97
+ this.resetDrawingInfo();
+ // END KGU#136 2016-03-01
+ // START KGU#220 2016-07-27: Enh. #207
+ analyse();
+ // END KGU#220 2016-07-27
+ repaint();
+ }
+
+ /*========================================
* further settings
*========================================*/
- /**
- * Enables or disables the syntax higighting in the elements for all
- * diagrams
- *
- * @param _highlight - true to switch syntax markup on, false to disable it
- */
- public void setHightlightVars(boolean _highlight) {
- Element.E_VARHIGHLIGHT = _highlight; // this is now directly used for drawing
- //root.highlightVars = _highlight;
- // START KGU#136 2016-03-01: Bugfix #97
- this.resetDrawingInfo();
- // END KGU#136 2016-03-01
- NSDControl.doButtons();
- redraw();
- }
-
- // START KGU#872 2020-10-17: Enh. #872 new display mode
- /**
- * Enables or disables mode to display operators in C style
- *
- * @param _operatorsC - true to switch operator display mode to C style,
- * false to standard
- */
- public void setOperatorDisplayC(boolean _operatorsC) {
- Element.E_SHOW_C_OPERATORS = _operatorsC;
- if (_operatorsC) {
- Element.E_VARHIGHLIGHT = true;
- }
- this.resetDrawingInfo();
- NSDControl.doButtons();
- redraw();
- }
- // END KGU#872 2020-10-17
-
- /**
- * Toggles the activation of the Analyser component (and the visibility of
- * the Report list).
- *
- * @see #setAnalyser(boolean)
- */
- public void toggleAnalyser() {
- setAnalyser(!Element.E_ANALYSER);
- if (Element.E_ANALYSER == true) {
- analyse();
- }
- }
-
- /**
- * Enables or disables the Analyser, according to the value of
- * {@code _analyse}.
- *
- * @param _analyse - the new status of Analyser (true to enable, obviously)
- * @see #toggleAnalyser()
- */
- public void setAnalyser(boolean _analyse) {
- Element.E_ANALYSER = _analyse;
- NSDControl.doButtons();
- }
-
- // START KGU#305 2016-12-14: Enh. #305
- /**
- * Enables or disables the Arranger Index, according to the value of
- * {@code _showIndex}.
- *
- * @param _showIndex - whether to enable (true) or disable (false) the index
- * @see #showingArrangerIndex()
- */
- public void setArrangerIndex(boolean _showIndex) {
- this.show_ARRANGER_INDEX = _showIndex;
- NSDControl.doButtons();
- }
-
- /**
- * @return true if the Arranger index is currently enabled (shown), false
- * otherwise
- * @see #setArrangerIndex(boolean)
- */
- public boolean showingArrangerIndex() {
- return this.show_ARRANGER_INDEX;
- }
- // END KGU#305 2016-12-14
-
- // START KGU#705 2019-09-23: Enh. #738
- /**
- * Enables or disables the Code Preview, according to the value of
- * {@code _showPreview}.
- *
- * @param _showPreview - whether to enable (true) or disable (false) the
- * code preview
- * @see #showingCodePreview()
- */
- public void setCodePreview(boolean _showPreview) {
- this.show_CODE_PREVIEW = _showPreview;
- if (_showPreview) {
- this.updateCodePreview();
- }
- NSDControl.doButtons();
- }
-
- /**
- * @return true if the Code Preview is currently enabled (shown), false
- * otherwise
- * @see #setCodePreview(boolean)
- */
- public boolean showingCodePreview() {
- return this.show_CODE_PREVIEW;
- }
- // END KGU#305 216-12-14
-
- // START KGU#123 2016-01-04: Enh. #87
- /**
- * Toggles the use of the mouse wheel for collapsing/expanding elements
- *
- * @see #toggleCtrlWheelMode()
- * @see #configureWheelUnit()
- */
- public void toggleWheelMode() {
- Element.E_WHEELCOLLAPSE = !Element.E_WHEELCOLLAPSE;
- // START KGU#792 2020-02-04: Bugfix #805
- Ini.getInstance().setProperty("wheelToCollapse", (Element.E_WHEELCOLLAPSE ? "1" : "0"));
- // END KGU#792 2020-02-04
- }
- // END KGU#123 2016-01-04
-
- // START KGU#503 2018-03-14: Enh. #519
- /**
- * Toggles the effect of the mouse wheel (with Ctrl key pressed) for
- * Zooming: in or out.
- *
- * @see #toggleWheelMode()
- * @see #configureWheelUnit()
- */
- public void toggleCtrlWheelMode() {
- Element.E_WHEEL_REVERSE_ZOOM = !Element.E_WHEEL_REVERSE_ZOOM;
- // START KGU#792 2020-02-04: Bugfix #805
- Ini.getInstance().setProperty("wheelCtrlReverse", (Element.E_WHEEL_REVERSE_ZOOM ? "1" : "0"));
- // END KGU#792 2020-02-04
- // START KGU#685 2020-12-12: Enh. #704
- // Behaviour of DiagramControllers should be consistent ...
- if (turtle != null) {
- turtle.setReverseZoomWheel(Element.E_WHEEL_REVERSE_ZOOM);
- }
- // END KGU#685 2020-12-12
- }
- // END KGU#503 2018-03-14
-
- // START KGU#699 2019-03-27: Issue #717 scrolling "speed" ought to be configurable
- /**
- * Opens a little dialog offering to configure the default scrolling
- * increment for the mouse wheel via a spinner.
- *
- * @see #toggleWheelMode()
- * @see #toggleCtrlWheelMode()
- */
- public void configureWheelUnit() {
- JSpinner spnUnit = new JSpinner();
- spnUnit.setModel(new SpinnerNumberModel(Math.max(1, Element.E_WHEEL_SCROLL_UNIT), 1, 20, 1));
- spnUnit.addMouseWheelListener(this);
- if (JOptionPane.showConfirmDialog(this.getFrame(),
- spnUnit,
- Menu.ttlMouseScrollUnit.getText(),
- JOptionPane.OK_CANCEL_OPTION,
- JOptionPane.QUESTION_MESSAGE,
- IconLoader.getIcon(9)) == JOptionPane.OK_OPTION) {
- Element.E_WHEEL_SCROLL_UNIT = (Integer) spnUnit.getModel().getValue();
- this.adaptScrollUnits();
- if (Arranger.hasInstance()) {
- Arranger.getInstance().adaptScrollUnits();
- }
- // START KGU#792 2020-02-04: Bugfix #805
- Ini.getInstance().setProperty("wheelScrollUnit", Integer.toString(Element.E_WHEEL_SCROLL_UNIT));
- // END KGU#792 2020-02-04
- }
- }
- // END KGU#699 2019-03-27
-
- // START KGU#170 2016-04-01: Enh. #144: Maintain a preferred export generator
- /**
- * Retrieves (and caches) the configured favourite code generator (also
- * relevant for the code preview)
- *
- * @return Language title of the preferred generator
- * @see #setPreferredGeneratorName(String)
- */
- public String getPreferredGeneratorName() {
- if (this.prefGeneratorName.isEmpty()) {
- try {
- Ini ini = Ini.getInstance();
- ini.load();
- this.prefGeneratorName = ini.getProperty("genExportPreferred", "Java");
- } catch (IOException ex) {
- // START KGU#484 2018-04-05: Issue #463
- //ex.printStackTrace();
- logger.log(Level.WARNING, "Trouble accessing preferences.", ex);
- // END KGU#484 2018-04-05
- }
- }
- return this.prefGeneratorName;
- }
- // END KGU#170 2016-04-01
-
- // START KGU#705 2019-09-24: Enh. #738
- /**
- * Retrieves (and caches) the configured favourite code generator (also
- * relevant for the code preview).
- *
- * @param genName - Language title for the preferred generator
- * @see #getPreferredGeneratorName()
- */
- public void setPreferredGeneratorName(String genName) {
- if (genName == null || genName.trim().isEmpty()) {
- return;
- }
- try {
- Ini ini = Ini.getInstance();
- for (GENPlugin plugin : Menu.generatorPlugins) {
- if (genName.equalsIgnoreCase(plugin.title)) {
- ini.load();
- // START KGU#764 2019-11-29: Issue #777 - Another Sructorizer instance may have changed the favourite language
- //if (!genName.equalsIgnoreCase(this.prefGeneratorName)) {
- // this.generatorUseCount = 1;
- //}
- //this.prefGeneratorName = plugin.title;
- //if (!this.prefGeneratorName.equals(ini.getProperty("genExportPreferred", "Java"))) {
- String iniGeneratorName = ini.getProperty("genExportPreferred", this.prefGeneratorName);
- boolean modified = !genName.equalsIgnoreCase(this.prefGeneratorName) || !genName.equalsIgnoreCase(iniGeneratorName);
- if (modified) {
- this.prefGeneratorName = plugin.title;
- // END KGU#764 2019-11-29
- ini.setProperty("genExportPreferred", plugin.title);
- ini.save();
- updateCodePreview();
- NSDControl.doButtons();
- }
- break;
- }
- }
- } catch (IOException ex) {
- logger.log(Level.WARNING, "Trouble accessing preferences.", ex);
- }
- }
- // END KGU#705 2ß19-09-24
-
- /*========================================
+ /**
+ * Enables or disables the syntax higighting in the elements for all
+ * diagrams
+ *
+ * @param _highlight - true to switch syntax markup on, false to disable it
+ */
+ public void setHightlightVars(boolean _highlight) {
+ Element.E_VARHIGHLIGHT = _highlight; // this is now directly used for drawing
+ //root.highlightVars = _highlight;
+ // START KGU#136 2016-03-01: Bugfix #97
+ this.resetDrawingInfo();
+ // END KGU#136 2016-03-01
+ NSDControl.doButtons();
+ redraw();
+ }
+
+ // START KGU#872 2020-10-17: Enh. #872 new display mode
+ /**
+ * Enables or disables mode to display operators in C style
+ *
+ * @param _operatorsC - true to switch operator display mode to C style,
+ * false to standard
+ */
+ public void setOperatorDisplayC(boolean _operatorsC) {
+ Element.E_SHOW_C_OPERATORS = _operatorsC;
+ if (_operatorsC) {
+ Element.E_VARHIGHLIGHT = true;
+ }
+ this.resetDrawingInfo();
+ NSDControl.doButtons();
+ redraw();
+ }
+ // END KGU#872 2020-10-17
+
+ /**
+ * Toggles the activation of the Analyser component (and the visibility of
+ * the Report list).
+ *
+ * @see #setAnalyser(boolean)
+ */
+ public void toggleAnalyser() {
+ setAnalyser(!Element.E_ANALYSER);
+ if (Element.E_ANALYSER == true) {
+ analyse();
+ }
+ }
+
+ /**
+ * Enables or disables the Analyser, according to the value of
+ * {@code _analyse}.
+ *
+ * @param _analyse - the new status of Analyser (true to enable, obviously)
+ * @see #toggleAnalyser()
+ */
+ public void setAnalyser(boolean _analyse) {
+ Element.E_ANALYSER = _analyse;
+ NSDControl.doButtons();
+ }
+
+ // START KGU#305 2016-12-14: Enh. #305
+ /**
+ * Enables or disables the Arranger Index, according to the value of
+ * {@code _showIndex}.
+ *
+ * @param _showIndex - whether to enable (true) or disable (false) the index
+ * @see #showingArrangerIndex()
+ */
+ public void setArrangerIndex(boolean _showIndex) {
+ this.show_ARRANGER_INDEX = _showIndex;
+ NSDControl.doButtons();
+ }
+
+ /**
+ * @return true if the Arranger index is currently enabled (shown), false
+ * otherwise
+ * @see #setArrangerIndex(boolean)
+ */
+ public boolean showingArrangerIndex() {
+ return this.show_ARRANGER_INDEX;
+ }
+ // END KGU#305 2016-12-14
+
+ // START KGU#705 2019-09-23: Enh. #738
+ /**
+ * Enables or disables the Code Preview, according to the value of
+ * {@code _showPreview}.
+ *
+ * @param _showPreview - whether to enable (true) or disable (false) the
+ * code preview
+ * @see #showingCodePreview()
+ */
+ public void setCodePreview(boolean _showPreview) {
+ this.show_CODE_PREVIEW = _showPreview;
+ if (_showPreview) {
+ this.updateCodePreview();
+ }
+ NSDControl.doButtons();
+ }
+
+ /**
+ * @return true if the Code Preview is currently enabled (shown), false
+ * otherwise
+ * @see #setCodePreview(boolean)
+ */
+ public boolean showingCodePreview() {
+ return this.show_CODE_PREVIEW;
+ }
+ // END KGU#305 216-12-14
+
+ // START KGU#123 2016-01-04: Enh. #87
+ /**
+ * Toggles the use of the mouse wheel for collapsing/expanding elements
+ *
+ * @see #toggleCtrlWheelMode()
+ * @see #configureWheelUnit()
+ */
+ public void toggleWheelMode() {
+ Element.E_WHEELCOLLAPSE = !Element.E_WHEELCOLLAPSE;
+ // START KGU#792 2020-02-04: Bugfix #805
+ Ini.getInstance().setProperty("wheelToCollapse", (Element.E_WHEELCOLLAPSE ? "1" : "0"));
+ // END KGU#792 2020-02-04
+ }
+ // END KGU#123 2016-01-04
+
+ // START KGU#503 2018-03-14: Enh. #519
+ /**
+ * Toggles the effect of the mouse wheel (with Ctrl key pressed) for
+ * Zooming: in or out.
+ *
+ * @see #toggleWheelMode()
+ * @see #configureWheelUnit()
+ */
+ public void toggleCtrlWheelMode() {
+ Element.E_WHEEL_REVERSE_ZOOM = !Element.E_WHEEL_REVERSE_ZOOM;
+ // START KGU#792 2020-02-04: Bugfix #805
+ Ini.getInstance().setProperty("wheelCtrlReverse", (Element.E_WHEEL_REVERSE_ZOOM ? "1" : "0"));
+ // END KGU#792 2020-02-04
+ // START KGU#685 2020-12-12: Enh. #704
+ // Behaviour of DiagramControllers should be consistent ...
+ if (turtle != null) {
+ turtle.setReverseZoomWheel(Element.E_WHEEL_REVERSE_ZOOM);
+ }
+ // END KGU#685 2020-12-12
+ }
+ // END KGU#503 2018-03-14
+
+ // START KGU#699 2019-03-27: Issue #717 scrolling "speed" ought to be configurable
+ /**
+ * Opens a little dialog offering to configure the default scrolling
+ * increment for the mouse wheel via a spinner.
+ *
+ * @see #toggleWheelMode()
+ * @see #toggleCtrlWheelMode()
+ */
+ public void configureWheelUnit() {
+ JSpinner spnUnit = new JSpinner();
+ spnUnit.setModel(new SpinnerNumberModel(Math.max(1, Element.E_WHEEL_SCROLL_UNIT), 1, 20, 1));
+ spnUnit.addMouseWheelListener(this);
+ if (JOptionPane.showConfirmDialog(this.getFrame(),
+ spnUnit,
+ Menu.ttlMouseScrollUnit.getText(),
+ JOptionPane.OK_CANCEL_OPTION,
+ JOptionPane.QUESTION_MESSAGE,
+ IconLoader.getIcon(9)) == JOptionPane.OK_OPTION) {
+ Element.E_WHEEL_SCROLL_UNIT = (Integer) spnUnit.getModel().getValue();
+ this.adaptScrollUnits();
+ if (Arranger.hasInstance()) {
+ Arranger.getInstance().adaptScrollUnits();
+ }
+ // START KGU#792 2020-02-04: Bugfix #805
+ Ini.getInstance().setProperty("wheelScrollUnit", Integer.toString(Element.E_WHEEL_SCROLL_UNIT));
+ // END KGU#792 2020-02-04
+ }
+ }
+ // END KGU#699 2019-03-27
+
+ // START KGU#170 2016-04-01: Enh. #144: Maintain a preferred export generator
+ /**
+ * Retrieves (and caches) the configured favourite code generator (also
+ * relevant for the code preview)
+ *
+ * @return Language title of the preferred generator
+ * @see #setPreferredGeneratorName(String)
+ */
+ public String getPreferredGeneratorName() {
+ if (this.prefGeneratorName.isEmpty()) {
+ try {
+ Ini ini = Ini.getInstance();
+ ini.load();
+ this.prefGeneratorName = ini.getProperty("genExportPreferred", "Java");
+ } catch (IOException ex) {
+ // START KGU#484 2018-04-05: Issue #463
+ //ex.printStackTrace();
+ logger.log(Level.WARNING, "Trouble accessing preferences.", ex);
+ // END KGU#484 2018-04-05
+ }
+ }
+ return this.prefGeneratorName;
+ }
+ // END KGU#170 2016-04-01
+
+ // START KGU#705 2019-09-24: Enh. #738
+ /**
+ * Retrieves (and caches) the configured favourite code generator (also
+ * relevant for the code preview).
+ *
+ * @param genName - Language title for the preferred generator
+ * @see #getPreferredGeneratorName()
+ */
+ public void setPreferredGeneratorName(String genName) {
+ if (genName == null || genName.trim().isEmpty()) {
+ return;
+ }
+ try {
+ Ini ini = Ini.getInstance();
+ for (GENPlugin plugin : Menu.generatorPlugins) {
+ if (genName.equalsIgnoreCase(plugin.title)) {
+ ini.load();
+ // START KGU#764 2019-11-29: Issue #777 - Another Sructorizer instance may have changed the favourite language
+ //if (!genName.equalsIgnoreCase(this.prefGeneratorName)) {
+ // this.generatorUseCount = 1;
+ //}
+ //this.prefGeneratorName = plugin.title;
+ //if (!this.prefGeneratorName.equals(ini.getProperty("genExportPreferred", "Java"))) {
+ String iniGeneratorName = ini.getProperty("genExportPreferred", this.prefGeneratorName);
+ boolean modified = !genName.equalsIgnoreCase(this.prefGeneratorName) || !genName.equalsIgnoreCase(iniGeneratorName);
+ if (modified) {
+ this.prefGeneratorName = plugin.title;
+ // END KGU#764 2019-11-29
+ ini.setProperty("genExportPreferred", plugin.title);
+ ini.save();
+ updateCodePreview();
+ NSDControl.doButtons();
+ }
+ break;
+ }
+ }
+ } catch (IOException ex) {
+ logger.log(Level.WARNING, "Trouble accessing preferences.", ex);
+ }
+ }
+ // END KGU#705 2ß19-09-24
+
+ /*========================================
* inputbox methods
*========================================*/
- // START KGU 2015-10-14: additional parameters for title customisation
- //public void showInputBox(EditData _data)
- /**
- * Opens the appropriate element editor version for element type
- * {@code _elementType} and gathers the editing results in {@code _data}.
- *
- * @param _data - container for the content transfer between the element and
- * the InputBox
- * @param _elementType - Class name of the {@link Element} we offer editing
- * for
- * @param _isInsertion - Indicates whether or not the element is a new
- * object
- * @param _allowCommit - Whether the OK button is enabled (not for immutable
- * elements)
- */
- public void showInputBox(EditData _data, String _elementType, boolean _isInsertion, boolean _allowCommit) // END KGU 2015-10-14
- {
- if (NSDControl != null) {
- // START KGU#946 2021-02-28: Bugfix #947: Now the type is distinguished before calling this
- boolean isRoot = _elementType.equals("Root")
- || _elementType.equals("Function")
- || _elementType.equals("Includable");
- // END KGU#946 2021-02-28
- // START KGU#170 2016-04-01: Issue #143 - on opening the editor a comment popup should vanish
- hideComments();
- // END KGU#170 2016-04-01
- // START KGU#3 2015-10-25: Dedicated support for FOR loops
- //InputBox inputbox = new InputBox(NSDControl.getFrame(),true);
- InputBox inputbox = null;
- if (_elementType.equals("For")) {
- InputBoxFor ipbFor = new InputBoxFor(NSDControl.getFrame(), true);
- // START #61 2016-09-24: After partial redesign some things work differently, now
- //if (!_isInsertion)
- //{
- if (_isInsertion) {
- // Split the default text to find out what style it is
- String[] forFractions = For.splitForClause(_data.text.getLongString());
- for (int i = 0; i < 4; i++) {
- _data.forParts.add(forFractions[i]);
- }
- if (forFractions[5] != null) {
- _data.forParts.add(forFractions[5]);
- }
- }
- // END KGU#61 2016-09-24
- ipbFor.txtVariable.setText(_data.forParts.get(0));
- ipbFor.txtStartVal.setText(_data.forParts.get(1));
- ipbFor.txtEndVal.setText(_data.forParts.get(2));
- ipbFor.txtIncr.setText(_data.forParts.get(3));
- // START KGU#61 2016-03-21: Enh. #84 - Consider FOR-IN loops
- //ipbFor.chkTextInput.setSelected(!_data.forPartsConsistent);
- //ipbFor.enableTextFields(!_data.forPartsConsistent);
- if (_data.forParts.count() > 4) {
- ipbFor.txtValueList.setText(ipbFor.forInValueList = _data.forParts.get(4));
- ipbFor.txtVariableIn.setText(_data.forParts.get(0));
- }
- boolean textMode = _data.forLoopStyle == For.ForLoopStyle.FREETEXT;
- ipbFor.chkTextInput.setSelected(textMode);
- ipbFor.enableTextFields(textMode);
- ipbFor.setIsTraversingLoop(_data.forLoopStyle == For.ForLoopStyle.TRAVERSAL);
- // END KGU#61 2016-03-21
-// }
-// else {
-// ipbFor.enableTextFields(false);
-// }
- inputbox = ipbFor;
- } // START KGU#363 2017-03-13: Enh. #372
- // START KGU#946 2021-02-28: Bugfix #947: Now the type is distinguished before calling this
- //else if (_elementType.equals("Root")) {
- else if (isRoot) {
- // END KGU#946 2021-02-28
- InputBoxRoot ipbRt = new InputBoxRoot(getFrame(), true);
-// ipbRt.licenseInfo.rootName = root.getMethodName();
-// ipbRt.licenseInfo.licenseName = _data.licenseName;
-// ipbRt.licenseInfo.licenseText = _data.licenseText;
-// String author = _data.authorName;
-// String user = System.getProperty("user.name");
-// ipbRt.txtAuthorName.setText(author);
-// if (author != null &&
-// !author.equalsIgnoreCase(Ini.getInstance().getProperty("author", user)) &&
-// !author.equalsIgnoreCase(user)) {
-// ipbRt.txtAuthorName.setEditable(false);
-// }
- ipbRt.licenseInfo = _data.licInfo;
- // START KGU#376 2017-07-01: Enh. #389
- ipbRt.setIncludeList(_data.diagramRefs);
- // END KGU#376 2017-07-01
- inputbox = ipbRt;
- } // END KGU#363 2017-03-13
- // START KGU#916 2021-01-24: Enh. #915
- else if (_elementType.equals("Case") && Element.useInputBoxCase) {
- // START KGU#927 2021-02-06: Enh. #915
- //inputbox = new InputBoxCase(getFrame(), true);
- inputbox = new InputBoxCase(getFrame(), true, new CaseEditHelper(root));
- ((InputBoxCase) inputbox).branchOrder = _data.branchOrder;
- // END KGU#927 2021-02-06
- inputbox.txtText.setVisible(false);
- } // END KGU#916 2021-01-24
- else {
- inputbox = new InputBox(getFrame(), true);
- }
- // END KGU#3 2015-10-25
- //Point p = getLocationOnScreen();
- // position inputbox in the middle of this component
-
- //inputbox.setLocation(Math.round(p.x+(this.getVisibleRect().width-inputbox.getWidth())/2+this.getVisibleRect().x),
- // Math.round(p.y+(this.getVisibleRect().height-inputbox.getHeight())/2+this.getVisibleRect().y));
- inputbox.setLocationRelativeTo(getFrame());
-
- // set title (as default)
- inputbox.setTitle(_data.title);
-
- // set field
- inputbox.txtText.setText(_data.text.getText());
- inputbox.txtComment.setText(_data.comment.getText());
- // START KGU#43 2015-10-12: Breakpoint support
- // START KGU#946 2021-02-28: Bugfix #947 - it might be a different Root we summon here...
- //boolean notRoot = getSelected() != root;
- //inputbox.chkBreakpoint.setVisible(notRoot);
- inputbox.chkBreakpoint.setVisible(!isRoot);
- // END KGU#946 2021-02-28
- inputbox.chkBreakpoint.setSelected(_data.breakpoint);
- // START KGU#686 2019-03-17: Enh. #56 - Introduction of Try
- if (_elementType.equals("Try") || _elementType.equals("Forever")) {
- inputbox.chkBreakpoint.setEnabled(false);
- inputbox.chkBreakpoint.setSelected(false);
- }
- // END KGU#686 2019-03-17
- // END KGU#43 2015-10-12
- // START KGU#695 2021-01-22: Enh. #714: Special checkbox for Try elements
- if (_elementType.equals("Try")) {
- inputbox.chkShowFinally.setVisible(true);
- inputbox.chkShowFinally.setSelected(_data.showFinally);
- }
- // END KGU#695 2021-01-22
- // START KGU#213 2016-08-01: Enh. #215
- // START KGU#246 2016-09-13: Bugfix #241)
- //inputbox.lblBreakTrigger.setText(inputbox.lblBreakText.getText().replace("%", Integer.toString(_data.breakTriggerCount)));
- // START KGU#213 2016-10-13: Enh. #215 - Make it invisible if zero
- //inputbox.lblBreakTriggerText.setVisible(notRoot);
- inputbox.lblBreakTriggerText.setVisible(!isRoot && _data.breakTriggerCount > 0);
- // END KGU#213 2016-10-13
- inputbox.lblBreakTrigger.setText(Integer.toString(_data.breakTriggerCount));
- // END KGU#246 2016-09-13
- // END KGU#213 2016-08-01
- // START KGU#277 2016-10-13: Enh. #270
- inputbox.chkDisabled.setVisible(!isRoot);
- inputbox.chkDisabled.setSelected(_data.disabled);
- // END KGU#277 2016-10-13
-
- inputbox.OK = false;
- // START KGU#42 2015-10-14: Pass the additional information for title translation control
- // START KGU#42 2019-03-05: Adapted to new type set
- //if (_elementType.equals("Root") && !this.isProgram())
- //{
- // _elementType = "Function";
- //}
- if (_elementType.equals("Root")) {
- if (this.isSubroutine()) {
- _elementType = "Function";
- } else if (this.isInclude()) {
- _elementType = "Includable";
- }
- } // END KGU#42 2019-03-05
- else if (_elementType.equals("Forever")) {
- inputbox.lblText.setVisible(false);
- inputbox.txtText.setVisible(false);
- }
- inputbox.elementType = _elementType;
- inputbox.forInsertion = _isInsertion;
- // END KGU#42 2015-10-14
- // START KGU#91 2015-12-04: Issue #39 - Attempt to set focus - always fails
- //if (Element.E_TOGGLETC || _elementType.equals("Forever"))
- //{
- // boolean ok = inputbox.txtComment.requestFocusInWindow();
- // //if (ok) System.out.println("Comment will get focus");
- //}
- //else
- //{
- // boolean ok = inputbox.txtText.requestFocusInWindow();
- // //if (ok) System.out.println("Text will get focus");
- //}
- // END KGU KGU#91 2015-12-04
- // START KGU#61 2016-03-21: Give InputBox an opportunity to check and ensure consistency
- inputbox.checkConsistency();
- // END KGU#61 2016-03-21
- // START KGU#911 2021-01-10: Enh. #910
- inputbox.btnOK.setEnabled(_allowCommit);
- // END KGU#911 2021-01-10
- inputbox.setVisible(true);
-
- // -------------------------------------------------------------------------------------
- // START KGU#927 2021-02-07: Enh. #915 Avoid unnecessary Case branch reordering
- _data.branchOrder = null;
- // END KGU#927 2021-02-07
- // get fields
- _data.text.setText(inputbox.txtText.getText());
- _data.comment.setText(inputbox.txtComment.getText());
- // START KGU#43 2015-10-12: Breakpoint support
- _data.breakpoint = inputbox.chkBreakpoint.isSelected();
- // END KGU#43 2015-10-12
- // START KGU#277 2016-10-13: Enh. #270
- _data.disabled = inputbox.chkDisabled.isSelected();
- // END KGU#277 2016-10-13
- // START KGU#213 2016-08-01: Enh. #215 (temporarily disabled again)
+ // START KGU 2015-10-14: additional parameters for title customisation
+ //public void showInputBox(EditData _data)
+ /**
+ * Opens the appropriate element editor version for element type
+ * {@code _elementType} and gathers the editing results in {@code _data}.
+ *
+ * @param _data - container for the content transfer between the element and
+ * the InputBox
+ * @param _elementType - Class name of the {@link Element} we offer editing
+ * for
+ * @param _isInsertion - Indicates whether or not the element is a new
+ * object
+ * @param _allowCommit - Whether the OK button is enabled (not for immutable
+ * elements)
+ */
+ public void showInputBox(EditData _data, String _elementType, boolean _isInsertion, boolean _allowCommit) // END KGU 2015-10-14
+ {
+ if (NSDControl != null) {
+ // START KGU#946 2021-02-28: Bugfix #947: Now the type is distinguished before calling this
+ boolean isRoot = _elementType.equals("Root")
+ || _elementType.equals("Function")
+ || _elementType.equals("Includable");
+ // END KGU#946 2021-02-28
+ // START KGU#170 2016-04-01: Issue #143 - on opening the editor a comment popup should vanish
+ hideComments();
+ // END KGU#170 2016-04-01
+ // START KGU#3 2015-10-25: Dedicated support for FOR loops
+ //InputBox inputbox = new InputBox(NSDControl.getFrame(),true);
+ InputBox inputbox = null;
+ if (_elementType.equals("For")) {
+ InputBoxFor ipbFor = new InputBoxFor(NSDControl.getFrame(), true);
+ // START #61 2016-09-24: After partial redesign some things work differently, now
+ //if (!_isInsertion)
+ //{
+ if (_isInsertion) {
+ // Split the default text to find out what style it is
+ String[] forFractions = For.splitForClause(_data.text.getLongString());
+ for (int i = 0; i < 4; i++) {
+ _data.forParts.add(forFractions[i]);
+ }
+ if (forFractions[5] != null) {
+ _data.forParts.add(forFractions[5]);
+ }
+ }
+ // END KGU#61 2016-09-24
+ ipbFor.txtVariable.setText(_data.forParts.get(0));
+ ipbFor.txtStartVal.setText(_data.forParts.get(1));
+ ipbFor.txtEndVal.setText(_data.forParts.get(2));
+ ipbFor.txtIncr.setText(_data.forParts.get(3));
+ // START KGU#61 2016-03-21: Enh. #84 - Consider FOR-IN loops
+ //ipbFor.chkTextInput.setSelected(!_data.forPartsConsistent);
+ //ipbFor.enableTextFields(!_data.forPartsConsistent);
+ if (_data.forParts.count() > 4) {
+ ipbFor.txtValueList.setText(ipbFor.forInValueList = _data.forParts.get(4));
+ ipbFor.txtVariableIn.setText(_data.forParts.get(0));
+ }
+ boolean textMode = _data.forLoopStyle == For.ForLoopStyle.FREETEXT;
+ ipbFor.chkTextInput.setSelected(textMode);
+ ipbFor.enableTextFields(textMode);
+ ipbFor.setIsTraversingLoop(_data.forLoopStyle == For.ForLoopStyle.TRAVERSAL);
+ // END KGU#61 2016-03-21
+ inputbox = ipbFor;
+ }
+ // START KGU#363 2017-03-13: Enh. #372
+ // START KGU#946 2021-02-28: Bugfix #947: Now the type is distinguished before calling this
+ //else if (_elementType.equals("Root")) {
+ else if (isRoot) {
+ // END KGU#946 2021-02-28
+ InputBoxRoot ipbRt = new InputBoxRoot(getFrame(), true);
+ ipbRt.licenseInfo = _data.licInfo;
+ // START KGU#376 2017-07-01: Enh. #389
+ ipbRt.setIncludeList(_data.diagramRefs);
+ // END KGU#376 2017-07-01
+ inputbox = ipbRt;
+ } // END KGU#363 2017-03-13
+ // START KGU#916 2021-01-24: Enh. #915
+ else if (_elementType.equals("Case") && Element.useInputBoxCase) {
+ // START KGU#927 2021-02-06: Enh. #915
+ //inputbox = new InputBoxCase(getFrame(), true);
+ inputbox = new InputBoxCase(getFrame(), true, new CaseEditHelper(root));
+ ((InputBoxCase) inputbox).branchOrder = _data.branchOrder;
+ // END KGU#927 2021-02-06
+ inputbox.txtText.setVisible(false);
+ } // END KGU#916 2021-01-24
+ else {
+ inputbox = new InputBox(getFrame(), true);
+ }
+ // END KGU#3 2015-10-25
+ inputbox.setLocationRelativeTo(getFrame());
+
+ // set title (as default)
+ inputbox.setTitle(_data.title);
+
+ // set field
+ inputbox.txtText.setText(_data.text.getText());
+ inputbox.txtComment.setText(_data.comment.getText());
+ // START KGU#43 2015-10-12: Breakpoint support
+ // START KGU#946 2021-02-28: Bugfix #947 - it might be a different Root we summon here...
+ //boolean notRoot = getSelected() != root;
+ //inputbox.chkBreakpoint.setVisible(notRoot);
+ inputbox.chkBreakpoint.setVisible(!isRoot);
+ // END KGU#946 2021-02-28
+ inputbox.chkBreakpoint.setSelected(_data.breakpoint);
+ // START KGU#686 2019-03-17: Enh. #56 - Introduction of Try
+ if (_elementType.equals("Try") || _elementType.equals("Forever")) {
+ inputbox.chkBreakpoint.setEnabled(false);
+ inputbox.chkBreakpoint.setSelected(false);
+ }
+ // END KGU#686 2019-03-17
+ // END KGU#43 2015-10-12
+ // START KGU#695 2021-01-22: Enh. #714: Special checkbox for Try elements
+ if (_elementType.equals("Try")) {
+ inputbox.chkShowFinally.setVisible(true);
+ inputbox.chkShowFinally.setSelected(_data.showFinally);
+ }
+ // END KGU#695 2021-01-22
+ // START KGU#213 2016-08-01: Enh. #215
+ // START KGU#246 2016-09-13: Bugfix #241)
+ //inputbox.lblBreakTrigger.setText(inputbox.lblBreakText.getText().replace("%", Integer.toString(_data.breakTriggerCount)));
+ // START KGU#213 2016-10-13: Enh. #215 - Make it invisible if zero
+ //inputbox.lblBreakTriggerText.setVisible(notRoot);
+ inputbox.lblBreakTriggerText.setVisible(!isRoot && _data.breakTriggerCount > 0);
+ // END KGU#213 2016-10-13
+ inputbox.lblBreakTrigger.setText(Integer.toString(_data.breakTriggerCount));
+ // END KGU#246 2016-09-13
+ // END KGU#213 2016-08-01
+ // START KGU#277 2016-10-13: Enh. #270
+ inputbox.chkDisabled.setVisible(!isRoot);
+ inputbox.chkDisabled.setSelected(_data.disabled);
+ // END KGU#277 2016-10-13
+
+ inputbox.OK = false;
+ // START KGU#42 2015-10-14: Pass the additional information for title translation control
+ // START KGU#42 2019-03-05: Adapted to new type set
+ //if (_elementType.equals("Root") && !this.isProgram())
+ //{
+ // _elementType = "Function";
+ //}
+ if (_elementType.equals("Root")) {
+ if (this.isSubroutine()) {
+ _elementType = "Function";
+ } else if (this.isInclude()) {
+ _elementType = "Includable";
+ }
+ } // END KGU#42 2019-03-05
+ else if (_elementType.equals("Forever")) {
+ inputbox.lblText.setVisible(false);
+ inputbox.txtText.setVisible(false);
+ }
+ inputbox.elementType = _elementType;
+ inputbox.forInsertion = _isInsertion;
+ // END KGU#42 2015-10-14
+ // START KGU#61 2016-03-21: Give InputBox an opportunity to check and ensure consistency
+ inputbox.checkConsistency();
+ // END KGU#61 2016-03-21
+ // START KGU#911 2021-01-10: Enh. #910
+ inputbox.btnOK.setEnabled(_allowCommit);
+ // END KGU#911 2021-01-10
+ inputbox.setVisible(true);
+
+ // -------------------------------------------------------------------------------------
+ // START KGU#927 2021-02-07: Enh. #915 Avoid unnecessary Case branch reordering
+ _data.branchOrder = null;
+ // END KGU#927 2021-02-07
+ // get fields
+ _data.text.setText(inputbox.txtText.getText());
+ _data.comment.setText(inputbox.txtComment.getText());
+ // START KGU#43 2015-10-12: Breakpoint support
+ _data.breakpoint = inputbox.chkBreakpoint.isSelected();
+ // END KGU#43 2015-10-12
+ // START KGU#277 2016-10-13: Enh. #270
+ _data.disabled = inputbox.chkDisabled.isSelected();
+ // END KGU#277 2016-10-13
+// START KGU#213 2016-08-01: Enh. #215 (temporarily disabled again)
// try{
// _data.breakTriggerCount = Integer.parseUnsignedInt(inputbox.txtBreakTrigger.getText());
// }
@@ -9843,1482 +9647,1486 @@ else if (_elementType.equals("Forever")) {
// {
// _data.breakTriggerCount = 0;
// }
- // END KGU#213 2016-08-01
- // START KGU#695 2021-01-22: Enh. #714
- _data.showFinally = inputbox.chkShowFinally.isSelected();
- // END KGU#695 2021-01-22
- // START KGU#3 2015-10-25: Dedicated support for For loops
- if (inputbox instanceof InputBoxFor) {
- _data.forParts = new StringList();
- _data.forParts.add(((InputBoxFor) inputbox).txtVariable.getText());
- _data.forParts.add(((InputBoxFor) inputbox).txtStartVal.getText());
- _data.forParts.add(((InputBoxFor) inputbox).txtEndVal.getText());
- _data.forParts.add(((InputBoxFor) inputbox).txtIncr.getText());
- // START KGU#61 2016-03-21: Enh. #84 - consider FOR-IN loops
- //_data.forPartsConsistent = !((InputBoxFor)inputbox).chkTextInput.isSelected();
- //if (!((InputBoxFor)inputbox).chkTextInput.isSelected())
- //{
- // _data.forLoopStyle = For.ForLoopStyle.COUNTER;
- //}
- //else if (((InputBoxFor)inputbox).forInValueList != null)
- //{
- // _data.forLoopStyle = For.ForLoopStyle.TRAVERSAL;
- // _data.forParts.add(((InputBoxFor)inputbox).forInValueList); }
- //else
- //{
- // _data.forLoopStyle = For.ForLoopStyle.FREETEXT;
- //}
- _data.forLoopStyle = ((InputBoxFor) inputbox).identifyForLoopStyle();
- if (_data.forLoopStyle == For.ForLoopStyle.TRAVERSAL) {
- // (InputBoxFor)inputbox).txtVariableIn.getText() should equal (InputBoxFor)inputbox).txtVariable.getText(),
- // such that nothing must be done about it here
- _data.forParts.add(((InputBoxFor) inputbox).forInValueList);
- }
- if (((InputBoxFor) inputbox).chkTextInput.isSelected() && !((InputBoxFor) inputbox).isLoopDataConsistent()) {
- _data.forLoopStyle = For.ForLoopStyle.FREETEXT;
- }
- // END KGU#61 2016-03-21
-
- } // END KGU#3 2015-10-25
- // START KGU#363 2017-03-13: Enh. 372
- else if (inputbox instanceof InputBoxRoot) {
- // START KGU#363 2017-05-20
-// _data.authorName = ((InputBoxRoot)inputbox).txtAuthorName.getText();
-// _data.licenseName = ((InputBoxRoot)inputbox).licenseInfo.licenseName;
-// _data.licenseText = ((InputBoxRoot)inputbox).licenseInfo.licenseText;
- _data.licInfo = ((InputBoxRoot) inputbox).licenseInfo;
- // END KGU#363 2017-05-20
- // START KGU#376 2017-07-01: Enh. #389
- _data.diagramRefs = ((InputBoxRoot) inputbox).getIncludeList();
- // END KGU#376 2017-07-01
- } // END KGU#363 2017-03-13
- // START KGU#916 2021-01-24: Enh. #915 additional functionality for Case elements
- else if (inputbox instanceof InputBoxCase) {
- _data.branchOrder = ((InputBoxCase) inputbox).branchOrder;
- }
- // END KGU#916 2021-01-24
- _data.result = inputbox.OK;
-
- inputbox.dispose();
- }
- }
-
- /*========================================
+// END KGU#213 2016-08-01
+ // START KGU#695 2021-01-22: Enh. #714
+ _data.showFinally = inputbox.chkShowFinally.isSelected();
+ // END KGU#695 2021-01-22
+ // START KGU#3 2015-10-25: Dedicated support for For loops
+ if (inputbox instanceof InputBoxFor) {
+ _data.forParts = new StringList();
+ _data.forParts.add(((InputBoxFor) inputbox).txtVariable.getText());
+ _data.forParts.add(((InputBoxFor) inputbox).txtStartVal.getText());
+ _data.forParts.add(((InputBoxFor) inputbox).txtEndVal.getText());
+ _data.forParts.add(((InputBoxFor) inputbox).txtIncr.getText());
+ // START KGU#61 2016-03-21: Enh. #84 - consider FOR-IN loops
+ _data.forLoopStyle = ((InputBoxFor) inputbox).identifyForLoopStyle();
+ if (_data.forLoopStyle == For.ForLoopStyle.TRAVERSAL) {
+ // (InputBoxFor)inputbox).txtVariableIn.getText() should equal (InputBoxFor)inputbox).txtVariable.getText(),
+ // such that nothing must be done about it here
+ _data.forParts.add(((InputBoxFor) inputbox).forInValueList);
+ }
+ if (((InputBoxFor) inputbox).chkTextInput.isSelected() && !((InputBoxFor) inputbox).isLoopDataConsistent()) {
+ _data.forLoopStyle = For.ForLoopStyle.FREETEXT;
+ }
+ // END KGU#61 2016-03-21
+
+ } // END KGU#3 2015-10-25
+ // START KGU#363 2017-03-13: Enh. 372
+ else if (inputbox instanceof InputBoxRoot) {
+ // START KGU#363 2017-05-20
+ // _data.authorName = ((InputBoxRoot)inputbox).txtAuthorName.getText();
+ // _data.licenseName = ((InputBoxRoot)inputbox).licenseInfo.licenseName;
+ // _data.licenseText = ((InputBoxRoot)inputbox).licenseInfo.licenseText;
+ _data.licInfo = ((InputBoxRoot) inputbox).licenseInfo;
+ // END KGU#363 2017-05-20
+ // START KGU#376 2017-07-01: Enh. #389
+ _data.diagramRefs = ((InputBoxRoot) inputbox).getIncludeList();
+ // END KGU#376 2017-07-01
+ }
+ // END KGU#363 2017-03-13
+ // START KGU#916 2021-01-24: Enh. #915 additional functionality for Case elements
+ else if (inputbox instanceof InputBoxCase) {
+ _data.branchOrder = ((InputBoxCase) inputbox).branchOrder;
+ }
+ // END KGU#916 2021-01-24
+ _data.result = inputbox.OK;
+
+ inputbox.dispose();
+ }
+ }
+
+ /*========================================
* CLIPBOARD INTERACTIONS
- *========================================*/
- /**
- * Copies the diagram as a PNG picture to the system clipboard.
- * NOTE: For some platforms, the clipboard content may yet be a JPEG image
- * rather than PNG.
- *
- * @see #copyToClipboardEMF()
- */
- public void copyToClipboardPNG() {
- // START KGU#183 2016-04-24: Issue #169 - retain old selection
- Element wasSelected = selected;
- // END KGU#183 2016-04-24
-
- // START KGU 2015-10-11
- //root.selectElementByCoord(-1,-1); // Unselect all elements
- //redraw();
- unselectAll(true);
- // END KGU 2015-10-11
-
- Clipboard systemClipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
- //DataFlavor pngFlavor = new DataFlavor("image/png","Portable Network Graphics");
-
- // get diagram
- // START KGU#660 2019-03-25: Issue #685
- //BufferedImage image = new BufferedImage(root.width+1,root.height+1, BufferedImage.TYPE_INT_ARGB);
- int imageType = BufferedImage.TYPE_INT_ARGB;
- if (System.getProperty("os.name").toLowerCase().contains("windows")) {
- /* Windows always converts to JPEG instead of PNG, so it doesn't cope
+ *========================================*/
+ /**
+ * Copies the diagram as a PNG picture to the system clipboard.
+ * NOTE: For some platforms, the clipboard content may yet be a JPEG image
+ * rather than PNG.
+ *
+ * @see #copyToClipboardEMF()
+ */
+ public void copyToClipboardPNG() {
+ // START KGU#183 2016-04-24: Issue #169 - retain old selection
+ Element wasSelected = selected;
+ // END KGU#183 2016-04-24
+
+ // START KGU 2015-10-11
+ //root.selectElementByCoord(-1,-1); // Unselect all elements
+ //redraw();
+ unselectAll(true);
+ // END KGU 2015-10-11
+
+ Clipboard systemClipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ //DataFlavor pngFlavor = new DataFlavor("image/png","Portable Network Graphics");
+
+ // get diagram
+ // START KGU#660 2019-03-25: Issue #685
+ //BufferedImage image = new BufferedImage(root.width+1,root.height+1, BufferedImage.TYPE_INT_ARGB);
+ int imageType = BufferedImage.TYPE_INT_ARGB;
+ if (System.getProperty("os.name").toLowerCase().contains("windows")) {
+ /* Windows always converts to JPEG instead of PNG, so it doesn't cope
* with alpha channel. In Java 11, this will produce exception stack
* traces, so we just circumvent it now.
- */
- imageType = BufferedImage.TYPE_INT_RGB;
- }
- BufferedImage image = new BufferedImage(root.width + 1, root.height + 1, imageType);
- // END KGU#660 2019-03-25
- // START KGU#906 2021-01-06: Enh. #905 - we don't want the triangles in the clipboard
- //root.draw(image.getGraphics(), null);
- root.draw(image.getGraphics(), null, DrawingContext.DC_IMAGE_EXPORT);
- // END KGU#906 2021-01-06
-
- // put image to clipboard
- ImageSelection imageSelection = new ImageSelection(image);
- systemClipboard.setContents(imageSelection, null);
-
- // START KGU#183 2016-04-24: Issue #169 - restore old selection
- selected = wasSelected;
- if (selected != null) {
- selected.setSelected(true);
- }
- redraw();
- // END KGU#183 2016-04-24
- }
-
- /**
- * Copies the diagram as a EMF picture to the system clipboard.
- *
- * @see #copyToClipboardPNG()
- */
- public void copyToClipboardEMF() {
- // START KGU#183 2016-04-24: Issue #169 - retain old selection
- Element wasSelected = selected;
- // END KGU#183 2016-04-24
-
- // START KGU 2015-10-11
- //root.selectElementByCoord(-1,-1); // Unselect all elements
- //redraw();
- unselectAll(true);
- // END KGU 2015-10-11
-
- Clipboard systemClipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
-
- try {
- ByteArrayOutputStream myEMF = new ByteArrayOutputStream();
- EMFGraphics2D emf = new EMFGraphics2D(myEMF, new Dimension(root.width + 6, root.height + 1));
- emf.setFont(Element.getFont());
-
- emf.startExport();
- lu.fisch.graphics.Canvas c = new lu.fisch.graphics.Canvas(emf);
- lu.fisch.graphics.Rect myrect = root.prepareDraw(c);
- root.draw(c, myrect, null, false);
- emf.endExport();
-
- systemClipboard.setContents(new EMFSelection(myEMF), null);
- } catch (Exception e) {
- // START KGU#484 2018-04-05: Issue #463
- //e.printStackTrace();
- logger.log(Level.WARNING, "Clipboad action failed.", e);
- // END KGU#484 2018-04-05
- }
-
- // START KGU#183 2016-04-24: Issue #169 - restore old selection
- selected = wasSelected;
- if (selected != null) {
- selected.setSelected(true);
- }
- redraw();
- // END KGU#183 2016-04-24
- }
-
- // Inner class is used to hold an image while on the clipboard.
- public static class EMFSelection implements Transferable, ClipboardOwner {
-
- public static final DataFlavor emfFlavor = new DataFlavor("image/emf", "Enhanced Meta File");
- // the Image object which will be housed by the ImageSelection
- private ByteArrayOutputStream os;
-
- static {
- try {
- SystemFlavorMap sfm = (SystemFlavorMap) SystemFlavorMap.getDefaultFlavorMap();
- sfm.addUnencodedNativeForFlavor(emfFlavor, "ENHMETAFILE");
- } catch (Exception e) {
- String message = e.getMessage();
- if (message == null || message.isEmpty()) {
- message = e.toString();
- }
- logger.logp(Level.SEVERE, "EMFSelection", "static init", message);
- }
- }
-
- private static DataFlavor[] supportedFlavors = {emfFlavor};
-
- public EMFSelection(ByteArrayOutputStream os) {
- this.os = os;
- }
-
- // Returns the supported flavors of our implementation
- public DataFlavor[] getTransferDataFlavors() {
- return supportedFlavors;
- }
-
- // Returns true if flavor is supported
- public boolean isDataFlavorSupported(DataFlavor flavor) {
- for (int i = 0; i < supportedFlavors.length; i++) {
- DataFlavor f = supportedFlavors[i];
- if (f.equals(flavor)) {
- return true;
- }
- }
- return false;
- }
-
- // Returns Image object housed by Transferable object
- public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
- if (flavor.equals(emfFlavor)) {
- return (new ByteArrayInputStream(os.toByteArray()));
- } else {
- //System.out.println("Hei !!!");
- throw new UnsupportedFlavorException(flavor);
- }
- }
-
- public void lostOwnership(Clipboard arg0, Transferable arg1) {
- }
-
- }
-
- // Inner class is used to hold an image while on the clipboard.
- public static class ImageSelection implements Transferable {
- // the Image object which will be housed by the ImageSelection
-
- private Image image;
-
- public ImageSelection(Image image) {
- this.image = image;
- }
-
- // Returns the supported flavors of our implementation
- public DataFlavor[] getTransferDataFlavors() {
- return new DataFlavor[]{DataFlavor.imageFlavor};
- }
-
- // Returns true if flavor is supported
- public boolean isDataFlavorSupported(DataFlavor flavor) {
- return DataFlavor.imageFlavor.equals(flavor);
- }
-
- // Returns Image object housed by Transferable object
- public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
- if (!DataFlavor.imageFlavor.equals(flavor)) {
- throw new UnsupportedFlavorException(flavor);
- }
- // else return the payload
- return image;
- }
- }
-
- /*========================================
+ */
+ imageType = BufferedImage.TYPE_INT_RGB;
+ }
+ BufferedImage image = new BufferedImage(root.width + 1, root.height + 1, imageType);
+ // END KGU#660 2019-03-25
+ // START KGU#906 2021-01-06: Enh. #905 - we don't want the triangles in the clipboard
+ //root.draw(image.getGraphics(), null);
+ root.draw(image.getGraphics(), null, DrawingContext.DC_IMAGE_EXPORT);
+ // END KGU#906 2021-01-06
+
+ // put image to clipboard
+ ImageSelection imageSelection = new ImageSelection(image);
+ systemClipboard.setContents(imageSelection, null);
+
+ // START KGU#183 2016-04-24: Issue #169 - restore old selection
+ selected = wasSelected;
+ if (selected != null) {
+ selected.setSelected(true);
+ }
+ redraw();
+ // END KGU#183 2016-04-24
+ }
+
+ /**
+ * Copies the diagram as a EMF picture to the system clipboard.
+ *
+ * @see #copyToClipboardPNG()
+ */
+ public void copyToClipboardEMF() {
+ // START KGU#183 2016-04-24: Issue #169 - retain old selection
+ Element wasSelected = selected;
+ // END KGU#183 2016-04-24
+
+ // START KGU 2015-10-11
+ //root.selectElementByCoord(-1,-1); // Unselect all elements
+ //redraw();
+ unselectAll(true);
+ // END KGU 2015-10-11
+
+ Clipboard systemClipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+
+ try {
+ ByteArrayOutputStream myEMF = new ByteArrayOutputStream();
+ EMFGraphics2D emf = new EMFGraphics2D(myEMF, new Dimension(root.width + 6, root.height + 1));
+ emf.setFont(Element.getFont());
+
+ emf.startExport();
+ lu.fisch.graphics.Canvas c = new lu.fisch.graphics.Canvas(emf);
+ lu.fisch.graphics.Rect myrect = root.prepareDraw(c);
+ root.draw(c, myrect, null, false);
+ emf.endExport();
+
+ systemClipboard.setContents(new EMFSelection(myEMF), null);
+ } catch (Exception e) {
+ // START KGU#484 2018-04-05: Issue #463
+ //e.printStackTrace();
+ logger.log(Level.WARNING, "Clipboad action failed.", e);
+ // END KGU#484 2018-04-05
+ }
+
+ // START KGU#183 2016-04-24: Issue #169 - restore old selection
+ selected = wasSelected;
+ if (selected != null) {
+ selected.setSelected(true);
+ }
+ redraw();
+ // END KGU#183 2016-04-24
+ }
+
+ // Inner class is used to hold an image while on the clipboard.
+ public static class EMFSelection implements Transferable, ClipboardOwner {
+
+ public static final DataFlavor emfFlavor = new DataFlavor("image/emf", "Enhanced Meta File");
+ // the Image object which will be housed by the ImageSelection
+ private ByteArrayOutputStream os;
+
+ static {
+ try {
+ SystemFlavorMap sfm = (SystemFlavorMap) SystemFlavorMap.getDefaultFlavorMap();
+ sfm.addUnencodedNativeForFlavor(emfFlavor, "ENHMETAFILE");
+ } catch (Exception e) {
+ String message = e.getMessage();
+ if (message == null || message.isEmpty()) {
+ message = e.toString();
+ }
+ logger.logp(Level.SEVERE, "EMFSelection", "static init", message);
+ }
+ }
+
+ private static DataFlavor[] supportedFlavors = {emfFlavor};
+
+ public EMFSelection(ByteArrayOutputStream os) {
+ this.os = os;
+ }
+
+ // Returns the supported flavors of our implementation
+ public DataFlavor[] getTransferDataFlavors() {
+ return supportedFlavors;
+ }
+
+ // Returns true if flavor is supported
+ public boolean isDataFlavorSupported(DataFlavor flavor) {
+ for (int i = 0; i < supportedFlavors.length; i++) {
+ DataFlavor f = supportedFlavors[i];
+ if (f.equals(flavor)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Returns Image object housed by Transferable object
+ public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
+ if (flavor.equals(emfFlavor)) {
+ return (new ByteArrayInputStream(os.toByteArray()));
+ } else {
+ //System.out.println("Hei !!!");
+ throw new UnsupportedFlavorException(flavor);
+ }
+ }
+
+ public void lostOwnership(Clipboard arg0, Transferable arg1) {
+ }
+
+ }
+
+ // Inner class is used to hold an image while on the clipboard.
+ public static class ImageSelection implements Transferable {
+ // the Image object which will be housed by the ImageSelection
+
+ private Image image;
+
+ public ImageSelection(Image image) {
+ this.image = image;
+ }
+
+ // Returns the supported flavors of our implementation
+ public DataFlavor[] getTransferDataFlavors() {
+ return new DataFlavor[]{DataFlavor.imageFlavor};
+ }
+
+ // Returns true if flavor is supported
+ public boolean isDataFlavorSupported(DataFlavor flavor) {
+ return DataFlavor.imageFlavor.equals(flavor);
+ }
+
+ // Returns Image object housed by Transferable object
+ public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
+ if (!DataFlavor.imageFlavor.equals(flavor)) {
+ throw new UnsupportedFlavorException(flavor);
+ }
+ // else return the payload
+ return image;
+ }
+ }
+
+ /*========================================
* ANALYSER
*========================================*/
- /**
- * Instigates the analysis of the current diagram held in {@link #root}
- */
- protected void analyse() {
- if (Element.E_ANALYSER && errorlist != null && isInitialized) {
- //System.out.println("Analysing ...");
-
- // Olà - The use of a thread to show the errorlist
- // seams not to work, because the list is not always
- // shown. Concurrency problem?
-
- /*
+ /**
+ * Instigates the analysis of the current diagram held in {@link #root}
+ */
+ protected void analyse() {
+ if (Element.E_ANALYSER && errorlist != null && isInitialized) {
+ //System.out.println("Analysing ...");
+
+ // Olà - The use of a thread to show the errorlist
+ // seams not to work, because the list is not always
+ // shown. Concurrency problem?
+
+ /*
Analyser analyser = new Analyser(root,errorlist);
analyser.start();
/**/
- //System.out.println("Working ...");
- Vector vec = root.analyse();
- DefaultListModel errors
- = (DefaultListModel) errorlist.getModel();
- errors.clear();
-
- for (int i = 0; i < vec.size(); i++) {
- errors.addElement(vec.get(i));
- }
-
- errorlist.repaint();
- errorlist.validate();
- }
- }
-
- /*========================================
+ //System.out.println("Working ...");
+ Vector vec = root.analyse();
+ DefaultListModel errors =
+ (DefaultListModel) errorlist.getModel();
+ errors.clear();
+
+ for (int i = 0; i < vec.size(); i++) {
+ errors.addElement(vec.get(i));
+ }
+
+ errorlist.repaint();
+ errorlist.validate();
+ }
+ }
+
+ /*========================================
* Recently used files
*========================================*/
- /**
- * Adds the given path {@code _filename} to the list of recently used files.
- *
- * @param _filename - the path of the file most recently used (loaded/saved)
- * @see #addRecentFile(String, boolean)
- */
- public void addRecentFile(String _filename) {
- addRecentFile(_filename, true);
- }
-
- /**
- * Adds the given {@code _filename} to the list of recently used files. If
- * this would exceed {@link #MAX_RECENT_FILES} then the oldest file name
- * gets dropped from the list.
- *
- * @param _filename - path of a file most recently used
- * @param saveINI - if true then we will immediately save the list to the
- * ini file and have all button visibility checked immediately.
- * @see #addRecentFile(String)
- */
- public void addRecentFile(String _filename, boolean saveINI) {
- if (!recentFiles.isEmpty() && recentFiles.get(0).equals(_filename)) {
- return; // nothing to do
- }
- if (recentFiles.contains(_filename)) {
- recentFiles.remove(_filename);
- }
- recentFiles.insertElementAt(_filename, 0);
- while (recentFiles.size() > MAX_RECENT_FILES) {
- recentFiles.removeElementAt(recentFiles.size() - 1);
- }
- // START KGU#602 2018-10-28 - saveINI = false is typically called on startup, so postpone the button stuff too
- //NSDControl.doButtons();
- //if (saveINI==true) {NSDControl.savePreferences();}
- if (saveINI) {
- NSDControl.doButtons();
- NSDControl.savePreferences();
- }
- // END KGU#602 2018-10-28
- }
-
- /*========================================
+ /**
+ * Adds the given path {@code _filename} to the list of recently used files.
+ *
+ * @param _filename - the path of the file most recently used (loaded/saved)
+ * @see #addRecentFile(String, boolean)
+ */
+ public void addRecentFile(String _filename) {
+ addRecentFile(_filename, true);
+ }
+
+ /**
+ * Adds the given {@code _filename} to the list of recently used files. If
+ * this would exceed {@link #MAX_RECENT_FILES} then the oldest file name
+ * gets dropped from the list.
+ *
+ * @param _filename - path of a file most recently used
+ * @param saveINI - if true then we will immediately save the list to the
+ * ini file and have all button visibility checked immediately.
+ * @see #addRecentFile(String)
+ */
+ public void addRecentFile(String _filename, boolean saveINI) {
+ if (!recentFiles.isEmpty() && recentFiles.get(0).equals(_filename)) {
+ return; // nothing to do
+ }
+ if (recentFiles.contains(_filename)) {
+ recentFiles.remove(_filename);
+ }
+ recentFiles.insertElementAt(_filename, 0);
+ while (recentFiles.size() > MAX_RECENT_FILES) {
+ recentFiles.removeElementAt(recentFiles.size() - 1);
+ }
+ // START KGU#602 2018-10-28 - saveINI = false is typically called on startup, so postpone the button stuff too
+ //NSDControl.doButtons();
+ //if (saveINI==true) {NSDControl.savePreferences();}
+ if (saveINI) {
+ NSDControl.doButtons();
+ NSDControl.savePreferences();
+ }
+ // END KGU#602 2018-10-28
+ }
+
+ /*========================================
* Run
*========================================*/
- /**
- * Activates the {@link Executor} forcing open the debug {@link Control}.
- *
- * @see #goTurtle()
- */
- public void goRun() {
- // START KGU#448 2018-01-05: Enh. #443 - generalized DiagramController activation
- //Executor.getInstance(this,null);
- Executor.getInstance(this, this.getEnabledControllers());
- // END KGU#448 2018-01-05
- if (root.advanceTutorialState(26, this.root)) {
- analyse();
- }
- // KGU#908 2021-01-06: Bugfix #907 - the previous three lins were duplicate here
- }
-
- /**
- * Ensures the {@link TurtleBox} being open and activates the
- * {@link Executor} forcing open the debug {@link Control}.
- *
- * @see #goRun()
- */
- public void goTurtle() {
- if (turtle == null) {
- // START KGU#889 2020-12-28: Enh. #890 statusbar needs slightly more width
- //turtle = new TurtleBox(500,500);
- turtle = new TurtleBox(512, 560);
- // END KGU#889 2020-12-28
- // START KGU#685 2020-12-12: Enh. #704
- Locales.getInstance().register(turtle.getFrame(), true);
- turtle.setReverseZoomWheel(Element.E_WHEEL_REVERSE_ZOOM);
- // END KGU#685 2020-12-12
- // START KGU#894 2020-12-21: Issue #895 Wasn't correctly scaled (with "Nimbus")
- turtle.updateLookAndFeel();
- GUIScaler.rescaleComponents(turtle.getFrame());
- // END KGU#894 2020-12-21
- }
- turtle.setVisible(true);
- // Activate the executor (getInstance() is supposed to do that)
- // START KGU#448 2018-01-05: Enh. #443: Cope with potentially several controllers
- //Executor.getInstance(this,turtle);
- this.enableController(turtle.getClass().getName(), true);
- goRun();
- // END KGU#448 2018-01-05
-
- }
-
- /**
- * Checks for running status of the Root currently held and suggests the
- * user to stop the execution if it is running
- *
- * @return true if the fostered Root isn't executed (action may proceed),
- * false otherwise
- */
- private boolean checkRunning() {
- if (this.root == null || !this.root.isExecuted()) {
- return true; // No problem
- } // Give the user the chance to kill the execution but don't do anything for now,
- // whatever the user may have been decided.
- Executor.getInstance(null, null);
- return false;
- }
-
- // START KGU#448 2018-01-05: Enh. #443
- /**
- * Lazy initialization method for static field {@link #diagramControllers}
- *
- * @return the initialized list of {@link DiagramController} instances; the
- * first element (reserved for a {@link TurtleBox)} instance) may be null.
- */
- // START KGU#911 2021-01-10: Enh. #910 Result type changed
- //protected ArrayList getDiagramControllers() {
- protected LinkedHashMap getDiagramControllers() {
- // END KGU#911 2021-01-10
- if (diagramControllers != null) {
- return diagramControllers;
- }
- // START KGU#911 2021-01-10: Enh. #910 data structure changed
- //diagramControllers = new ArrayList();
- // Turtleizer is always added as first entry (no matter whether initialized or not)
- //diagramControllers.add(turtle);
- diagramControllers = new LinkedHashMap();
- // We try to add Turtleizer as first entry
- if (turtle != null) {
- diagramControllers.put(turtle, null);
- }
- // END KGU#911 2021-01-10
- String errors = "";
- Vector plugins = Menu.controllerPlugins;
- if (plugins.isEmpty()) {
- BufferedInputStream buff = null;
- try {
- buff = new BufferedInputStream(getClass().getResourceAsStream("controllers.xml"));
- GENParser genp = new GENParser();
- plugins = genp.parse(buff);
- } catch (Exception ex) {
- errors = ex.toString();
- // START KGU#484 2018-04-05: Issue #463
- //ex.printStackTrace();
- logger.log(Level.WARNING, "Trouble accessing controller plugin definitions.", ex);
- // END KGU#484 2018-04-05
- }
- if (buff != null) {
- try {
- buff.close();
- } catch (IOException ex) {
- // START KGU#484 2018-04-05: Issue #463
- //ex.printStackTrace();
- logger.log(Level.WARNING, "Couldn't close the controller plugin definition file.", ex);
- // END KGU#484 2018-04-05
- }
- }
- }
- for (int i = 0; i < plugins.size(); i++) {
- GENPlugin plugin = plugins.get(i);
- final String className = plugin.className;
- // If it's not Turtleizer then add it to the available controllers
- // START KGU#911 2021-01-10: Bugfix on behalf of #910
- //if (!className.equals("TurtleBox")) {
- if (!className.equals("lu.fisch.turtle.TurtleBox")) {
- // END KGU#911 2021-01-10
- try {
- Class> genClass = Class.forName(className);
- // START KGU#911 2021-01-10: Enh. #910 data structure changed
- //diagramControllers.add((DiagramController) genClass.getDeclaredConstructor().newInstance());
- DiagramController ctrlr = (DiagramController) genClass.getDeclaredConstructor().newInstance();
- // Try to set the name according to the plugin title (does not necessarily work)
- ctrlr.setName(plugin.title);
- Root incl = constructDiagrContrIncludable(ctrlr);
- diagramControllers.put(ctrlr, incl);
- // END KGU#911 2021-01-10
- } catch (Exception ex) {
- errors += "\n" + plugin.title + ": " + ex.getLocalizedMessage();
- }
- }
- }
- if (!errors.isEmpty()) {
- errors = Menu.msgTitleLoadingError.getText() + errors;
- JOptionPane.showMessageDialog(this.getFrame(), errors,
- Menu.msgTitleParserError.getText(), JOptionPane.ERROR_MESSAGE);
- }
- return diagramControllers;
- }
-
- // START KGU#911 2021-01-10: Enh. #910 - We represent DiagramControllers by includables
- /**
- * Constructs a special Includable diagram for the given DiagramController
- * {@code controller} listing all provided routines in the comment and
- * defining specified data type (particularly enumeration types)
- *
- * @param controller - a {@link DiagramController} implementor instance
- * @return a special immutable Includable
- */
- private Root constructDiagrContrIncludable(DiagramController controller) {
- Root incl = new Root(StringList.getNew("$" + controller.getName().replace(" ", "_")));
- incl.setInclude(false);
- StringList comment = new StringList();
- comment.add("Represents Diagram Controller \"" + controller.getName() + "\"");
- comment.add("");
- comment.add("Provided procedures:");
- int count = addRoutineSignatures(controller.getProcedureMap(), comment);
- if (count == 0) {
- comment.add("\t-");
- }
- comment.add("Provided Functions:");
- count = addRoutineSignatures(controller.getFunctionMap(), comment);
- if (count == 0) {
- comment.add("\t-");
- }
- String[] enumDefs = controller.getEnumerators();
- if (enumDefs != null) {
- comment.add("Provided Enumeration Types:");
- count = 0;
- for (int j = 0; j < enumDefs.length; j++) {
- String enumDef = enumDefs[j];
- int posBrace = enumDef.indexOf("{");
- if (posBrace > 0) {
- String typeName = null;
- if (enumDef.startsWith("enum ")) {
- // Seems to be in Java syntax, convert it to Structorizer syntax
- typeName = enumDef.substring(5, posBrace).trim();
- enumDef = ("type " + typeName + " = enum" + enumDef.substring(posBrace)).trim();
- if (enumDef.endsWith(";")) {
- enumDef = enumDef.substring(0, enumDef.length() - 1);
- }
- } else if (enumDef.startsWith("type ")
- && (posBrace = enumDef.substring(0, posBrace).indexOf("=")) > 0) {
- typeName = enumDef.substring(5, posBrace).trim();
- }
- if (typeName != null) {
- comment.add(String.format("%4d. %s", ++count, typeName));
- Instruction typedef = new Instruction(enumDef);
- incl.children.addElement(typedef);
- }
- }
- }
- if (count == 0) {
- comment.add("\t-");
- }
- }
- incl.setComment(comment);
- incl.children.addElement(new Instruction("restart()"));
- incl.setDisabled(true);
- return incl;
- }
-
- /**
- * Retrieves the signatures of the given API routines and adds them to the
- * StringList {@code comment}.
- *
- * @param routines - the procedure or function map of the DiagramController
- * @param comment - the {@link StringList} the routine descriptions are to
- * be added to
- * @return number of routines
- */
- public int addRoutineSignatures(HashMap routines, StringList comment) {
- int count = 0;
- for (Map.Entry entry : routines.entrySet()) {
- String[] parts = entry.getKey().split("#", -1);
- Method meth = entry.getValue();
- if (meth.getName().equalsIgnoreCase(parts[0])) {
- // prefer the true name
- parts[0] = meth.getName();
- }
- Class>[] argTypes = meth.getParameterTypes();
- Class> resType = meth.getReturnType();
- StringList typeNames = new StringList();
- String resTypeName = "";
- if (resType != null && !resType.getName().equals("void")) {
- resTypeName = ": " + resType.getSimpleName();
- }
- for (int i = 0; i < argTypes.length; i++) {
- typeNames.add(argTypes[i].getSimpleName());
- }
-
- comment.add(String.format("%4d. %s(%s)%s", ++count,
- parts[0], typeNames.concatenate(", "), resTypeName));
- }
- return count;
- }
- // END KGU#911 2021-01-10
-
- /**
- * @return an array of {@link DiagramController} instances enabled for
- * execution
- * @see #isControllerEnabled(String)
- * @see #enableController(String, boolean)
- */
- private DiagramController[] getEnabledControllers() {
- this.getDiagramControllers();
- LinkedList controllers = new LinkedList();
- // START KGU#911 2021-01-09: Enh. #910 status now coded in the Includables
- //long mask = 1;
- //for (DiagramController contr: diagramControllers) {
- // if (contr != null && (this.enabledDiagramControllers & mask) != 0) {
- // controllers.add(contr);
- // }
- // mask <<= 1;
- //}
- for (Map.Entry entry : diagramControllers.entrySet()) {
- if (entry.getValue() == null || !entry.getValue().isDisabled(false)) {
- controllers.add(entry.getKey());
- }
- }
- // END KGU#911 2021-01-09
- return controllers.toArray(new DiagramController[controllers.size()]);
- }
- // END KGU#448 2018-01-08
-
- // START KGU#177 2016-04-07: Enh. #158
- /**
- * Tries to shift the selection to the next element in the _direction
- * specified. It turned out that on going down and right it's most intuitive
- * to dive into the substructure of compound elements (rather than jumping
- * to its successor). (For Repeat elements this holds on going up).
- *
- * @param _direction - the cursor key orientation (up, down, left, right)
- */
- public void moveSelection(Editor.CursorMoveDirection _direction) {
- if (selected != null) {
- Rect selRect = selected.getRectOffDrawPoint();
- // Get center coordinates
- int x = (selRect.left + selRect.right) / 2;
- int y = (selRect.top + selRect.bottom) / 2;
- switch (_direction) {
- case CMD_UP:
- // START KGU#495 2018-02-15: Bugfix #511 - we must never dive into collapsed loops!
- //if (selected instanceof Repeat)
- if (selected instanceof Repeat && !selected.isCollapsed(false)) // END KGU#495 2018-02-15
- {
- // START KGU#292 2016-11-16: Bugfix #291
- //y = ((Repeat)selected).getRectOffDrawPoint().bottom - 2;
- y = ((Repeat) selected).getBody().getRectOffDrawPoint().bottom - 2;
- // END KGU#292 2016-11-16
- } else if (selected instanceof Root) {
- y = ((Root) selected).children.getRectOffDrawPoint().bottom - 2;
- } else {
- y = selRect.top - 2;
- }
- break;
- case CMD_DOWN:
- // START KGU#495 2018-02-15: Bugfix #511 - we must never dive into collapsed loops!
- //if (selected instanceof ILoop && !(selected instanceof Repeat))
- if (selected instanceof ILoop && !selected.isCollapsed(false) && !(selected instanceof Repeat)) // END KGU#495 2018-02-15
- {
- Subqueue body = ((ILoop) selected).getBody();
- y = body.getRectOffDrawPoint().top + 2;
- } // START KGU#346 2017-02-08: Issue #198 - Unification of forking elements
- //else if (selected instanceof Alternative)
- //{
- // y = ((Alternative)selected).qTrue.getRectOffDrawPoint().top + 2;
- //}
- //else if (selected instanceof Case)
- //{
- // y = ((Case)selected).qs.get(0).getRectOffDrawPoint().top + 2;
- //}
- // START KGU#498 2018-02-18: Bugfix #511 - cursor was caught when collapsed
- //else if (selected instanceof IFork)
- else if (selected instanceof IFork && !selected.isCollapsed(false)) // END KGU#498 2018-02-18
- {
- y = selRect.top + ((IFork) selected).getHeadRect().bottom + 2;
- } // END KGU#346 2017-02-08
- // START KGU#498 2018-02-18: Bugfix #511 - cursor was caught when collapsed
- //else if (selected instanceof Parallel)
- else if (selected instanceof Parallel && !selected.isCollapsed(false)) // END KGU#498 2018-02-18
- {
- y = ((Parallel) selected).qs.get(0).getRectOffDrawPoint().top + 2;
- } else if (selected instanceof Root) {
- y = ((Root) selected).children.getRectOffDrawPoint().top + 2;
- } // START KGU#729 2019-09-24: Bugfix #751
- else if (selected instanceof Try) {
- y = ((Try) selected).qTry.getRectOffDrawPoint().top + 2;
- } // END KGU#729 2019-09-24
- else {
- y = selRect.bottom + 2;
- }
- break;
- case CMD_LEFT:
- if (selected instanceof Root) {
- Rect bodyRect = ((Root) selected).children.getRectOffDrawPoint();
- // The central element of the subqueue isn't the worst choice because from
- // here the distances are minimal. The top element, on the other hand,
- // is directly reachable by cursor down.
- x = bodyRect.right - 2;
- y = (bodyRect.top + bodyRect.bottom) / 2;
- } else {
- x = selRect.left - 2;
- // START KGU#346 2017-02-08: Bugfix #198: It's more intuitive to stay at header y level
- if (selected instanceof IFork) {
- y = selRect.top + ((IFork) selected).getHeadRect().bottom / 2;
- }
- // END KGU#346 2017-02-08
- }
- break;
- case CMD_RIGHT:
- // START KGU#495 2018-02-15: Bugfix #511 - we must never dive into collapsed loops!
- //if (selected instanceof ILoop)
- if (selected instanceof ILoop && !selected.isCollapsed(false)) // END KGU#495 2018-02-15
- {
- Rect bodyRect = ((ILoop) selected).getBody().getRectOffDrawPoint();
- x = bodyRect.left + 2;
- // The central element of the subqueue isn't the worst choice because from
- // here the distances are minimal. The top element, on the other hand,
- // is directly reachable by cursor down.
- y = (bodyRect.top + bodyRect.bottom) / 2;
- } else if (selected instanceof Root) {
- Rect bodyRect = ((Root) selected).children.getRectOffDrawPoint();
- // The central element of the subqueue isn't the worst choice because from
- // here the distances are minimal. The top element, on the other hand,
- // is directly reachable by cursor down.
- x = bodyRect.left + 2;
- y = (bodyRect.top + bodyRect.bottom) / 2;
- } // START KGU#729 2019-09-24: Bugfix #751
- else if (selected instanceof Try) {
- Rect catchRect = ((Try) selected).qCatch.getRectOffDrawPoint();
- x = catchRect.left + 2;
- y = catchRect.top + 2;
- } // END KGU#729 2019-09-24
- else {
- x = selRect.right + 2;
- // START KGU#346 2017-02-08: Bugfix #198: It's more intuitive to stay at header y level
- if (selected instanceof IFork) {
- y = selRect.top + ((IFork) selected).getHeadRect().bottom / 2;
- }
- // END KGU#346 2017-02-08
- }
- break;
- }
- Element newSel = root.getElementByCoord(x, y, true);
- if (newSel != null) {
- // START KGU#177 2016-04-24: Bugfix - couldn't leave Parallel and Forever elements
- // Compound elements with a lower bar would catch the selection again when their last
- // encorporated element is left downwards. So identify such a situation and leap after
- // the enclosing compound...
- if (_direction == Editor.CursorMoveDirection.CMD_DOWN
- && (newSel instanceof Parallel || newSel instanceof Forever || !Element.E_DIN && newSel instanceof For)
- && newSel.getRectOffDrawPoint().top < selRect.top) {
- newSel = root.getElementByCoord(x, newSel.getRectOffDrawPoint().bottom + 2, true);
- } // END KGU#177 2016-04-24
- // START KGU#214 2016-07-25: Improvement of enh. #158
- else if (_direction == Editor.CursorMoveDirection.CMD_UP
- && (newSel instanceof Forever || !Element.E_DIN && newSel instanceof For)
- && newSel.getRectOffDrawPoint().bottom < selRect.bottom) {
- Subqueue body = ((ILoop) newSel).getBody();
- Element sel = root.getElementByCoord(x, body.getRectOffDrawPoint().bottom - 2, true);
- if (sel != null) {
- newSel = sel;
- }
- } // END KGU#214 2016-07-25
- // START KGU#214 2016-07-31: Issue #158
- else if (newSel instanceof Root && (_direction == Editor.CursorMoveDirection.CMD_LEFT
- || _direction == Editor.CursorMoveDirection.CMD_RIGHT)) {
- newSel = selected; // Stop before the border on boxed diagrams
- } // END KGU#214 2015-07-31
- // START KGU#729 2019-09-24: Bugfix #751
- else if (newSel instanceof Try) {
- Element sel = null;
- if (_direction == Editor.CursorMoveDirection.CMD_UP) {
- // From finally go to catch, from catch to try, from outside to finally
- if (selected == ((Try) newSel).qFinally || selected.isDescendantOf(((Try) newSel).qFinally)) {
- sel = root.getElementByCoord(x, ((Try) newSel).qCatch.getRectOffDrawPoint().bottom - 2, true);
- } else if (selected == ((Try) newSel).qCatch || selected.isDescendantOf(((Try) newSel).qCatch)) {
- sel = root.getElementByCoord(x, ((Try) newSel).qTry.getRectOffDrawPoint().bottom - 2, true);
- } else if (!selected.isDescendantOf(newSel)) {
- sel = root.getElementByCoord(x, ((Try) newSel).qFinally.getRectOffDrawPoint().bottom - 2, true);
- }
- } else if (_direction == Editor.CursorMoveDirection.CMD_DOWN) {
- // From try go to catch, from catch to finally, from finally to subsequent element
- if (selected == ((Try) newSel).qTry || selected.isDescendantOf(((Try) newSel).qTry)) {
- sel = root.getElementByCoord(x, ((Try) newSel).qCatch.getRectOffDrawPoint().top + 2, true);
- } else if (selected == ((Try) newSel).qCatch || selected.isDescendantOf(((Try) newSel).qCatch)) {
- sel = root.getElementByCoord(x, ((Try) newSel).qFinally.getRectOffDrawPoint().top + 2, true);
- } else if (selected == ((Try) newSel).qFinally || selected.isDescendantOf(((Try) newSel).qFinally)) {
- sel = root.getElementByCoord(x, newSel.getRectOffDrawPoint().bottom + 2, true);
- }
- }
- if (sel != null) {
- newSel = sel;
- }
- }
- // END KGU#729 2019-09-24
- selected = newSel;
- }
- // START KGU#214 2016-07-25: Bugfix for enh. #158 - un-boxed Roots didn't catch the selection
- // This was better than to rush around on horizontal wheel activity! Hence fix withdrawn
-// else if (_direction != Editor.CursorMoveDirection.CMD_UP && !root.isNice)
-// {
-// selected = root;
-// }
- // END KGU#214 2016-07-25
- selected = selected.setSelected(true);
-
- // START KGU#177 2016-04-14: Enh. #158 - scroll to the selected element
- //redraw();
- redraw(selected);
- // END KGU#177 2016-04-14
-
- // START KGU#926 2021-02-04: Enh. #926
- this.scrollErrorListToSelected();
- // END KGU#926 2021-02-04
- // START KGU#705 2019-09-24: Enh. #738
- highlightCodeForSelection();
- // END KGU#705 2019-09-24
- // START KGU#177 2016-04-24: Bugfix - buttons haven't been updated
- this.doButtons();
- // END KGU#177 2016-04-24
- }
- }
- // END KGU#177 2016-04-07
-
- // START KGU#206 2016-07-21: Enh. #158 + #197
- /**
- * Tries to expand the selection towards the next element in the _direction
- * specified. This is of course limited to the bounds of the containing
- * Subqueue.
- *
- * @param _direction - the cursor key orientation (up, down)
- */
- public void expandSelection(Editor.SelectionExpandDirection _direction) {
- if (selected != null
- && !(selected instanceof Subqueue)
- && !(selected instanceof Root)) {
- boolean newSelection = false;
- Subqueue sq = (Subqueue) selected.parent;
- Element first = selected;
- Element last = selected;
- // START KGU#866 2020-05-02: Issue #866 improved expansion / reduction strategy
- int anchorOffset = 0;
- boolean atUpperEnd = true; // Is the selection to be modified at upper end?
- boolean atLowerEnd = true; // Is the selection to be modified at lower end?
- // END KGU#866 2020-05-02
- if (selected instanceof SelectedSequence) {
- SelectedSequence sel = (SelectedSequence) selected;
- first = sel.getElement(0);
- last = sel.getElement(sel.getSize() - 1);
- // START KGU#866 2020-05-02: Issue #866 improved expansion / reduction strategy
- anchorOffset = sel.getAnchorOffset();
- atUpperEnd = !sel.wasModifiedBelowAnchor(); // FIXME offset of anchor?
- atLowerEnd = sel.wasModifiedBelowAnchor();
- // END KGU#866 2020-05-02
- }
- int index0 = sq.getIndexOf(first);
- int index1 = sq.getIndexOf(last);
- // START KGU#866 2020-05-02: Issue #866 improved expansion / reduction strategy
- //if (_direction == Editor.SelectionExpandDirection.EXPAND_UP && index0 > 0)
- if (index0 > 0
- && (_direction == Editor.SelectionExpandDirection.EXPAND_TOP
- || _direction == Editor.SelectionExpandDirection.EXPAND_UP && atUpperEnd)) // END KGU#866 2020-05-02
- {
- // START KGU#866 2020-05-02: Issue #866 improved expansion / reduction strategy
- //selected = new SelectedSequence(sq, index0-1, index1);
- selected = new SelectedSequence(sq, index0 - 1, index1, anchorOffset + 1, false);
- // END KGU#866 2020-05-02
- newSelection = true;
- } // START KGU#866 2020-05-02: Issue #866 improved expansion / reduction strategy
- //else if (_direction == Editor.SelectionExpandDirection.EXPAND_DOWN && index1 < sq.getSize()-1)
- else if (index1 < sq.getSize() - 1
- && (_direction == Editor.SelectionExpandDirection.EXPAND_BOTTOM
- || _direction == Editor.SelectionExpandDirection.EXPAND_DOWN && atLowerEnd)) // END KGU#866 2020-05-02
- {
- // START KGU#866 2020-05-02: Issue #866 improved expansion / reduction strategy
- //selected = new SelectedSequence(sq, index0, index1+1, _index1, true);
- selected = new SelectedSequence(sq, index0, index1 + 1, anchorOffset, true);
- // END KGU#866 2020-05-02
- newSelection = true;
- } // START KGU#866 2020-05-02: Issue #866 improved expansion / reduction strategy
- else if (_direction == Editor.SelectionExpandDirection.EXPAND_UP && atLowerEnd) {
- // Reduce at end
- selected.setSelected(false);
- redraw(selected);
- if (index0 + 1 >= index1) {
- // Selected sequence collapses to a single element
- selected = first;
- } else {
- selected = new SelectedSequence(sq, index0, index1 - 1,
- (anchorOffset == index1 - index0 ? anchorOffset - 1 : anchorOffset),
- true);
- }
- newSelection = true;
- } else if (_direction == Editor.SelectionExpandDirection.EXPAND_DOWN && atUpperEnd) {
- // Reduce at start
- selected.setSelected(false);
- redraw(selected);
- if (index0 + 1 >= index1) {
- // Selected sequence collapses to a single element
- selected = last;
- } else {
- selected = new SelectedSequence(sq, index0 + 1, index1,
- (anchorOffset == 0 ? 0 : anchorOffset - 1),
- false);
- }
- newSelection = true;
- }
- // END KGU#866 2020-05-02
- if (newSelection) {
- selected.setSelected(true);
- redraw(selected);
- this.doButtons();
- }
- // START KGU#705 2019-09-24: Enh. #738
- highlightCodeForSelection();
- // END KGU#705 2019-09-24
- }
- }
- // END KGU#206 2016-07-21
-
- @Override
- public void lostOwnership(Clipboard arg0, Transferable arg1) {
- // Nothing to do here
- }
-
- // START KGU#305 2016-12-15: Issues #305, #312
- @Override
- public void valueChanged(ListSelectionEvent ev) {
- if (ev.getSource() == errorlist) {
- // an error list entry has been selected
- // START KGU#565 2018-07-27: Bugfix #569 - content outsourced (as it may also be needed in mouseClicked())
- handleErrorListSelection();
- // END KGU#565 2018-07-27
- }
- }
- // END KGU#305
-
- // START KGU#565 2018-07-27: Bugfix #569 - errorlist selection without index change wasn't recognised
- /**
- * Handles a single-click selection in the {@link #errorlist} (ensures the
- * corresponding diagram element gets selected)
- *
- * @return {@code true} if an {@link Element} was associated with the
- * selected error entry (which will then be the new {@link #selected} value)
- */
- // START KGU#565 2021-01-06: More consistent selection/scroll handling
- //private void handleErrorListSelection() {
- private boolean handleErrorListSelection() {
- // END KGU#565 2021-01-06
- boolean hadElement = false;
- if (errorlist.getSelectedIndex() >= 0) {
- // get the selected error
- DetectedError err = root.errors.get(errorlist.getSelectedIndex());
- Element ele = err.getElement();
- // START KGU 2021-01-06: The scrolling should also be done for an already selected element
- //if (ele != null && ele != selected)
- if (ele != null) // END KGU 2021-01-06
- {
- // START KGU 2021-01-06: see above
- if (ele != selected) {
- // END KGU 2021-01-06
- // deselect the previously selected element (if any)
- if (selected != null) {
- selected.setSelected(false);
- }
- // select the new one
- selected = ele.setSelected(true);
- // START KGU 2021-01-06: See above
- }
- hadElement = true;
- // END KGU 2021-01-06
-
- // redraw the diagram
- // START KGU#276 2016-11-18: Issue #269 - ensure the associated element be visible
- //redraw();
- redraw(ele);
- // END KGU#276 2016-11-18
-
- // do the button thing
- if (NSDControl != null) {
- NSDControl.doButtons();
- }
-
- // START KGU#705 2019-09-24: Enh. #738
- highlightCodeForSelection();
- // END KGU#705 2019-09-24
- errorlist.requestFocusInWindow();
- }
- }
- // START KGU 2021-01-06: See above
- return hadElement;
- // END KGU 2021-01-06
- }
-
- // START KGU#363 2017-05-19: Enh. #372
- /**
- * Opens the {@link AttributeInspector} for the current {@link Root}.
- *
- * @see #inspectAttributes(Root)
- */
- public void attributesNSD() {
- inspectAttributes(root);
- }
-
- /**
- * Opens the {@link AttributeInspector} for the specified {@code _root}.
- *
- * @param _root - a {@link Root} the attributes of which are to be presented
- * @see #attributesNSD()
- */
- public void inspectAttributes(Root _root) {
- RootAttributes licInfo = new RootAttributes(_root);
- AttributeInspector attrInsp = new AttributeInspector(
- this.getFrame(), licInfo);
- hideComments(); // Issue #143: Hide the current comment popup if visible
- // START KGU#911 2021-01-10: Enh. #910: We may not allow any change
- if (_root.isRepresentingDiagramController()) {
- attrInsp.btnOk.setEnabled(false);
- }
- // END KGU#911 2021-01-10
- attrInsp.setVisible(true);
- if (attrInsp.isCommitted()) {
- _root.addUndo(true);
- _root.adoptAttributes(attrInsp.licenseInfo);
- }
- }
- // END KGU#363 2017-05-17
-
- // START KGU#324 2017-05-30: Enh. #415
- public void findAndReplaceNSD() {
- if (this.findDialog == null) {
- findDialog = new FindAndReplace(this);
- }
- hideComments();
- // Even if the Find&Replace dialog had been visible it has now to regain focus
- findDialog.setVisible(true);
- }
-
- /**
- * This only cares for the look and feel update of the Find&Replace dialog
- * (if it is open) and of the Turtleizer.
- */
- protected void updateLookAndFeel() {
- // START KGU#902 2021-01-01: Enh. #903
- try {
- javax.swing.SwingUtilities.updateComponentTreeUI(this.pop);
- } catch (Exception ex) {
- }
- // END KGU#902 2021-01-01
- if (this.findDialog != null) {
- try {
- javax.swing.SwingUtilities.updateComponentTreeUI(this.findDialog);
- // Restore sub-component listeners which might have got lost by the previous operation.
- this.findDialog.adaptToNewLaF();
- } catch (Exception ex) {
- }
- }
- // START KGU#685 2020-12-12: Enh. #704
- if (turtle != null) {
- turtle.updateLookAndFeel();
- }
- // END KGU#685 2020-12-12
- if (this.codeHighlighter != null) {
- this.codeHighlighter = codePreview.getHighlighter();
- this.updateCodePreview();
- }
- }
- // END KGU#324 2017-05-30
-
- // START KGU#324 2017-06-16: Enh. #415 Extracted from Mainform
- /**
- * Caches several settings held in fields to the given {@link Ini} instance
- *
- * @param ini - the {@link Ini} instance (a singleton)
- * @see #fetchIniProperties(Ini)
- */
- public void cacheIniProperties(Ini ini) {
- if (this.currentDirectory != null) {
- ini.setProperty("currentDirectory", this.currentDirectory.getAbsolutePath());
- // START KGU#354 2071-04-26: Enh. #354 Also retain the other directories
- ini.setProperty("lastExportDirectory", this.lastCodeExportDir.getAbsolutePath());
- ini.setProperty("lastImportDirectory", this.lastCodeImportDir.getAbsolutePath());
- ini.setProperty("lastImportFilter", this.lastImportFilter);
- // END KGU#354 2017-04-26
- }
- // START KGU#305 2016-12-15: Enh. #305
- ini.setProperty("index", (this.showingArrangerIndex() ? "1" : "0"));
- // END KGU#305 2016-12-15
- // START KGU#705 2019-09-24: Enh. #738
- ini.setProperty("codePreview", (this.showingCodePreview() ? "1" : "0"));
- // END KGU#705 2019-09-14
- if (this.recentFiles.size() != 0) {
- for (int i = 0; i < this.recentFiles.size(); i++) {
- //System.out.println(i);
- ini.setProperty("recent" + String.valueOf(i), (String) this.recentFiles.get(i));
- }
- }
- // START KGU#602 2018-10-28: Enh. #419
- ini.setProperty("wordWrapLimit", Integer.toString(this.lastWordWrapLimit));
- // END KGU#602 2018-10-28
- // START KGU#654 2019-02-15: Enh. #681
- ini.setProperty("genExportPrefTrigger", Integer.toString(this.generatorProposalTrigger));
- // END KGU#654 2019-02-15
-
- if (this.findDialog != null) {
- this.findDialog.cacheToIni(ini);
- }
- }
- // END KGU#324 2017-06-16
-
- // START KGU#602 2018-10-28: Extracted from Mainform.loadFromIni()
- /**
- * Adopts several settings held in fields from the given {@link Ini}
- * instance
- *
- * @param ini - the {@link Ini} instance (a singleton)
- * @see #cacheIniProperties(Ini)
- */
- public void fetchIniProperties(Ini ini) {
- // current directory
- // START KGU#95 2015-12-04: Fix #42 Don't propose the System root but the user home
- //diagram.currentDirectory = new File(ini.getProperty("currentDirectory", System.getProperty("file.separator")));
- this.currentDirectory = new File(ini.getProperty("currentDirectory", System.getProperty("user.home")));
- // END KGU#95 2015-12-04
- // START KGU#354 2071-04-26: Enh. #354 Also retain the other directories
- this.lastCodeExportDir = new File(ini.getProperty("lastExportDirectory", System.getProperty("user.home")));
- this.lastCodeImportDir = new File(ini.getProperty("lastImportDirectory", System.getProperty("user.home")));
- this.lastImportFilter = ini.getProperty("lastImportDirectory", "");
- // END KGU#354 2017-04-26
- // START KGU#602 2018-10-28: Enh. #419
- try {
- this.lastWordWrapLimit = Integer.parseInt(ini.getProperty("wordWrapLimit", "0"));
- // START KGU#654 2019-02-15: Enh. #681
- this.generatorProposalTrigger = Integer.parseInt(ini.getProperty("genExportPrefTrigger", "5"));
- // END KGU#654 2019-02-15
- } catch (NumberFormatException ex) {
- }
- // END KGU#602 2018-10-28
-
- // recent files
- try {
- for (int i = MAX_RECENT_FILES - 1; i >= 0; i--) {
- if (ini.keySet().contains("recent" + i)) {
- if (!ini.getProperty("recent" + i, "").trim().isEmpty()) {
- this.addRecentFile(ini.getProperty("recent" + i, ""), false);
- }
- }
- }
- } catch (Exception e) {
- logger.log(Level.WARNING, "Ini", e);
- }
- NSDControl.doButtons();
- }
- // END KGU#602 2018-10-28
-
- public void setSimplifiedGUI(boolean _simplified) {
- if (Element.E_REDUCED_TOOLBARS != _simplified) {
- Element.E_REDUCED_TOOLBARS = _simplified;
- for (MyToolbar toolbar : toolbars) {
- if (expertToolbars.contains(toolbar)) {
- // The toolbar is to be hidden completely
- toolbar.setVisible(!_simplified);
- } else {
- // Some speed buttons of the toolbar may have to be hidden
- toolbar.setExpertVisibility(!_simplified);
- }
- }
- Element.cacheToIni();
- }
- }
-
- /**
- * Sets this instance initialized and has it redraw all.
- */
- public void setInitialized() {
- this.isInitialized = true;
- redraw();
- analyse();
- }
-
- // START KGU#459 2017-11-14: Enh. #459-1
- public void showTutorialHint() {
- JOptionPane.showMessageDialog(this.getFrame(),
- Menu.msgGuidedTours.getText(),
- Menu.ttlGuidedTours.getText(),
- JOptionPane.INFORMATION_MESSAGE,
- IconLoader.getIconImage(getClass().getResource("icons/AnalyserHint.png")));
- analyse();
- repaint();
- }
- // END KGU#459 2017-11-14
-
- // START KGU#477 2017-12-06: Enh. #487
- /**
- * Sets the display mode for hiding of mere declarartory element sequences
- * according to the argument.
- *
- * @param _activate - whether to enable or disable the hiding mode.
- */
- public void setHideDeclarations(boolean _activate) {
- Element selectedElement = this.selected;
- Element.E_HIDE_DECL = _activate;
- this.resetDrawingInfo();
- analyse();
- repaint();
- if (selectedElement != null) {
- if (selectedElement instanceof Instruction) {
- selectedElement.setSelected(false);
- selected = selectedElement = ((Instruction) selectedElement).getDrawingSurrogate(false);
- selectedElement.setSelected(true);
- }
- redraw(selectedElement);
- } else {
- redraw();
- }
- // START KGU#705 2019-09-24: Enh. #738
- updateCodePreview();
- // END KGU#705 2019-09-24
- // FIXME: The diagram will not always have been scrolled to the selected element by now...
- }
- // END KGU#477 2017-12-06
-
- // START KGU#479 2017-12-14: Enh. #492
- /**
- * Opens an element designation configurator - this is to allow to discouple
- * element names from localization.
- */
- public void elementNamesNSD() {
- ElementNamePreferences namePrefs = new ElementNamePreferences(this.getFrame());
- for (int i = 0; i < namePrefs.txtElements.length; i++) {
- namePrefs.txtElements[i].setText(ElementNames.configuredNames[i]);
- }
- namePrefs.chkUseConfNames.setSelected(ElementNames.useConfiguredNames);
- namePrefs.setVisible(true);
- if (namePrefs.OK) {
- for (int i = 0; i < namePrefs.txtElements.length; i++) {
- ElementNames.configuredNames[i] = namePrefs.txtElements[i].getText();
- }
- ElementNames.useConfiguredNames = namePrefs.chkUseConfNames.isSelected();
- ElementNames.saveToINI();
- Locales.getInstance().setLocale(Locales.getInstance().getLoadedLocaleName());
- }
- }
- // END KGU#479 2017-12-14
-
- // START KGU#448 2018-01-05: Enh. #443
- /**
- * Ensures field {@link #diagramControllers} being initialized and enables
- * or disables the {@link DiagramController} with class name
- * {@code className} according to the value of {@code selected}.
- *
- * @param className - full class name of a {@link DiagramController}
- * subclass
- * @param selected - if true enables, otherwise disables the specified
- * controller
- * @return true if the specified controller class was found.
- * @see #getEnabledControllers()
- * @see #isControllerEnabled(String)
- */
- public boolean enableController(String className, boolean selected) {
- // Ensure diagramControllers is initialised
- this.getDiagramControllers();
- // START KGU#911 2021-01-10: Enh. #910 Status now held in associated Includables
- //long mask = 1;
- //for (DiagramController controller: diagramControllers) {
- // // The initial position is reserved for the TurtleBox instance, which may not have been created
- // if (controller == null && mask == 1) {
- // diagramControllers.set(0, turtle);
- // controller = turtle;
- // }
- // if (controller != null && controller.getClass().getName().equalsIgnoreCase(className)) {
- // if (selected) {
- // this.enabledDiagramControllers |= mask;
- // }
- // else {
- // this.enabledDiagramControllers &= ~mask;
- // }
- // // START KGU#911 2021-01-09: Enh. #910 We must ensure the possible enumerators
- // analyse();
- // redraw();
- // // END KGU#911 2021-01-09
- // return true;
- // }
- // mask <<= 1;
- //}
- if (turtle != null && !diagramControllers.containsKey(turtle)) {
- diagramControllers.put(turtle, null);
- }
- for (Map.Entry entry : diagramControllers.entrySet()) {
- if (entry.getKey().getClass().getName().equals(className)) {
- Root incl = entry.getValue();
- // Turtleizer (incl == null) cannot be disabled
- if (incl != null) {
- boolean statusChanged = incl.isDisabled(true) == selected;
- incl.setDisabled(!selected);
- if (selected && !Arranger.getInstance().getAllRoots().contains(incl)) {
- Arranger.getInstance().addToPool(incl, this.getFrame(),
- Arranger.DIAGRAM_CONTROLLER_GROUP_NAME);
- // Ensure invisibility of the group and hence the diagram in Arranger
- for (Group group : Arranger.getInstance().getGroupsFromRoot(incl, true)) {
- if (group.getName().equals(Arranger.DIAGRAM_CONTROLLER_GROUP_NAME)) {
- group.setVisible(false);
- break;
- }
- }
- } else if (!selected && Arranger.hasInstance()) {
- Arranger.getInstance().removeDiagram(incl);
- }
- // We must ensure the possible enumerators are visible
- if (statusChanged) {
- this.resetDrawingInfo();
- analyse();
- redraw();
- }
- }
- return true;
- }
- }
- // END KGU#911 2021-01-10
- return false;
- }
- // END KGU#448 2018-01-14
-
- // START KGU#911 2021-01-10: Enh. #910 Added for menu "button" control
- public boolean isControllerEnabled(String className) {
- for (Map.Entry entry : diagramControllers.entrySet()) {
- if (entry.getKey().getClass().getName().equals(className)) {
- return entry.getValue() == null || !entry.getValue().isDisabled(true);
- }
- }
- return false;
- }
- // END KGU#911 2021-01-10
-
- // START KGU#480 2018-01-18: Enh. #490
- /**
- * Opens a dialog allowing to configure alias names for
- * {@link DiagramController} API methods (e.g. for {@link TurtleBox}).
- *
- * @param controllerPlugins - the plugin objects for the available
- * {@link DiagramController}s
- */
- public void controllerAliasesNSD(Vector controllerPlugins) {
- DiagramControllerAliases dialog = new DiagramControllerAliases(this.getFrame(), controllerPlugins);
- dialog.setVisible(true);
- // FIXME: Just temporary - mind Element.controllerName2Alias and Element.controllerAlias2Name
- if (dialog.OK) {
- try {
- Ini.getInstance().save();
- } catch (IOException ex) {
- // START KGU#484 2018-04-05: Issue #463
- //ex.printStackTrace();
- logger.log(Level.WARNING, "Trouble saving preferences.", ex);
- // END KGU#484 2018-04-05
- }
- setApplyAliases(dialog.chkApplyAliases.isSelected());
- }
- }
-
- /**
- * Switches the replacement of {@link DiagramController} routine names with
- * aliases on or off
- *
- * @param apply - new status value
- */
- public void setApplyAliases(boolean apply) {
- Element.E_APPLY_ALIASES = apply;
- this.resetDrawingInfo();
- redraw();
- // START KGU#792 2020-02-04: Bugfix #805
- Ini.getInstance().setProperty("applyAliases", apply ? "1" : "0");
- // END KGU#792 2020-02-04
- }
- // END KGU#480 2018-01-18
-
- // START KGU#356 2019-03-14: Issue #366
- /**
- * @return the owning @{@link JFrame} (actually the {@link Mainform}) or
- * null
- */
- public JFrame getFrame() {
- // START KGU 2019-11-24: Make sure this doesn't cause a NullPointerException
- if (this.NSDControl == null) {
- return null;
- }
- // END KGU 2019-11-24
- return this.NSDControl.getFrame();
- }
- // END KGU#356 2019-03-14
-
- // START KGU#466 2019-08-03: Issue #733 - Selective preferences export
- /**
- * Caches the last used selection pattern in the preference category dialog
- */
- private static Vector prefCategorySelection = new Vector();
-
- /**
- * Opens a dialog allowing to elect preference categories for saving.
- * Composes a set of ini property keys to be stored from the user selection.
- * If the user opts for complete export then the returns set will be empty,
- * if the user cancels then the result will be null.
- *
- * @param title - dialog title
- * @param preferenceKeys - maps preference menu item names to arrays of key
- * patterns
- * @return the set of key patterns for filtering the preference export. may
- * be empty or {@code null}.
- */
- public Set selectPreferencesToExport(String title, HashMap preferenceKeys) {
- double scale = Double.parseDouble(Ini.getInstance().getProperty("scaleFactor", "1"));
- // Fill the selection vector to the necessary size
- for (int j = prefCategorySelection.size(); j < preferenceKeys.size(); j++) {
- prefCategorySelection.add(false);
- }
- Set keys = null;
- JPanel panel = new JPanel();
- JPanel panel1 = new JPanel();
- JPanel panel2 = new JPanel();
- panel1.setLayout(new GridLayout(0, 1));
- panel2.setLayout(new GridLayout(0, 2, (int) (5 * scale), 0));
- panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
- JCheckBox chkAll = new JCheckBox(Menu.msgAllPreferences.getText(), true);
- JCheckBox[] chkCategories = new JCheckBox[preferenceKeys.size()];
- JButton btnInvert = new JButton(Menu.msgInvertSelection.getText());
- int i = 0;
- for (String category : preferenceKeys.keySet()) {
- String msgKey = "Menu." + category + ".text";
- String caption = Locales.getValue("Structorizer", msgKey, true);
- int posEllipse = caption.indexOf("...");
- if (posEllipse > 0) {
- caption = caption.substring(0, posEllipse).trim();
- }
- if (caption.endsWith("?")) {
- caption = caption.substring((caption.startsWith("¿") ? 1 : 0), caption.length() - 1);
- }
- JCheckBox chk = new JCheckBox(caption, prefCategorySelection.get(i));
- (chkCategories[i++] = chk).setEnabled(false);
- if (category.equals("menuDiagram")) {
- chk.setToolTipText(Menu.ttDiagramMenuSettings.getText().replace("%", caption));
- }
- }
- btnInvert.setEnabled(false);
- chkAll.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent evt) {
- boolean sel = chkAll.isSelected();
- for (int i = 0; i < chkCategories.length; i++) {
- chkCategories[i].setEnabled(!sel);
- }
- btnInvert.setEnabled(!sel);
- }
- });
- btnInvert.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- for (int i = 0; i < chkCategories.length; i++) {
- chkCategories[i].setSelected(!chkCategories[i].isSelected());
- }
- }
- });
- panel1.add(chkAll);
- //for (JCheckBox chk: chkCategories) {
- // panel2.add(chk);
- //}
- int offset = (chkCategories.length + 1) / 2;
- for (int j = 0; j < offset; j++) {
- panel2.add(chkCategories[j]);
- if (j + offset < chkCategories.length) {
- panel2.add(chkCategories[j + offset]);
- }
- }
- panel2.add(btnInvert);
- panel.add(panel1);
- panel.add(new JSeparator(SwingConstants.HORIZONTAL));
- panel.add(panel2);
- GUIScaler.rescaleComponents(panel);
- if (JOptionPane.showConfirmDialog(this.getFrame(), panel, title, JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION) {
- keys = new HashSet();
- if (!chkAll.isSelected()) {
- i = 0;
- for (String[] patterns : preferenceKeys.values()) {
- // START KGU#855 2020-04-23: Bugfix #856 didn't collect the correct items
- //if (prefCategorySelection.set(i, chkCategories[i].isSelected())) {
- boolean isSelected = chkCategories[i].isSelected();
- prefCategorySelection.set(i, isSelected);
- if (isSelected) {
- // END KGU#855 2020-04-23
- for (String pattern : patterns) {
- keys.add(pattern);
- }
- }
- i++;
- }
- if (keys.isEmpty()) {
- // If nothing is selected then it doesn't make sense to save anything
- // (and to return an empty here set would mean to save all)
- keys = null;
- }
- }
- }
- return keys;
- }
- // END KGU#466 2019-08-03
+ /**
+ * Activates the {@link Executor} forcing open the debug {@link Control}.
+ *
+ * @see #goTurtle()
+ */
+ public void goRun() {
+ // START KGU#448 2018-01-05: Enh. #443 - generalized DiagramController activation
+ //Executor.getInstance(this,null);
+ Executor.getInstance(this, this.getEnabledControllers());
+ // END KGU#448 2018-01-05
+ if (root.advanceTutorialState(26, this.root)) {
+ analyse();
+ }
+ // KGU#908 2021-01-06: Bugfix #907 - the previous three lins were duplicate here
+ }
+
+ /**
+ * Ensures the {@link TurtleBox} being open and activates the
+ * {@link Executor} forcing open the debug {@link Control}.
+ *
+ * @see #goRun()
+ */
+ public void goTurtle() {
+ if (turtle == null) {
+ // START KGU#889 2020-12-28: Enh. #890 statusbar needs slightly more width
+ //turtle = new TurtleBox(500,500);
+ turtle = new TurtleBox(512, 560);
+ // END KGU#889 2020-12-28
+ // START KGU#685 2020-12-12: Enh. #704
+ Locales.getInstance().register(turtle.getFrame(), true);
+ turtle.setReverseZoomWheel(Element.E_WHEEL_REVERSE_ZOOM);
+ // END KGU#685 2020-12-12
+ // START KGU#894 2020-12-21: Issue #895 Wasn't correctly scaled (with "Nimbus")
+ turtle.updateLookAndFeel();
+ GUIScaler.rescaleComponents(turtle.getFrame());
+ // END KGU#894 2020-12-21
+ }
+ turtle.setVisible(true);
+ // Activate the executor (getInstance() is supposed to do that)
+ // START KGU#448 2018-01-05: Enh. #443: Cope with potentially several controllers
+ //Executor.getInstance(this,turtle);
+ this.enableController(turtle.getClass().getName(), true);
+ goRun();
+ // END KGU#448 2018-01-05
+
+ }
+
+ /**
+ * Checks for running status of the Root currently held and suggests the
+ * user to stop the execution if it is running
+ *
+ * @return true if the fostered Root isn't executed (action may proceed),
+ * false otherwise
+ */
+ private boolean checkRunning() {
+ if (this.root == null || !this.root.isExecuted()) {
+ return true; // No problem
+ } // Give the user the chance to kill the execution but don't do anything for now,
+ // whatever the user may have been decided.
+ Executor.getInstance(null, null);
+ return false;
+ }
+
+ // START KGU#448 2018-01-05: Enh. #443
+ /**
+ * Lazy initialization method for static field {@link #diagramControllers}
+ *
+ * @return the initialized list of {@link DiagramController} instances; the
+ * first element (reserved for a {@link TurtleBox)} instance) may be null.
+ */
+ // START KGU#911 2021-01-10: Enh. #910 Result type changed
+ //protected ArrayList getDiagramControllers() {
+ protected LinkedHashMap getDiagramControllers() {
+ // END KGU#911 2021-01-10
+ if (diagramControllers != null) {
+ return diagramControllers;
+ }
+ // START KGU#911 2021-01-10: Enh. #910 data structure changed
+ //diagramControllers = new ArrayList();
+ // Turtleizer is always added as first entry (no matter whether initialized or not)
+ //diagramControllers.add(turtle);
+ diagramControllers = new LinkedHashMap();
+ // We try to add Turtleizer as first entry
+ if (turtle != null) {
+ diagramControllers.put(turtle, null);
+ }
+ // END KGU#911 2021-01-10
+ String errors = "";
+ Vector plugins = Menu.controllerPlugins;
+ if (plugins.isEmpty()) {
+ BufferedInputStream buff = null;
+ try {
+ buff = new BufferedInputStream(getClass().getResourceAsStream("controllers.xml"));
+ GENParser genp = new GENParser();
+ plugins = genp.parse(buff);
+ } catch (Exception ex) {
+ errors = ex.toString();
+ // START KGU#484 2018-04-05: Issue #463
+ //ex.printStackTrace();
+ logger.log(Level.WARNING, "Trouble accessing controller plugin definitions.", ex);
+ // END KGU#484 2018-04-05
+ }
+ if (buff != null) {
+ try {
+ buff.close();
+ } catch (IOException ex) {
+ // START KGU#484 2018-04-05: Issue #463
+ //ex.printStackTrace();
+ logger.log(Level.WARNING, "Couldn't close the controller plugin definition file.", ex);
+ // END KGU#484 2018-04-05
+ }
+ }
+ }
+ for (int i = 0; i < plugins.size(); i++) {
+ GENPlugin plugin = plugins.get(i);
+ final String className = plugin.className;
+ // If it's not Turtleizer then add it to the available controllers
+ // START KGU#911 2021-01-10: Bugfix on behalf of #910
+ //if (!className.equals("TurtleBox")) {
+ if (!className.equals("lu.fisch.turtle.TurtleBox")) {
+ // END KGU#911 2021-01-10
+ try {
+ Class> genClass = Class.forName(className);
+ // START KGU#911 2021-01-10: Enh. #910 data structure changed
+ //diagramControllers.add((DiagramController) genClass.getDeclaredConstructor().newInstance());
+ DiagramController ctrlr = (DiagramController) genClass.getDeclaredConstructor().newInstance();
+ // Try to set the name according to the plugin title (does not necessarily work)
+ ctrlr.setName(plugin.title);
+ Root incl = constructDiagrContrIncludable(ctrlr);
+ diagramControllers.put(ctrlr, incl);
+ // END KGU#911 2021-01-10
+ } catch (Exception ex) {
+ errors += "\n" + plugin.title + ": " + ex.getLocalizedMessage();
+ }
+ }
+ }
+ if (!errors.isEmpty()) {
+ errors = Menu.msgTitleLoadingError.getText() + errors;
+ JOptionPane.showMessageDialog(this.getFrame(), errors,
+ Menu.msgTitleParserError.getText(), JOptionPane.ERROR_MESSAGE);
+ }
+ return diagramControllers;
+ }
+
+ // START KGU#911 2021-01-10: Enh. #910 - We represent DiagramControllers by includables
+ /**
+ * Constructs a special Includable diagram for the given DiagramController
+ * {@code controller} listing all provided routines in the comment and
+ * defining specified data type (particularly enumeration types)
+ *
+ * @param controller - a {@link DiagramController} implementor instance
+ * @return a special immutable Includable
+ */
+ private Root constructDiagrContrIncludable(DiagramController controller) {
+ Root incl = new Root(StringList.getNew("$" + controller.getName().replace(" ", "_")));
+ incl.setInclude(false);
+ StringList comment = new StringList();
+ comment.add("Represents Diagram Controller \"" + controller.getName() + "\"");
+ comment.add("");
+ comment.add("Provided procedures:");
+ int count = addRoutineSignatures(controller.getProcedureMap(), comment);
+ if (count == 0) {
+ comment.add("\t-");
+ }
+ comment.add("Provided Functions:");
+ count = addRoutineSignatures(controller.getFunctionMap(), comment);
+ if (count == 0) {
+ comment.add("\t-");
+ }
+ String[] enumDefs = controller.getEnumerators();
+ if (enumDefs != null) {
+ comment.add("Provided Enumeration Types:");
+ count = 0;
+ for (int j = 0; j < enumDefs.length; j++) {
+ String enumDef = enumDefs[j];
+ int posBrace = enumDef.indexOf("{");
+ if (posBrace > 0) {
+ String typeName = null;
+ if (enumDef.startsWith("enum ")) {
+ // Seems to be in Java syntax, convert it to Structorizer syntax
+ typeName = enumDef.substring(5, posBrace).trim();
+ enumDef = ("type " + typeName + " = enum" + enumDef.substring(posBrace)).trim();
+ if (enumDef.endsWith(";")) {
+ enumDef = enumDef.substring(0, enumDef.length() - 1);
+ }
+ } else if (enumDef.startsWith("type ")
+ && (posBrace = enumDef.substring(0, posBrace).indexOf("=")) > 0) {
+ typeName = enumDef.substring(5, posBrace).trim();
+ }
+ if (typeName != null) {
+ comment.add(String.format("%4d. %s", ++count, typeName));
+ Instruction typedef = new Instruction(enumDef);
+ incl.children.addElement(typedef);
+ }
+ }
+ }
+ if (count == 0) {
+ comment.add("\t-");
+ }
+ }
+ incl.setComment(comment);
+ incl.children.addElement(new Instruction("restart()"));
+ incl.setDisabled(true);
+ return incl;
+ }
+
+ /**
+ * Retrieves the signatures of the given API routines and adds them to the
+ * StringList {@code comment}.
+ *
+ * @param routines - the procedure or function map of the DiagramController
+ * @param comment - the {@link StringList} the routine descriptions are to
+ * be added to
+ * @return number of routines
+ */
+ public int addRoutineSignatures(HashMap routines, StringList comment) {
+ int count = 0;
+ for (Map.Entry entry : routines.entrySet()) {
+ String[] parts = entry.getKey().split("#", -1);
+ Method meth = entry.getValue();
+ if (meth.getName().equalsIgnoreCase(parts[0])) {
+ // prefer the true name
+ parts[0] = meth.getName();
+ }
+ Class>[] argTypes = meth.getParameterTypes();
+ Class> resType = meth.getReturnType();
+ StringList typeNames = new StringList();
+ String resTypeName = "";
+ if (resType != null && !resType.getName().equals("void")) {
+ resTypeName = ": " + resType.getSimpleName();
+ }
+ for (int i = 0; i < argTypes.length; i++) {
+ typeNames.add(argTypes[i].getSimpleName());
+ }
+
+ comment.add(String.format("%4d. %s(%s)%s", ++count,
+ parts[0], typeNames.concatenate(", "), resTypeName));
+ }
+ return count;
+ }
+ // END KGU#911 2021-01-10
+
+ /**
+ * @return an array of {@link DiagramController} instances enabled for
+ * execution
+ * @see #isControllerEnabled(String)
+ * @see #enableController(String, boolean)
+ */
+ private DiagramController[] getEnabledControllers() {
+ this.getDiagramControllers();
+ LinkedList controllers = new LinkedList();
+ // START KGU#911 2021-01-09: Enh. #910 status now coded in the Includables
+ //long mask = 1;
+ //for (DiagramController contr: diagramControllers) {
+ // if (contr != null && (this.enabledDiagramControllers & mask) != 0) {
+ // controllers.add(contr);
+ // }
+ // mask <<= 1;
+ //}
+ for (Map.Entry entry : diagramControllers.entrySet()) {
+ if (entry.getValue() == null || !entry.getValue().isDisabled(false)) {
+ controllers.add(entry.getKey());
+ }
+ }
+ // END KGU#911 2021-01-09
+ return controllers.toArray(new DiagramController[controllers.size()]);
+ }
+ // END KGU#448 2018-01-08
+
+ // START KGU#177 2016-04-07: Enh. #158
+ /**
+ * Tries to shift the selection to the next element in the _direction
+ * specified. It turned out that on going down and right it's most intuitive
+ * to dive into the substructure of compound elements (rather than jumping
+ * to its successor). (For Repeat elements this holds on going up).
+ *
+ * @param _direction - the cursor key orientation (up, down, left, right)
+ */
+ public void moveSelection(Editor.CursorMoveDirection _direction) {
+ if (selected != null) {
+ Rect selRect = selected.getRectOffDrawPoint();
+ // Get center coordinates
+ int x = (selRect.left + selRect.right) / 2;
+ int y = (selRect.top + selRect.bottom) / 2;
+ switch (_direction) {
+ case CMD_UP:
+ // START KGU#495 2018-02-15: Bugfix #511 - we must never dive into collapsed loops!
+ //if (selected instanceof Repeat)
+ if (selected instanceof Repeat && !selected.isCollapsed(false)) // END KGU#495 2018-02-15
+ {
+ // START KGU#292 2016-11-16: Bugfix #291
+ //y = ((Repeat)selected).getRectOffDrawPoint().bottom - 2;
+ y = ((Repeat) selected).getBody().getRectOffDrawPoint().bottom - 2;
+ // END KGU#292 2016-11-16
+ } else if (selected instanceof Root) {
+ y = ((Root) selected).children.getRectOffDrawPoint().bottom - 2;
+ } else {
+ y = selRect.top - 2;
+ }
+ break;
+ case CMD_DOWN:
+ // START KGU#495 2018-02-15: Bugfix #511 - we must never dive into collapsed loops!
+ //if (selected instanceof ILoop && !(selected instanceof Repeat))
+ if (selected instanceof ILoop && !selected.isCollapsed(false) && !(selected instanceof Repeat)) // END KGU#495 2018-02-15
+ {
+ Subqueue body = ((ILoop) selected).getBody();
+ y = body.getRectOffDrawPoint().top + 2;
+ }
+ // START KGU#346 2017-02-08: Issue #198 - Unification of forking elements
+ //else if (selected instanceof Alternative)
+ //{
+ // y = ((Alternative)selected).qTrue.getRectOffDrawPoint().top + 2;
+ //}
+ //else if (selected instanceof Case)
+ //{
+ // y = ((Case)selected).qs.get(0).getRectOffDrawPoint().top + 2;
+ //}
+ // START KGU#498 2018-02-18: Bugfix #511 - cursor was caught when collapsed
+ //else if (selected instanceof IFork)
+ else if (selected instanceof IFork && !selected.isCollapsed(false)) // END KGU#498 2018-02-18
+ {
+ y = selRect.top + ((IFork) selected).getHeadRect().bottom + 2;
+ }
+ // END KGU#346 2017-02-08
+ // START KGU#498 2018-02-18: Bugfix #511 - cursor was caught when collapsed
+ //else if (selected instanceof Parallel)
+ else if (selected instanceof Parallel && !selected.isCollapsed(false))
+ // END KGU#498 2018-02-18
+ {
+ y = ((Parallel) selected).qs.get(0).getRectOffDrawPoint().top + 2;
+ } else if (selected instanceof Root) {
+ y = ((Root) selected).children.getRectOffDrawPoint().top + 2;
+ }
+ // START KGU#729 2019-09-24: Bugfix #751
+ else if (selected instanceof Try) {
+ y = ((Try) selected).qTry.getRectOffDrawPoint().top + 2;
+ }
+ // END KGU#729 2019-09-24
+ else {
+ y = selRect.bottom + 2;
+ }
+ break;
+ case CMD_LEFT:
+ if (selected instanceof Root) {
+ Rect bodyRect = ((Root) selected).children.getRectOffDrawPoint();
+ // The central element of the subqueue isn't the worst choice because from
+ // here the distances are minimal. The top element, on the other hand,
+ // is directly reachable by cursor down.
+ x = bodyRect.right - 2;
+ y = (bodyRect.top + bodyRect.bottom) / 2;
+ } else {
+ x = selRect.left - 2;
+ // START KGU#346 2017-02-08: Bugfix #198: It's more intuitive to stay at header y level
+ if (selected instanceof IFork) {
+ y = selRect.top + ((IFork) selected).getHeadRect().bottom / 2;
+ }
+ // END KGU#346 2017-02-08
+ }
+ break;
+ case CMD_RIGHT:
+ // START KGU#495 2018-02-15: Bugfix #511 - we must never dive into collapsed loops!
+ //if (selected instanceof ILoop)
+ if (selected instanceof ILoop && !selected.isCollapsed(false))
+ // END KGU#495 2018-02-15
+ {
+ Rect bodyRect = ((ILoop) selected).getBody().getRectOffDrawPoint();
+ x = bodyRect.left + 2;
+ // The central element of the subqueue isn't the worst choice because from
+ // here the distances are minimal. The top element, on the other hand,
+ // is directly reachable by cursor down.
+ y = (bodyRect.top + bodyRect.bottom) / 2;
+ } else if (selected instanceof Root) {
+ Rect bodyRect = ((Root) selected).children.getRectOffDrawPoint();
+ // The central element of the subqueue isn't the worst choice because from
+ // here the distances are minimal. The top element, on the other hand,
+ // is directly reachable by cursor down.
+ x = bodyRect.left + 2;
+ y = (bodyRect.top + bodyRect.bottom) / 2;
+ }
+ // START KGU#729 2019-09-24: Bugfix #751
+ else if (selected instanceof Try) {
+ Rect catchRect = ((Try) selected).qCatch.getRectOffDrawPoint();
+ x = catchRect.left + 2;
+ y = catchRect.top + 2;
+ }
+ // END KGU#729 2019-09-24
+ else {
+ x = selRect.right + 2;
+ // START KGU#346 2017-02-08: Bugfix #198: It's more intuitive to stay at header y level
+ if (selected instanceof IFork) {
+ y = selRect.top + ((IFork) selected).getHeadRect().bottom / 2;
+ }
+ // END KGU#346 2017-02-08
+ }
+ break;
+ }
+ Element newSel = root.getElementByCoord(x, y, true);
+ if (newSel != null) {
+ // START KGU#177 2016-04-24: Bugfix - couldn't leave Parallel and Forever elements
+ // Compound elements with a lower bar would catch the selection again when their last
+ // encorporated element is left downwards. So identify such a situation and leap after
+ // the enclosing compound...
+ if (_direction == Editor.CursorMoveDirection.CMD_DOWN
+ && (newSel instanceof Parallel || newSel instanceof Forever || !Element.E_DIN && newSel instanceof For)
+ && newSel.getRectOffDrawPoint().top < selRect.top) {
+ newSel = root.getElementByCoord(x, newSel.getRectOffDrawPoint().bottom + 2, true);
+ }
+ // END KGU#177 2016-04-24
+ // START KGU#214 2016-07-25: Improvement of enh. #158
+ else if (_direction == Editor.CursorMoveDirection.CMD_UP
+ && (newSel instanceof Forever || !Element.E_DIN && newSel instanceof For)
+ && newSel.getRectOffDrawPoint().bottom < selRect.bottom) {
+ Subqueue body = ((ILoop) newSel).getBody();
+ Element sel = root.getElementByCoord(x, body.getRectOffDrawPoint().bottom - 2, true);
+ if (sel != null) {
+ newSel = sel;
+ }
+ }
+ // END KGU#214 2016-07-25
+ // START KGU#214 2016-07-31: Issue #158
+ else if (newSel instanceof Root && (_direction == Editor.CursorMoveDirection.CMD_LEFT
+ || _direction == Editor.CursorMoveDirection.CMD_RIGHT)) {
+ newSel = selected; // Stop before the border on boxed diagrams
+ }
+ // END KGU#214 2015-07-31
+ // START KGU#729 2019-09-24: Bugfix #751
+ else if (newSel instanceof Try) {
+ Element sel = null;
+ if (_direction == Editor.CursorMoveDirection.CMD_UP) {
+ // From finally go to catch, from catch to try, from outside to finally
+ if (selected == ((Try) newSel).qFinally || selected.isDescendantOf(((Try) newSel).qFinally)) {
+ sel = root.getElementByCoord(x, ((Try) newSel).qCatch.getRectOffDrawPoint().bottom - 2, true);
+ } else if (selected == ((Try) newSel).qCatch || selected.isDescendantOf(((Try) newSel).qCatch)) {
+ sel = root.getElementByCoord(x, ((Try) newSel).qTry.getRectOffDrawPoint().bottom - 2, true);
+ } else if (!selected.isDescendantOf(newSel)) {
+ sel = root.getElementByCoord(x, ((Try) newSel).qFinally.getRectOffDrawPoint().bottom - 2, true);
+ }
+ } else if (_direction == Editor.CursorMoveDirection.CMD_DOWN) {
+ // From try go to catch, from catch to finally, from finally to subsequent element
+ if (selected == ((Try) newSel).qTry || selected.isDescendantOf(((Try) newSel).qTry)) {
+ sel = root.getElementByCoord(x, ((Try) newSel).qCatch.getRectOffDrawPoint().top + 2, true);
+ } else if (selected == ((Try) newSel).qCatch || selected.isDescendantOf(((Try) newSel).qCatch)) {
+ sel = root.getElementByCoord(x, ((Try) newSel).qFinally.getRectOffDrawPoint().top + 2, true);
+ } else if (selected == ((Try) newSel).qFinally || selected.isDescendantOf(((Try) newSel).qFinally)) {
+ sel = root.getElementByCoord(x, newSel.getRectOffDrawPoint().bottom + 2, true);
+ }
+ }
+ if (sel != null) {
+ newSel = sel;
+ }
+ }
+ // END KGU#729 2019-09-24
+ selected = newSel;
+ }
+ // START KGU#214 2016-07-25: Bugfix for enh. #158 - un-boxed Roots didn't catch the selection
+ // This was better than to rush around on horizontal wheel activity! Hence fix withdrawn
+ // else if (_direction != Editor.CursorMoveDirection.CMD_UP && !root.isNice)
+ // {
+ // selected = root;
+ // }
+ // END KGU#214 2016-07-25
+ selected = selected.setSelected(true);
+
+ // START KGU#177 2016-04-14: Enh. #158 - scroll to the selected element
+ //redraw();
+ redraw(selected);
+ // END KGU#177 2016-04-14
+
+ // START KGU#926 2021-02-04: Enh. #926
+ this.scrollErrorListToSelected();
+ // END KGU#926 2021-02-04
+ // START KGU#705 2019-09-24: Enh. #738
+ highlightCodeForSelection();
+ // END KGU#705 2019-09-24
+ // START KGU#177 2016-04-24: Bugfix - buttons haven't been updated
+ this.doButtons();
+ // END KGU#177 2016-04-24
+ }
+ }
+ // END KGU#177 2016-04-07
+
+ // START KGU#206 2016-07-21: Enh. #158 + #197
+ /**
+ * Tries to expand the selection towards the next element in the _direction
+ * specified. This is of course limited to the bounds of the containing
+ * Subqueue.
+ *
+ * @param _direction - the cursor key orientation (up, down)
+ */
+ public void expandSelection(Editor.SelectionExpandDirection _direction) {
+ if (selected != null
+ && !(selected instanceof Subqueue)
+ && !(selected instanceof Root)) {
+ boolean newSelection = false;
+ Subqueue sq = (Subqueue) selected.parent;
+ Element first = selected;
+ Element last = selected;
+ // START KGU#866 2020-05-02: Issue #866 improved expansion / reduction strategy
+ int anchorOffset = 0;
+ boolean atUpperEnd = true; // Is the selection to be modified at upper end?
+ boolean atLowerEnd = true; // Is the selection to be modified at lower end?
+ // END KGU#866 2020-05-02
+ if (selected instanceof SelectedSequence) {
+ SelectedSequence sel = (SelectedSequence) selected;
+ first = sel.getElement(0);
+ last = sel.getElement(sel.getSize() - 1);
+ // START KGU#866 2020-05-02: Issue #866 improved expansion / reduction strategy
+ anchorOffset = sel.getAnchorOffset();
+ atUpperEnd = !sel.wasModifiedBelowAnchor(); // FIXME offset of anchor?
+ atLowerEnd = sel.wasModifiedBelowAnchor();
+ // END KGU#866 2020-05-02
+ }
+ int index0 = sq.getIndexOf(first);
+ int index1 = sq.getIndexOf(last);
+ // START KGU#866 2020-05-02: Issue #866 improved expansion / reduction strategy
+ //if (_direction == Editor.SelectionExpandDirection.EXPAND_UP && index0 > 0)
+ if (index0 > 0
+ && (_direction == Editor.SelectionExpandDirection.EXPAND_TOP
+ || _direction == Editor.SelectionExpandDirection.EXPAND_UP && atUpperEnd))
+ // END KGU#866 2020-05-02
+ {
+ // START KGU#866 2020-05-02: Issue #866 improved expansion / reduction strategy
+ //selected = new SelectedSequence(sq, index0-1, index1);
+ selected = new SelectedSequence(sq, index0 - 1, index1, anchorOffset + 1, false);
+ // END KGU#866 2020-05-02
+ newSelection = true;
+ }
+ // START KGU#866 2020-05-02: Issue #866 improved expansion / reduction strategy
+ //else if (_direction == Editor.SelectionExpandDirection.EXPAND_DOWN && index1 < sq.getSize()-1)
+ else if (index1 < sq.getSize() - 1
+ && (_direction == Editor.SelectionExpandDirection.EXPAND_BOTTOM
+ || _direction == Editor.SelectionExpandDirection.EXPAND_DOWN && atLowerEnd))
+ // END KGU#866 2020-05-02
+ {
+ // START KGU#866 2020-05-02: Issue #866 improved expansion / reduction strategy
+ //selected = new SelectedSequence(sq, index0, index1+1, _index1, true);
+ selected = new SelectedSequence(sq, index0, index1 + 1, anchorOffset, true);
+ // END KGU#866 2020-05-02
+ newSelection = true;
+ }
+ // START KGU#866 2020-05-02: Issue #866 improved expansion / reduction strategy
+ else if (_direction == Editor.SelectionExpandDirection.EXPAND_UP && atLowerEnd) {
+ // Reduce at end
+ selected.setSelected(false);
+ redraw(selected);
+ if (index0 + 1 >= index1) {
+ // Selected sequence collapses to a single element
+ selected = first;
+ } else {
+ selected = new SelectedSequence(sq, index0, index1 - 1,
+ (anchorOffset == index1 - index0 ? anchorOffset - 1 : anchorOffset),
+ true);
+ }
+ newSelection = true;
+ } else if (_direction == Editor.SelectionExpandDirection.EXPAND_DOWN && atUpperEnd) {
+ // Reduce at start
+ selected.setSelected(false);
+ redraw(selected);
+ if (index0 + 1 >= index1) {
+ // Selected sequence collapses to a single element
+ selected = last;
+ } else {
+ selected = new SelectedSequence(sq, index0 + 1, index1,
+ (anchorOffset == 0 ? 0 : anchorOffset - 1),
+ false);
+ }
+ newSelection = true;
+ }
+ // END KGU#866 2020-05-02
+ if (newSelection) {
+ selected.setSelected(true);
+ redraw(selected);
+ this.doButtons();
+ }
+ // START KGU#705 2019-09-24: Enh. #738
+ highlightCodeForSelection();
+ // END KGU#705 2019-09-24
+ }
+ }
+ // END KGU#206 2016-07-21
+
+ @Override
+ public void lostOwnership(Clipboard arg0, Transferable arg1) {
+ // Nothing to do here
+ }
+
+ // START KGU#305 2016-12-15: Issues #305, #312
+ @Override
+ public void valueChanged(ListSelectionEvent ev) {
+ if (ev.getSource() == errorlist) {
+ // an error list entry has been selected
+ // START KGU#565 2018-07-27: Bugfix #569 - content outsourced (as it may also be needed in mouseClicked())
+ handleErrorListSelection();
+ // END KGU#565 2018-07-27
+ }
+ }
+ // END KGU#305
+
+ // START KGU#565 2018-07-27: Bugfix #569 - errorlist selection without index change wasn't recognised
+ /**
+ * Handles a single-click selection in the {@link #errorlist} (ensures the
+ * corresponding diagram element gets selected)
+ *
+ * @return {@code true} if an {@link Element} was associated with the
+ * selected error entry (which will then be the new {@link #selected} value)
+ */
+ // START KGU#565 2021-01-06: More consistent selection/scroll handling
+ //private void handleErrorListSelection() {
+ private boolean handleErrorListSelection() {
+ // END KGU#565 2021-01-06
+ boolean hadElement = false;
+ if (errorlist.getSelectedIndex() >= 0) {
+ // get the selected error
+ DetectedError err = root.errors.get(errorlist.getSelectedIndex());
+ Element ele = err.getElement();
+ // START KGU 2021-01-06: The scrolling should also be done for an already selected element
+ //if (ele != null && ele != selected)
+ if (ele != null)
+ // END KGU 2021-01-06
+ {
+ // START KGU 2021-01-06: see above
+ if (ele != selected) {
+ // END KGU 2021-01-06
+ // deselect the previously selected element (if any)
+ if (selected != null) {
+ selected.setSelected(false);
+ }
+ // select the new one
+ selected = ele.setSelected(true);
+ // START KGU 2021-01-06: See above
+ }
+ hadElement = true;
+ // END KGU 2021-01-06
+
+ // redraw the diagram
+ // START KGU#276 2016-11-18: Issue #269 - ensure the associated element be visible
+ //redraw();
+ redraw(ele);
+ // END KGU#276 2016-11-18
+
+ // do the button thing
+ if (NSDControl != null) {
+ NSDControl.doButtons();
+ }
+
+ // START KGU#705 2019-09-24: Enh. #738
+ highlightCodeForSelection();
+ // END KGU#705 2019-09-24
+ errorlist.requestFocusInWindow();
+ }
+ }
+ // START KGU 2021-01-06: See above
+ return hadElement;
+ // END KGU 2021-01-06
+ }
+
+ // START KGU#363 2017-05-19: Enh. #372
+ /**
+ * Opens the {@link AttributeInspector} for the current {@link Root}.
+ *
+ * @see #inspectAttributes(Root)
+ */
+ public void attributesNSD() {
+ inspectAttributes(root);
+ }
+
+ /**
+ * Opens the {@link AttributeInspector} for the specified {@code _root}.
+ *
+ * @param _root - a {@link Root} the attributes of which are to be presented
+ * @see #attributesNSD()
+ */
+ public void inspectAttributes(Root _root) {
+ RootAttributes licInfo = new RootAttributes(_root);
+ AttributeInspector attrInsp = new AttributeInspector(
+ this.getFrame(), licInfo);
+ hideComments(); // Issue #143: Hide the current comment popup if visible
+ // START KGU#911 2021-01-10: Enh. #910: We may not allow any change
+ if (_root.isRepresentingDiagramController()) {
+ attrInsp.btnOk.setEnabled(false);
+ }
+ // END KGU#911 2021-01-10
+ attrInsp.setVisible(true);
+ if (attrInsp.isCommitted()) {
+ _root.addUndo(true);
+ _root.adoptAttributes(attrInsp.licenseInfo);
+ }
+ }
+ // END KGU#363 2017-05-17
+
+ // START KGU#324 2017-05-30: Enh. #415
+ public void findAndReplaceNSD() {
+ if (this.findDialog == null) {
+ findDialog = new FindAndReplace(this);
+ }
+ hideComments();
+ // Even if the Find&Replace dialog had been visible it has now to regain focus
+ findDialog.setVisible(true);
+ }
+
+ /**
+ * This only cares for the look and feel update of the Find&Replace dialog
+ * (if it is open) and of the Turtleizer.
+ */
+ protected void updateLookAndFeel() {
+ // START KGU#902 2021-01-01: Enh. #903
+ try {
+ javax.swing.SwingUtilities.updateComponentTreeUI(this.pop);
+ } catch (Exception ex) {
+ }
+ // END KGU#902 2021-01-01
+ if (this.findDialog != null) {
+ try {
+ javax.swing.SwingUtilities.updateComponentTreeUI(this.findDialog);
+ // Restore sub-component listeners which might have got lost by the previous operation.
+ this.findDialog.adaptToNewLaF();
+ } catch (Exception ex) {
+ }
+ }
+ // START KGU#685 2020-12-12: Enh. #704
+ if (turtle != null) {
+ turtle.updateLookAndFeel();
+ }
+ // END KGU#685 2020-12-12
+ if (this.codeHighlighter != null) {
+ this.codeHighlighter = codePreview.getHighlighter();
+ this.updateCodePreview();
+ }
+ }
+ // END KGU#324 2017-05-30
+
+ // START KGU#324 2017-06-16: Enh. #415 Extracted from Mainform
+ /**
+ * Caches several settings held in fields to the given {@link Ini} instance
+ *
+ * @param ini - the {@link Ini} instance (a singleton)
+ * @see #fetchIniProperties(Ini)
+ */
+ public void cacheIniProperties(Ini ini) {
+ if (this.currentDirectory != null) {
+ ini.setProperty("currentDirectory", this.currentDirectory.getAbsolutePath());
+ // START KGU#354 2071-04-26: Enh. #354 Also retain the other directories
+ ini.setProperty("lastExportDirectory", this.lastCodeExportDir.getAbsolutePath());
+ ini.setProperty("lastImportDirectory", this.lastCodeImportDir.getAbsolutePath());
+ ini.setProperty("lastImportFilter", this.lastImportFilter);
+ // END KGU#354 2017-04-26
+ }
+ // START KGU#305 2016-12-15: Enh. #305
+ ini.setProperty("index", (this.showingArrangerIndex() ? "1" : "0"));
+ // END KGU#305 2016-12-15
+ // START KGU#705 2019-09-24: Enh. #738
+ ini.setProperty("codePreview", (this.showingCodePreview() ? "1" : "0"));
+ // END KGU#705 2019-09-14
+ if (this.recentFiles.size() != 0) {
+ for (int i = 0; i < this.recentFiles.size(); i++) {
+ //System.out.println(i);
+ ini.setProperty("recent" + String.valueOf(i), (String) this.recentFiles.get(i));
+ }
+ }
+ // START KGU#602 2018-10-28: Enh. #419
+ ini.setProperty("wordWrapLimit", Integer.toString(this.lastWordWrapLimit));
+ // END KGU#602 2018-10-28
+ // START KGU#654 2019-02-15: Enh. #681
+ ini.setProperty("genExportPrefTrigger", Integer.toString(this.generatorProposalTrigger));
+ // END KGU#654 2019-02-15
+
+ if (this.findDialog != null) {
+ this.findDialog.cacheToIni(ini);
+ }
+ }
+ // END KGU#324 2017-06-16
+
+ // START KGU#602 2018-10-28: Extracted from Mainform.loadFromIni()
+ /**
+ * Adopts several settings held in fields from the given {@link Ini}
+ * instance
+ *
+ * @param ini - the {@link Ini} instance (a singleton)
+ * @see #cacheIniProperties(Ini)
+ */
+ public void fetchIniProperties(Ini ini) {
+ // current directory
+ // START KGU#95 2015-12-04: Fix #42 Don't propose the System root but the user home
+ //diagram.currentDirectory = new File(ini.getProperty("currentDirectory", System.getProperty("file.separator")));
+ this.currentDirectory = new File(ini.getProperty("currentDirectory", System.getProperty("user.home")));
+ // END KGU#95 2015-12-04
+ // START KGU#354 2071-04-26: Enh. #354 Also retain the other directories
+ this.lastCodeExportDir = new File(ini.getProperty("lastExportDirectory", System.getProperty("user.home")));
+ this.lastCodeImportDir = new File(ini.getProperty("lastImportDirectory", System.getProperty("user.home")));
+ this.lastImportFilter = ini.getProperty("lastImportDirectory", "");
+ // END KGU#354 2017-04-26
+ // START KGU#602 2018-10-28: Enh. #419
+ try {
+ this.lastWordWrapLimit = Integer.parseInt(ini.getProperty("wordWrapLimit", "0"));
+ // START KGU#654 2019-02-15: Enh. #681
+ this.generatorProposalTrigger = Integer.parseInt(ini.getProperty("genExportPrefTrigger", "5"));
+ // END KGU#654 2019-02-15
+ } catch (NumberFormatException ex) {
+ }
+ // END KGU#602 2018-10-28
+
+ // recent files
+ try {
+ for (int i = MAX_RECENT_FILES - 1; i >= 0; i--) {
+ if (ini.keySet().contains("recent" + i)) {
+ if (!ini.getProperty("recent" + i, "").trim().isEmpty()) {
+ this.addRecentFile(ini.getProperty("recent" + i, ""), false);
+ }
+ }
+ }
+ } catch (Exception e) {
+ logger.log(Level.WARNING, "Ini", e);
+ }
+ NSDControl.doButtons();
+ }
+ // END KGU#602 2018-10-28
+
+ public void setSimplifiedGUI(boolean _simplified) {
+ if (Element.E_REDUCED_TOOLBARS != _simplified) {
+ Element.E_REDUCED_TOOLBARS = _simplified;
+ for (MyToolbar toolbar : toolbars) {
+ if (expertToolbars.contains(toolbar)) {
+ // The toolbar is to be hidden completely
+ toolbar.setVisible(!_simplified);
+ } else {
+ // Some speed buttons of the toolbar may have to be hidden
+ toolbar.setExpertVisibility(!_simplified);
+ }
+ }
+ Element.cacheToIni();
+ }
+ }
+
+ /**
+ * Sets this instance initialized and has it redraw all.
+ */
+ public void setInitialized() {
+ this.isInitialized = true;
+ redraw();
+ analyse();
+ }
+
+ // START KGU#459 2017-11-14: Enh. #459-1
+ public void showTutorialHint() {
+ JOptionPane.showMessageDialog(this.getFrame(),
+ Menu.msgGuidedTours.getText(),
+ Menu.ttlGuidedTours.getText(),
+ JOptionPane.INFORMATION_MESSAGE,
+ IconLoader.getIconImage(getClass().getResource("icons/AnalyserHint.png")));
+ analyse();
+ repaint();
+ }
+ // END KGU#459 2017-11-14
+
+ // START KGU#477 2017-12-06: Enh. #487
+ /**
+ * Sets the display mode for hiding of mere declarartory element sequences
+ * according to the argument.
+ *
+ * @param _activate - whether to enable or disable the hiding mode.
+ */
+ public void setHideDeclarations(boolean _activate) {
+ Element selectedElement = this.selected;
+ Element.E_HIDE_DECL = _activate;
+ this.resetDrawingInfo();
+ analyse();
+ repaint();
+ if (selectedElement != null) {
+ if (selectedElement instanceof Instruction) {
+ selectedElement.setSelected(false);
+ selected = selectedElement = ((Instruction) selectedElement).getDrawingSurrogate(false);
+ selectedElement.setSelected(true);
+ }
+ redraw(selectedElement);
+ } else {
+ redraw();
+ }
+ // START KGU#705 2019-09-24: Enh. #738
+ updateCodePreview();
+ // END KGU#705 2019-09-24
+ // FIXME: The diagram will not always have been scrolled to the selected element by now...
+ }
+ // END KGU#477 2017-12-06
+
+ // START KGU#479 2017-12-14: Enh. #492
+ /**
+ * Opens an element designation configurator - this is to allow to discouple
+ * element names from localization.
+ */
+ public void elementNamesNSD() {
+ ElementNamePreferences namePrefs = new ElementNamePreferences(this.getFrame());
+ for (int i = 0; i < namePrefs.txtElements.length; i++) {
+ namePrefs.txtElements[i].setText(ElementNames.configuredNames[i]);
+ }
+ namePrefs.chkUseConfNames.setSelected(ElementNames.useConfiguredNames);
+ namePrefs.setVisible(true);
+ if (namePrefs.OK) {
+ for (int i = 0; i < namePrefs.txtElements.length; i++) {
+ ElementNames.configuredNames[i] = namePrefs.txtElements[i].getText();
+ }
+ ElementNames.useConfiguredNames = namePrefs.chkUseConfNames.isSelected();
+ ElementNames.saveToINI();
+ Locales.getInstance().setLocale(Locales.getInstance().getLoadedLocaleName());
+ }
+ }
+ // END KGU#479 2017-12-14
+
+ // START KGU#448 2018-01-05: Enh. #443
+ /**
+ * Ensures field {@link #diagramControllers} being initialized and enables
+ * or disables the {@link DiagramController} with class name
+ * {@code className} according to the value of {@code selected}.
+ *
+ * @param className - full class name of a {@link DiagramController}
+ * subclass
+ * @param selected - if true enables, otherwise disables the specified
+ * controller
+ * @return true if the specified controller class was found.
+ * @see #getEnabledControllers()
+ * @see #isControllerEnabled(String)
+ */
+ public boolean enableController(String className, boolean selected) {
+ // Ensure diagramControllers is initialised
+ this.getDiagramControllers();
+ // START KGU#911 2021-01-10: Enh. #910 Status now held in associated Includables
+ //long mask = 1;
+ //for (DiagramController controller: diagramControllers) {
+ // // The initial position is reserved for the TurtleBox instance, which may not have been created
+ // if (controller == null && mask == 1) {
+ // diagramControllers.set(0, turtle);
+ // controller = turtle;
+ // }
+ // if (controller != null && controller.getClass().getName().equalsIgnoreCase(className)) {
+ // if (selected) {
+ // this.enabledDiagramControllers |= mask;
+ // }
+ // else {
+ // this.enabledDiagramControllers &= ~mask;
+ // }
+ // // START KGU#911 2021-01-09: Enh. #910 We must ensure the possible enumerators
+ // analyse();
+ // redraw();
+ // // END KGU#911 2021-01-09
+ // return true;
+ // }
+ // mask <<= 1;
+ //}
+ if (turtle != null && !diagramControllers.containsKey(turtle)) {
+ diagramControllers.put(turtle, null);
+ }
+ for (Map.Entry entry : diagramControllers.entrySet()) {
+ if (entry.getKey().getClass().getName().equals(className)) {
+ Root incl = entry.getValue();
+ // Turtleizer (incl == null) cannot be disabled
+ if (incl != null) {
+ boolean statusChanged = incl.isDisabled(true) == selected;
+ incl.setDisabled(!selected);
+ if (selected && !Arranger.getInstance().getAllRoots().contains(incl)) {
+ Arranger.getInstance().addToPool(incl, this.getFrame(),
+ Arranger.DIAGRAM_CONTROLLER_GROUP_NAME);
+ // Ensure invisibility of the group and hence the diagram in Arranger
+ for (Group group : Arranger.getInstance().getGroupsFromRoot(incl, true)) {
+ if (group.getName().equals(Arranger.DIAGRAM_CONTROLLER_GROUP_NAME)) {
+ group.setVisible(false);
+ break;
+ }
+ }
+ } else if (!selected && Arranger.hasInstance()) {
+ Arranger.getInstance().removeDiagram(incl);
+ }
+ // We must ensure the possible enumerators are visible
+ if (statusChanged) {
+ this.resetDrawingInfo();
+ analyse();
+ redraw();
+ }
+ }
+ return true;
+ }
+ }
+ // END KGU#911 2021-01-10
+ return false;
+ }
+ // END KGU#448 2018-01-14
+
+ // START KGU#911 2021-01-10: Enh. #910 Added for menu "button" control
+ public boolean isControllerEnabled(String className) {
+ for (Map.Entry entry : diagramControllers.entrySet()) {
+ if (entry.getKey().getClass().getName().equals(className)) {
+ return entry.getValue() == null || !entry.getValue().isDisabled(true);
+ }
+ }
+ return false;
+ }
+ // END KGU#911 2021-01-10
+
+ // START KGU#480 2018-01-18: Enh. #490
+ /**
+ * Opens a dialog allowing to configure alias names for
+ * {@link DiagramController} API methods (e.g. for {@link TurtleBox}).
+ *
+ * @param controllerPlugins - the plugin objects for the available
+ * {@link DiagramController}s
+ */
+ public void controllerAliasesNSD(Vector controllerPlugins) {
+ DiagramControllerAliases dialog = new DiagramControllerAliases(this.getFrame(), controllerPlugins);
+ dialog.setVisible(true);
+ // FIXME: Just temporary - mind Element.controllerName2Alias and Element.controllerAlias2Name
+ if (dialog.OK) {
+ try {
+ Ini.getInstance().save();
+ } catch (IOException ex) {
+ // START KGU#484 2018-04-05: Issue #463
+ //ex.printStackTrace();
+ logger.log(Level.WARNING, "Trouble saving preferences.", ex);
+ // END KGU#484 2018-04-05
+ }
+ setApplyAliases(dialog.chkApplyAliases.isSelected());
+ }
+ }
+
+ /**
+ * Switches the replacement of {@link DiagramController} routine names with
+ * aliases on or off
+ *
+ * @param apply - new status value
+ */
+ public void setApplyAliases(boolean apply) {
+ Element.E_APPLY_ALIASES = apply;
+ this.resetDrawingInfo();
+ redraw();
+ // START KGU#792 2020-02-04: Bugfix #805
+ Ini.getInstance().setProperty("applyAliases", apply ? "1" : "0");
+ // END KGU#792 2020-02-04
+ }
+ // END KGU#480 2018-01-18
+
+ // START KGU#356 2019-03-14: Issue #366
+ /**
+ * @return the owning @{@link JFrame} (actually the {@link Mainform}) or
+ * null
+ */
+ public JFrame getFrame() {
+ // START KGU 2019-11-24: Make sure this doesn't cause a NullPointerException
+ if (this.NSDControl == null) {
+ return null;
+ }
+ // END KGU 2019-11-24
+ return this.NSDControl.getFrame();
+ }
+ // END KGU#356 2019-03-14
+
+ // START KGU#466 2019-08-03: Issue #733 - Selective preferences export
+ /**
+ * Caches the last used selection pattern in the preference category dialog
+ */
+ private static Vector prefCategorySelection = new Vector();
+
+ /**
+ * Opens a dialog allowing to elect preference categories for saving.
+ * Composes a set of ini property keys to be stored from the user selection.
+ * If the user opts for complete export then the returns set will be empty,
+ * if the user cancels then the result will be null.
+ *
+ * @param title - dialog title
+ * @param preferenceKeys - maps preference menu item names to arrays of key
+ * patterns
+ * @return the set of key patterns for filtering the preference export. may
+ * be empty or {@code null}.
+ */
+ public Set selectPreferencesToExport(String title, HashMap preferenceKeys) {
+ double scale = Double.parseDouble(Ini.getInstance().getProperty("scaleFactor", "1"));
+ // Fill the selection vector to the necessary size
+ for (int j = prefCategorySelection.size(); j < preferenceKeys.size(); j++) {
+ prefCategorySelection.add(false);
+ }
+ Set keys = null;
+ JPanel panel = new JPanel();
+ JPanel panel1 = new JPanel();
+ JPanel panel2 = new JPanel();
+ panel1.setLayout(new GridLayout(0, 1));
+ panel2.setLayout(new GridLayout(0, 2, (int) (5 * scale), 0));
+ panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
+ JCheckBox chkAll = new JCheckBox(Menu.msgAllPreferences.getText(), true);
+ JCheckBox[] chkCategories = new JCheckBox[preferenceKeys.size()];
+ JButton btnInvert = new JButton(Menu.msgInvertSelection.getText());
+ int i = 0;
+ for (String category : preferenceKeys.keySet()) {
+ String msgKey = "Menu." + category + ".text";
+ String caption = Locales.getValue("Structorizer", msgKey, true);
+ int posEllipse = caption.indexOf("...");
+ if (posEllipse > 0) {
+ caption = caption.substring(0, posEllipse).trim();
+ }
+ if (caption.endsWith("?")) {
+ caption = caption.substring((caption.startsWith("¿") ? 1 : 0), caption.length() - 1);
+ }
+ JCheckBox chk = new JCheckBox(caption, prefCategorySelection.get(i));
+ (chkCategories[i++] = chk).setEnabled(false);
+ if (category.equals("menuDiagram")) {
+ chk.setToolTipText(Menu.ttDiagramMenuSettings.getText().replace("%", caption));
+ }
+ }
+ btnInvert.setEnabled(false);
+ chkAll.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent evt) {
+ boolean sel = chkAll.isSelected();
+ for (int i = 0; i < chkCategories.length; i++) {
+ chkCategories[i].setEnabled(!sel);
+ }
+ btnInvert.setEnabled(!sel);
+ }
+ });
+ btnInvert.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ for (int i = 0; i < chkCategories.length; i++) {
+ chkCategories[i].setSelected(!chkCategories[i].isSelected());
+ }
+ }
+ });
+ panel1.add(chkAll);
+ //for (JCheckBox chk: chkCategories) {
+ // panel2.add(chk);
+ //}
+ int offset = (chkCategories.length + 1) / 2;
+ for (int j = 0; j < offset; j++) {
+ panel2.add(chkCategories[j]);
+ if (j + offset < chkCategories.length) {
+ panel2.add(chkCategories[j + offset]);
+ }
+ }
+ panel2.add(btnInvert);
+ panel.add(panel1);
+ panel.add(new JSeparator(SwingConstants.HORIZONTAL));
+ panel.add(panel2);
+ GUIScaler.rescaleComponents(panel);
+ if (JOptionPane.showConfirmDialog(this.getFrame(), panel, title, JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION) {
+ keys = new HashSet();
+ if (!chkAll.isSelected()) {
+ i = 0;
+ for (String[] patterns : preferenceKeys.values()) {
+ // START KGU#855 2020-04-23: Bugfix #856 didn't collect the correct items
+ //if (prefCategorySelection.set(i, chkCategories[i].isSelected())) {
+ boolean isSelected = chkCategories[i].isSelected();
+ prefCategorySelection.set(i, isSelected);
+ if (isSelected) {
+ // END KGU#855 2020-04-23
+ for (String pattern : patterns) {
+ keys.add(pattern);
+ }
+ }
+ i++;
+ }
+ if (keys.isEmpty()) {
+ // If nothing is selected then it doesn't make sense to save anything
+ // (and to return an empty here set would mean to save all)
+ keys = null;
+ }
+ }
+ }
+ return keys;
+ }
+ // END KGU#466 2019-08-03
}
diff --git a/src/lu/fisch/structorizer/gui/changelog.txt b/src/lu/fisch/structorizer/gui/changelog.txt
index 082df0c2..2cc9296b 100644
--- a/src/lu/fisch/structorizer/gui/changelog.txt
+++ b/src/lu/fisch/structorizer/gui/changelog.txt
@@ -19,7 +19,7 @@ Known issues:
- Shell export neither copes with nested array/record initialisers and component access
nor with cleanly handling usual and associative arrays as parameters or results.
-Current development version 3.31-02 (2021-03-08)
+Current development version 3.31-03 (2021-04-09)
- 01: Bugfix #851/2: COBOL import: SPECIAL-NAMES sections caused parser abort <2>
- 01: Bugfix #851/3: COBOL import flaws concerning floating-point literals <2>:
- Decimal and float literals weren't recognised,
@@ -40,6 +40,7 @@ Current development version 3.31-02 (2021-03-08)
- 02: Substantial progress in the Italian localisation
- 02: Localisations for plugin-specific import options added (DE, ES) <2>
- 02: Issue #964: Processing import shall not place a draw() loop without draw() <2>
+- 03: Enh. #967: Generator for ARM code introduced
Version: 3.31 (2021-03-01)
- 01: Bugfix #759: Dried up another source of stale Mainforms. <2>
diff --git a/src/lu/fisch/utils/StringList.java b/src/lu/fisch/utils/StringList.java
index 26e8fdd4..67ad1d6e 100644
--- a/src/lu/fisch/utils/StringList.java
+++ b/src/lu/fisch/utils/StringList.java
@@ -16,48 +16,49 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see .
- */
+*/
+
package lu.fisch.utils;
-/**
- * ****************************************************************************************************
+/******************************************************************************************************
*
- * Author: Bob Fisch
+ * Author: Bob Fisch
*
- * Description: A dynamic list of strings. Copies the behaviour of a
- * "TStringList" in Delphi.
+ * Description: A dynamic list of strings.
+ * Copies the behaviour of a "TStringList" in Delphi.
*
******************************************************************************************************
*
- * Revision List
+ * Revision List
*
- * Author Date Description ------ ---- ----------- Bob Fisch 2007.12.09 First
- * Issue Kay Gürtzig 2015.11.04 Methods indexOf added. Kay Gürtzig 2015.11.24
- * Method clear added. Kay Gürtzig 2015.12.01 Methods replaceAll, replaceAllCi
- * added. Kay Gürtzig 2015.12.01 Methods concatenate(...) added; getText() etc.
- * reduced to them. Kay Gürtzig 2016.01.08 Method replaceAllBetween() added,
- * replaceAll etc. reduced to it. Kay Gürtzig 2016.03.26 Method subSequence()
- * added. Kay Gürtzig 2016.04.03 Method int removeAll(StringList, int, boolean)
- * added Bob Fisch 2016.08.01 added method "toArray()" and "remove(int)" (which
- * is a synonym to delete(int)) Kay Gürtzig 2017.01.31 Method remove(int,int)
- * added. Kay Gürtzig 2017.03.31 Methods addOrderedIfNew and addByLengthIfNew
- * revised (now with return value) Kay Gürtzig 2017.06.18 Methods
- * explodeWithDelimiter() revised (don't mistake '_by' for a regex anymore) Kay
- * Gürtzig 2017.10.02 New functional variant with null separator for methods
- * concatenate(...) Kay Gürtzig 2017.10.28 Method trim() added. Kay Gürtzig
- * 2019-02-15 Method isEmpty() added Kay Gürtzig 2019-03-03 Bugfix in method
- * explodeFirstOnly(String, String) Kay Gürtzig 2019-03-05 New method variants
- * explodeWithDelimiter() for case-independent splitting Kay Gürtzig 2019-11-20
- * New methods count(String), count(String, boolean), insert(StringList, int)
- * Kay Gürtzig 2020-03-18 Internal bugfix KGU#827 in toString, getCommaText() -
- * caused errors with null elements
+ * Author Date Description
+ * ------ ---- -----------
+ * Bob Fisch 2007.12.09 First Issue
+ * Kay Gürtzig 2015.11.04 Methods indexOf added.
+ * Kay Gürtzig 2015.11.24 Method clear added.
+ * Kay Gürtzig 2015.12.01 Methods replaceAll, replaceAllCi added.
+ * Kay Gürtzig 2015.12.01 Methods concatenate(...) added; getText() etc. reduced to them.
+ * Kay Gürtzig 2016.01.08 Method replaceAllBetween() added, replaceAll etc. reduced to it.
+ * Kay Gürtzig 2016.03.26 Method subSequence() added.
+ * Kay Gürtzig 2016.04.03 Method int removeAll(StringList, int, boolean) added
+ * Bob Fisch 2016.08.01 added method "toArray()" and "remove(int)" (which is a synonym to delete(int))
+ * Kay Gürtzig 2017.01.31 Method remove(int,int) added.
+ * Kay Gürtzig 2017.03.31 Methods addOrderedIfNew and addByLengthIfNew revised (now with return value)
+ * Kay Gürtzig 2017.06.18 Methods explodeWithDelimiter() revised (don't mistake '_by' for a regex anymore)
+ * Kay Gürtzig 2017.10.02 New functional variant with null separator for methods concatenate(...)
+ * Kay Gürtzig 2017.10.28 Method trim() added.
+ * Kay Gürtzig 2019-02-15 Method isEmpty() added
+ * Kay Gürtzig 2019-03-03 Bugfix in method explodeFirstOnly(String, String)
+ * Kay Gürtzig 2019-03-05 New method variants explodeWithDelimiter() for case-independent splitting
+ * Kay Gürtzig 2019-11-20 New methods count(String), count(String, boolean), insert(StringList, int)
+ * Kay Gürtzig 2020-03-18 Internal bugfix KGU#827 in toString, getCommaText() - caused errors with null elements
*
******************************************************************************************************
*
- * Comment: /
+ * Comment: /
*
- *****************************************************************************************************
- */
+ ******************************************************************************************************/
+
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
@@ -158,12 +159,13 @@ public static StringList explode(String _source, String _by) {
*
*
*
- * @see #explode(String, String)
- * @see #explode(StringList, String)
- * @see #explodeWithDelimiter(String, String, boolean)
* @param _source - the string to be split
* @param _by - the splitting regular expression
* @return the StringLits containing all splitting shards
+ *
+ * @see #explode(String, String)
+ * @see #explode(StringList, String)
+ * @see #explodeWithDelimiter(String, String, boolean)
*/
public static StringList explodeFirstOnly(String _source, String _by) {
// START KGU 2019-03-03: Bugfix explodeFirstOnly("test=, pas =", "=") returned {"test", ", pas "} instead of {"test", ", pas ="}
@@ -377,6 +379,7 @@ public void add(String _string) {
* string will be inserted.
*
* @param _string
+ *
* @see #add(String)
* @see #addOrderedIfNew(String)
* @see #addIfNew(String)
@@ -411,6 +414,7 @@ private boolean addOrdered(String _string, boolean _onlyIfNew) {
* be inserted.
*
* @param _string the string to be inserted
+ *
* @see #add(String)
* @see #addIfNew(String)
* @see #addOrdered(String)
@@ -441,6 +445,7 @@ public void addByLength(String _string) {
*
* @param _string - The string to be added
* @return true if the string was new
+ *
* @see #add(String)
* @see #addOrdered(String)
* @see #addOrderedIfNew(String)
@@ -461,6 +466,7 @@ public boolean addIfNew(String _string) {
*
* @param _string - The string to be added
* @return true if the string was new
+ *
* @see #add(String)
* @see #addIfNew(String)
* @see #addOrdered(String)
@@ -497,6 +503,7 @@ public boolean addByLengthIfNew(String _string) {
* no matter whether there might already be an equal string element in this.
*
* @param _string - The string to be added
+ *
* @see #add(String)
* @see #addIfNew(String)
* @see #addIfNew(StringList)
@@ -517,6 +524,7 @@ public void add(StringList _stringList) {
*
* @param _string - The string to be added
* @return true if some of the strings of _stringList was added
+ *
* @see #add(String)
* @see #addIfNew(String)
* @see #add(StringList)
@@ -563,6 +571,7 @@ public int lastIndexOf(String _string) {
* @param _backwardFrom - the index of the element from which (including!)
* {@code _string} is looked for backwards.
* @return element index or -1
+ *
* @see #indexOf(String)
* @see #indexOf(String, boolean)
* @see #indexOf(String, int)
@@ -886,6 +895,7 @@ public int count() {
*
* @param str - the string to search for
* @return the number of occurrences
+ *
* @see #count(String, boolean)
*/
public int count(String _str) {
@@ -1019,24 +1029,6 @@ public void loadFromFile(String _filename) {
add(StringList.explode(buffer.toString(), "\n"));
} catch (IOException ex) {
}
-
- /* try
- {
- BTextfile inp = new BTextfile(_filename);
- inp.reset();
- strings.clear();
- while(!inp.eof())
- {
- String s = inp.readln();
- strings.add(s);
- }
- inp.close();
- }
- catch (Exception e)
- {
- System.out.println(e.getMessage());
- }
- */
}
public void saveToFile(String _filename) {
@@ -1045,12 +1037,6 @@ public void saveToFile(String _filename) {
Writer out = new OutputStreamWriter(fos, "UTF-8");
out.write(this.getText());
out.close();
- /*
- BTextfile inp = new BTextfile(_filename);
- inp.rewrite();
- inp.write(this.getText());
- inp.close();
- */
} catch (IOException ex) {
System.err.println("StringListsaveToFile(): " + ex.getMessage());
}
@@ -1185,12 +1171,16 @@ public int removeAll(StringList _subList, boolean _matchCase) {
// START KGU#92 2015-12-01: New method to facilitate bugfix #41
/**
- * Replaces all elements being equal to the given string _stringOld by
- * _stringNew
+ * Replaces all elements being equal to the given string {@code _stringOld}
+ * by {@code _stringNew}
*
* @param _stringOld - the searched string
- * @param _stringNew - the string to replace occurrences of _stringOld
+ * @param _stringNew - the string to replace occurrences of {@code _stringOld}
* @return number of replacements
+ *
+ * @see #replaceAllBetween(String, String, boolean, int, int)
+ * @see #replaceAllCi(String, String)
+ * @see #replaceIfContains(String, String)
*/
public int replaceAll(String _stringOld, String _stringNew) {
// START KGU#129 2016-01-08: Delegated to common submethod
@@ -1220,6 +1210,10 @@ public int replaceAll(String _stringOld, String _stringNew) {
* @param _stringOld - the searched string
* @param _stringNew - the string to replace occurrences of _stringOld
* @return number of replacements
+ *
+ * @see #replaceAll(String, String)
+ * @see #replaceAllBetween(String, String, boolean, int, int)
+ * @see #replaceIfContains(String, String)
*/
public int replaceAllCi(String _stringOld, String _stringNew) {
// START KGU#129 2016-01-08: Delegated to common submethod
@@ -1255,6 +1249,10 @@ public int replaceAllCi(String _stringOld, String _stringNew) {
* @param _fromIndex - index of first element to be affected
* @param _toIndex - index beyond the last element to be affected
* @return number of replacements
+ *
+ * @see #replaceAll(String, String)
+ * @see #replaceAllCi(String, String)
+ * @see #replaceIfContains(String, String)
*/
public int replaceAllBetween(String _stringOld, String _stringNew, boolean _matchCase, int _fromIndex, int _toIndex) {
int nReplaced = 0;
@@ -1269,38 +1267,49 @@ public int replaceAllBetween(String _stringOld, String _stringNew, boolean _matc
}
// END KGU#129 2016-01-08
- // START AS 4 ARM
+ // START AS 2021-03-25: Enh. #967 (for ARMGenerator)
/**
- * Replaces all elements that contains the
- * given string _stringOld by _stringNew.
+ * Replaces string {@code _stringOld} by {@code _stringNew} in all elements.
*
* @param _stringOld - the searched string
- * @param _stringNew - the string to replace occurrences of _stringOld
- * @return number of replacements
+ * @param _stringNew - the string to replace occurrences of {@code _stringOld}
+ *
+ * @see #replaceAll(String, String)
+ * @see #replaceAllCi(String, String)
+ * @see #replaceAllBetween(String, String, boolean, int, int)
*/
public void replaceIfContains(String _stringOld, String _stringNew) {
- String c="";
for (int i = 0; i < count(); i++) {
- c = strings.get(i).replace(_stringOld, _stringNew);
+ String c = strings.get(i).replace(_stringOld, _stringNew);
strings.setElementAt(c, i);
}
}
- // END AS 4 ARM
+ // END AS 2021-03-25
+
@Override
public String toString() {
- // START KGU#827 2020-03-18 - result should be paranthesized
+ // START KGU#827 2020-03-18 - result should be parenthesized
//return getCommaText();
return "[" + getCommaText() + "]";
// END KGU#827 2020-03-18
}
// START KGU 2015-11-24
+ /**
+ * Empties this StringList.
+ */
public void clear() {
this.strings.clear();
}
// END KGU 2015-11-24
// START BOB 2016-08-01
+ /**
+ * Creates a String array with same elements as this contains.
+ * (This means that elements containing newlines will be copied to
+ * the array 1:1.)
+ * @return the resulting strung array
+ */
public String[] toArray() {
String[] array = new String[count()];
for (int i = 0; i < count(); i++) {
@@ -1344,6 +1353,7 @@ public void remove(int fromIndex, int toIndex) {
* this!
*
* @return this StringList after having been trimmed.
+ *
* @see #removeAll(String)
* @see #removeAll(String, boolean)
* @see #remove(int)