public ResourceCard(String key, String i18nKey) {

    this.key = key;
    String titleName = I18N.getGUIMessageOrNull("gui.cards." + i18nKey + ".title");
    if (titleName != null) {
      this.title =
          "<html><div style=\"text-align: center;\"><body>"
              + titleName.replaceFirst(" ", "<br>")
              + "</html></body>";
      this.tip = I18N.getGUIMessage("gui.cards." + i18nKey + ".tip");
    } else {
      // default case if no name and icon are defined:
      key = key.replace("_", " ");
      char[] stringArray = key.toCharArray();
      stringArray[0] = Character.toUpperCase(stringArray[0]);
      String defaultName = new String(stringArray);

      this.title =
          "<html><div style=\"text-align: center;\"><body>"
              + defaultName.replaceFirst(" ", "<br>")
              + "</html></body>";
      this.tip = defaultName;
    }

    String iconName = I18N.getGUIMessageOrNull("gui.cards." + i18nKey + ".icon");
    if (iconName != null) {
      this.icon = SwingTools.createIcon("32/" + iconName);
    } else {
      this.icon = SwingTools.createIcon("32/data_information.png"); // default icon
    }
  }
  private void calculateANOVA() throws SignificanceCalculationException {
    double alpha = -1;
    String alphaString = alphaField.getText();
    try {
      alpha = Double.parseDouble(alphaString);
    } catch (NumberFormatException e) {
      SwingTools.showVerySimpleErrorMessage("Significance level must be a number between 0 and 1.");
    }

    if ((alpha < 0) || (alpha > 1)) {
      SwingTools.showVerySimpleErrorMessage("Significance level must be a number between 0 and 1.");
    } else {
      this.calculator.clearGroups();
      this.calculator.setAlpha(alpha);
      for (int i = 0; i < tableModel.getRowCount(); i++) {
        int number = ((Integer) tableModel.getValueAt(i, 2)).intValue();
        double mean = ((Double) tableModel.getValueAt(i, 0)).doubleValue();
        double variance = ((Double) tableModel.getValueAt(i, 1)).doubleValue();
        calculator.addGroup(number, mean, variance);
      }
      if (tableModel.getRowCount() < 2) {
        SwingTools.showVerySimpleErrorMessage(
            "You need to add at least two rows in order to calculate an ANOVA test.");
        return;
      }

      SignificanceTestResult result = calculator.performSignificanceTest();
      JOptionPane.showMessageDialog(
          this, result.getVisualizationComponent(null), "ANOVA result", JOptionPane.PLAIN_MESSAGE);
    }
  }
 public void actionPerformed(ActionEvent e) {
   Operator selectedOperator = this.actions.getSelectedOperator();
   if (selectedOperator != null) {
     NewBuildingBlockDialog dialog = new NewBuildingBlockDialog();
     dialog.setVisible(true);
     if (dialog.isOk()) {
       try {
         BuildingBlock buildingBlock = dialog.getSelectedBuildingBlock();
         if (buildingBlock != null) {
           String xmlDescription = buildingBlock.getXML();
           try {
             InputSource source = new InputSource(new StringReader(xmlDescription));
             Document document =
                 DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(source);
             Element element = document.getDocumentElement();
             Operator operator =
                 Operator.createFromXML(
                     element,
                     actions.getProcess(),
                     new LinkedList<UnknownParameterInformation>(),
                     null,
                     XMLImporter.CURRENT_VERSION);
             operator.setUserDescription(buildingBlock.getDescription());
             actions.insert(Collections.singletonList(operator));
           } catch (Exception ex) {
             SwingTools.showSimpleErrorMessage(
                 "cannot_instantiate_building_block", ex, buildingBlock.getName());
           }
         }
       } catch (Exception ex) {
         SwingTools.showSimpleErrorMessage("cannot_instantiate_building_block", ex);
       }
     }
   }
 }
 @Override
 public void actionPerformed(ActionEvent e) {
   String loc =
       RepositoryLocationChooser.selectLocation(
           lastLocation, "", RapidMinerGUI.getMainFrame(), true, false, true, true, true);
   if (loc != null) {
     RepositoryLocation location;
     try {
       location = new RepositoryLocation(loc);
     } catch (Exception ex) {
       SwingTools.showSimpleErrorMessage("malformed_rep_location", ex, loc);
       return;
     }
     try {
       if (location.locateEntry() != null) {
         // overwrite?
         if (SwingTools.showConfirmDialog("overwrite", ConfirmDialog.YES_NO_OPTION, location)
             != ConfirmDialog.YES_OPTION) {
           return;
         }
       }
       RepositoryManager.getInstance(null).store(object, location, null);
       lastLocation = location;
     } catch (RepositoryException ex) {
       SwingTools.showSimpleErrorMessage("cannot_store_obj_at_location", ex, loc);
     }
   }
 }
 private void load() {
   File file = SwingTools.chooseFile(null, null, true, "wgt", "attribute weight file");
   try {
     AttributeWeights fileWeights = AttributeWeights.load(file);
     attributeTableModel.mergeWeights(fileWeights);
   } catch (IOException e) {
     SwingTools.showSimpleErrorMessage("cannot_load_attr_weights_from_file", e, file.getName());
   }
   update();
 }
 private void save() {
   File file = SwingTools.chooseFile(null, null, true, "wgt", "attribute weight file");
   try {
     attributeTableModel
         .getAttributeWeights()
         .writeAttributeWeights(file, Tools.getDefaultEncoding());
   } catch (IOException e) {
     SwingTools.showSimpleErrorMessage("cannot_write_attr_weights_to_file", e, file.getName());
   }
 }
/** @author Sebastian Land */
public class CollectionTreeCellRenderer extends DefaultTreeCellRenderer {

  private static final long serialVersionUID = 1L;

  private final Icon ICON_FOLDER_OPEN = SwingTools.createIcon("16/folder.png");
  private final Icon ICON_FOLDER_CLOSED = SwingTools.createIcon("16/folder_closed.png");

  private final Map<IOObject, String> childNames = new HashMap<IOObject, String>();

  public CollectionTreeCellRenderer(IOObject collection) {
    if (collection instanceof MetaModel) {
      MetaModel mm = (MetaModel) collection;
      for (int i = 0; i < mm.getModels().size(); i++) {
        childNames.put(mm.getModels().get(i), mm.getModelNames().get(i));
      }
    }
  }

  @Override
  public Component getTreeCellRendererComponent(
      JTree tree,
      Object value,
      boolean selected,
      boolean expanded,
      boolean leaf,
      int row,
      boolean hasFocus) {
    JLabel label =
        (JLabel)
            super.getTreeCellRendererComponent(
                tree, value, selected, expanded, leaf, row, hasFocus);
    if (value instanceof ResultObject) {
      ResultObject ro = (ResultObject) value;
      String name = childNames.get(ro);
      if (name == null) {
        name = ro.getName();
      }
      label.setText("<html>" + name + " (<small>" + ro.getSource() + "</small>)</html>");
      if (ro instanceof IOObjectCollection) {
        label.setIcon(expanded ? ICON_FOLDER_OPEN : ICON_FOLDER_CLOSED);
      } else {
        Icon resultIcon = ro.getResultIcon();
        label.setIcon(resultIcon);
      }
    } else if (value instanceof IOObject) {
      IOObject ioo = (IOObject) value;
      label.setText(ioo.getClass().getSimpleName());
    }
    return label;
  }
}
  private void overwriteProcess(final ProcessEntry processEntry) {
    if (SwingTools.showConfirmDialog(
            "overwrite", ConfirmDialog.YES_NO_OPTION, processEntry.getLocation())
        == ConfirmDialog.YES_OPTION) {
      ProgressThread storeProgressThread =
          new ProgressThread("store_process") {

            @Override
            public void run() {
              getProgressListener().setTotal(100);
              getProgressListener().setCompleted(10);
              try {
                Process process = RapidMinerGUI.getMainFrame().getProcess();
                process.setProcessLocation(
                    new RepositoryProcessLocation(processEntry.getLocation()));
                processEntry.storeXML(process.getRootOperator().getXML(false));
                RapidMinerGUI.addToRecentFiles(process.getProcessLocation());
                RapidMinerGUI.getMainFrame().processHasBeenSaved();
              } catch (Exception e) {
                SwingTools.showSimpleErrorMessage(
                    "cannot_store_process_in_repository", e, processEntry.getName());
              } finally {
                getProgressListener().setCompleted(100);
                getProgressListener().complete();
              }
            }
          };
      storeProgressThread.start();
    }
  }
 @Override
 public void valueForPathChanged(TreePath path, Object newValue) {
   try {
     ((Entry) path.getLastPathComponent()).rename(newValue.toString());
   } catch (Exception e) {
     SwingTools.showSimpleErrorMessage("error_rename", e, e.toString());
   }
 }
 @Override
 public void save(BlobEntry entry) {
   try {
     save(entry.openOutputStream(LIBRARY_MIME_TYPE));
   } catch (RepositoryException e) {
     SwingTools.showSimpleErrorMessage("cannot_access_repository", e);
   }
 }
 @Override
 protected void ok() {
   try {
     chooser.getRepositoryLocation();
     super.ok();
   } catch (MalformedRepositoryLocationException e) {
     SwingTools.showSimpleErrorMessage("malformed_repository_location", e, e.getMessage());
   }
 }
 @Override
 public void createConfigurationWizard(ParameterType type, ConfigurationListener listener) {
   ExcelExampleSource sourceOperator = (ExcelExampleSource) listener;
   try {
     new ExcelImportWizard(sourceOperator, listener, null).setVisible(true);
   } catch (OperatorException e) {
     SwingTools.showSimpleErrorMessage("importwizard.error_creating_wizard", e);
   }
 }
 @Override
 public void performAction(OperatorDescription description) {
   try {
     Operator operator = OperatorService.createOperator(description);
     RapidMinerGUI.getMainFrame().getActions().insert(Collections.singletonList(operator));
   } catch (Exception e) {
     SwingTools.showSimpleErrorMessage("cannot_instantiate", e, description.getName());
   }
 }
 @Override
 public void apply() {
   RepositoryLocation absLoc;
   try {
     absLoc = operator.getParameterAsRepositoryLocation(key);
     final RepositoryLocation processLoc = operator.getProcess().getRepositoryLocation().parent();
     if (processLoc == null) {
       SwingTools.showVerySimpleErrorMessage(
           "quickfix_failed", "Process is not stored in repository.");
     } else {
       String relative = absLoc.makeRelative(processLoc);
       operator.setParameter(key, relative);
     }
   } catch (UserError e) {
     // Should not happen. Parameter should be set, otherwise we would not have created this
     // prefix.
     SwingTools.showVerySimpleErrorMessage("quickfix_failed", e.toString());
   }
 }
Example #15
0
  /**
   * Enables and disables all actions according to the current state (process running, operator
   * selected...
   */
  public void enableActions() {
    synchronized (process) {
      SwingTools.invokeLater(
          new Runnable() {

            @Override
            public void run() {
              enableActionsNow();
            }
          });
    }
    updateCheckboxStates();
  }
Example #16
0
  public void drawOperator(Operator op, Graphics2D g) {
    Dimension d = getSize(op, g);

    g.setPaint(SwingTools.makeBluePaint(d.getWidth(), d.getHeight()));
    g.fillRect(0, 0, (int) d.getWidth(), (int) d.getHeight());
    g.setPaint(Color.black);
    g.setStroke(new BasicStroke(3));
    g.drawRect(0, 0, (int) d.getWidth(), (int) d.getHeight());
    Graphics2D g2 = (Graphics2D) g.create();
    g2.translate(BORDER, BORDER);
    drawName(op, g2);
    g2.dispose();
  }
 @Override
 public void actionPerformed(ActionEvent e) {
   File file =
       SwingTools.chooseFile(
           RapidMinerGUI.getMainFrame(),
           "export_process",
           null,
           false,
           false,
           new String[] {RapidMiner.PROCESS_FILE_EXTENSION, "xml"},
           new String[] {"Process File", "Process File"});
   if (file == null) {
     return;
   }
   try {
     new FileProcessLocation(file).store(RapidMinerGUI.getMainFrame().getProcess(), null);
   } catch (IOException e1) {
     SwingTools.showSimpleErrorMessage(
         "cannot_save_process",
         e1,
         RapidMinerGUI.getMainFrame().getProcess().getProcessLocation(),
         e1.getMessage());
   }
 }
Example #18
0
 @Override
 public void actionPerformed(ActionEvent e) {
   File file =
       SwingTools.chooseFile(
           RapidMinerGUI.getMainFrame(),
           "import_process",
           null,
           true,
           false,
           new String[] {RapidMiner.PROCESS_FILE_EXTENSION, "xml"},
           new String[] {"Process File", "Process File"});
   if (file == null) {
     return;
   }
   open(file);
 }
Example #19
0
  /**
   * The given operators will be inserted at the last position of the currently selected operator
   * chain.
   */
  public void insert(List<Operator> newOperators) {
    Object selectedNode = getSelectedOperator();
    if (selectedNode == null) {
      SwingTools.showVerySimpleErrorMessage("cannot_insert_operator");
      return;
    } else if (mainFrame.getProcessPanel().getProcessRenderer().getModel().getDisplayedChain()
        == selectedNode) {
      for (Operator newOperator : newOperators) {
        int index =
            mainFrame
                .getProcessPanel()
                .getProcessRenderer()
                .getProcessIndexUnder(
                    mainFrame
                        .getProcessPanel()
                        .getProcessRenderer()
                        .getModel()
                        .getCurrentMousePosition());
        if (index == -1) {
          index = 0;
        }
        ((OperatorChain) selectedNode).getSubprocess(index).addOperator(newOperator);
      }
    } else {
      int i = 0;
      Operator selectedOperator = (Operator) selectedNode;
      ExecutionUnit process = selectedOperator.getExecutionUnit();
      int parentIndex = process.getOperators().indexOf(selectedOperator) + 1;
      for (Operator newOperator : newOperators) {
        process.addOperator(newOperator, parentIndex + i);
        i++;
      }
    }

    AutoWireThread.autoWireInBackground(newOperators, true);
    mainFrame.selectOperators(newOperators);
  }
 @Override
 public String getVertexToolTip(String object) {
   Tree tree = vertexMap.get(object);
   if (tree != null) {
     StringBuffer result = new StringBuffer();
     if (tree.isLeaf()) {
       String labelString = tree.getLabel();
       if (labelString != null) {
         result.append("<html><b>Class:</b>&nbsp;" + labelString + "<br>");
         result.append("<b>Size:</b>&nbsp;" + tree.getFrequencySum() + "<br>");
         result.append(
             "<b>Class frequencies:</b>&nbsp;"
                 + SwingTools.transformToolTipText(tree.getCounterMap().toString())
                 + "</html>");
       }
     } else {
       result.append(
           "<html><b>Subtree Size:</b>&nbsp;" + tree.getSubtreeFrequencySum() + "</html>");
     }
     return result.toString();
   } else {
     return null;
   }
 }
/**
 * This class handles event hooks and draw decorators registered to the {@link ProcessRendererView}
 * for workflow annotations.
 *
 * @author Marco Boeck
 * @since 6.4.0
 */
public final class AnnotationsDecorator {

  /** name of the paste action (context menu) */
  private static final String PASTE_ACTION_NAME = "paste";

  /** name of the paste from clipboard action (ctrl+v) */
  private static final String PASTE_FROM_CLIPBOARD_ACTION_NAME = DefaultEditorKit.pasteAction;

  /** icon depicting annotations on an operator */
  private static final ImageIcon IMAGE_ANNOTATION = SwingTools.createIcon("16/note_pinned.png");

  /** the width of the edit panel above/below the annotation editor */
  private static final int EDIT_PANEL_WIDTH = 190;

  /** the height of the edit panel above/below the annotation editor */
  private static final int EDIT_PANEL_HEIGHT = 30;

  /** the width of the color panel above/below the annotation editor */
  private static final int EDIT_COLOR_PANEL_WIDTH = 215;

  /** the height of the color panel above/below the annotation editor */
  private static final int EDIT_COLOR_PANEL_HEIGHT = EDIT_PANEL_HEIGHT;

  /** the pane which can be used to edit the text */
  private JEditorPane editPane;

  /** the panel which can be used to edit color and alignment during editing */
  private JPanel editPanel;

  /** the dialog panel which can be used to edit color while editing */
  private JDialog colorOverlay;

  /** the button opening the color overlay */
  private JButton colorButton;

  /** the process renderer */
  private final ProcessRendererView view;

  /** the process renderer model */
  private final ProcessRendererModel rendererModel;

  /** the annotation visualizer instance */
  private final AnnotationsVisualizer visualizer;

  /** the model backing this decorator */
  private final AnnotationsModel model;

  /** the drawer for the annotations */
  private final AnnotationDrawer drawer;

  /** the event handling for annotations */
  private final AnnotationEventHook hook;

  /** draws process (free-flowing) annotations behind operators */
  private ProcessDrawDecorator processAnnotationDrawer =
      new ProcessDrawDecorator() {

        @Override
        public void draw(
            final ExecutionUnit process,
            final Graphics2D g2,
            final ProcessRendererModel rendererModel) {
          draw(process, g2, rendererModel, false);
        }

        @Override
        public void print(
            final ExecutionUnit process,
            final Graphics2D g2,
            final ProcessRendererModel rendererModel) {
          draw(process, g2, rendererModel, true);
        }

        /** Draws the background annoations. */
        private void draw(
            final ExecutionUnit process,
            final Graphics2D g2,
            final ProcessRendererModel rendererModel,
            final boolean printing) {
          if (!visualizer.isActive()) {
            return;
          }

          // background annotations
          WorkflowAnnotations annotations = rendererModel.getProcessAnnotations(process);
          if (annotations != null) {
            for (WorkflowAnnotation anno : annotations.getAnnotationsDrawOrder()) {
              // selected is drawn by highlight decorator
              if (anno.equals(model.getSelected())) {
                continue;
              }

              // paint the annotation itself
              Graphics2D g2P = (Graphics2D) g2.create();
              drawer.drawAnnotation(anno, g2P, printing);
              g2P.dispose();
            }
          }
        }
      };

  /** draws operator annotations */
  private ProcessDrawDecorator operatorAnnotationDrawer =
      new ProcessDrawDecorator() {

        @Override
        public void draw(
            final ExecutionUnit process,
            final Graphics2D g2,
            final ProcessRendererModel rendererModel) {
          draw(process, g2, rendererModel, false);
        }

        @Override
        public void print(
            final ExecutionUnit process,
            final Graphics2D g2,
            final ProcessRendererModel rendererModel) {
          draw(process, g2, rendererModel, true);
        }

        /** Draws the operator annoations. */
        private void draw(
            final ExecutionUnit process,
            final Graphics2D g2,
            final ProcessRendererModel rendererModel,
            final boolean printing) {
          if (!visualizer.isActive()) {
            return;
          }

          // operator attached annotations
          List<Operator> selectedOperators = rendererModel.getSelectedOperators();
          for (Operator operator : process.getOperators()) {
            if (selectedOperators.contains(operator)) {
              continue;
            }
            drawOpAnno(operator, g2, rendererModel, printing);
          }
          // selected operators annotations need to be drawn over non selected ones
          for (Operator selOp : selectedOperators) {
            if (process.equals(selOp.getExecutionUnit())) {
              drawOpAnno(selOp, g2, rendererModel, printing);
            }
          }
        }

        /** Draws the annotation for the given operator (if he has one). */
        private void drawOpAnno(
            final Operator operator,
            final Graphics2D g2,
            final ProcessRendererModel rendererModel,
            final boolean printing) {
          WorkflowAnnotations annotations = rendererModel.getOperatorAnnotations(operator);
          if (annotations == null) {
            return;
          }
          for (WorkflowAnnotation anno : annotations.getAnnotationsDrawOrder()) {
            // selected is drawn by highlight decorator
            if (anno.equals(model.getSelected())) {
              continue;
            }

            // paint the annotation itself
            Graphics2D g2P = (Graphics2D) g2.create();
            drawer.drawAnnotation(anno, g2P, printing);
            g2P.dispose();
          }
        }
      };

  /** draws process (free-flowing) annotations which are selected. Drawn over operators */
  private ProcessDrawDecorator workflowAnnotationDrawerHighlight =
      new ProcessDrawDecorator() {

        @Override
        public void draw(
            final ExecutionUnit process,
            final Graphics2D g2,
            final ProcessRendererModel rendererModel) {
          draw(process, g2, rendererModel, false);
        }

        @Override
        public void print(ExecutionUnit process, Graphics2D g2, ProcessRendererModel model) {
          draw(process, g2, rendererModel, true);
        }

        /** Draws the selected annotation. */
        private void draw(
            final ExecutionUnit process,
            final Graphics2D g2,
            final ProcessRendererModel rendererModel,
            final boolean printing) {
          if (!visualizer.isActive()) {
            return;
          }

          // paint the selected annotation
          WorkflowAnnotation selected = model.getSelected();
          if (selected != null) {
            // only draw in correct execution unit
            if (selected.getProcess().equals(process)) {
              // only paint annotation if not editing
              if (editPane == null) {
                // paint the annotation itself
                Graphics2D g2P = (Graphics2D) g2.create();
                drawer.drawAnnotation(selected, g2P, printing);
                g2P.dispose();
              } else {
                // only paint shadow
                Rectangle2D loc = selected.getLocation();
                g2.draw(
                    new Rectangle2D.Double(
                        loc.getX() - 1,
                        loc.getY() - 1,
                        editPane.getBounds().getWidth() + 1,
                        editPane.getBounds().getHeight() + 1));
                Rectangle2D shadowFrameEditor =
                    new Rectangle2D.Double(
                        loc.getX(),
                        loc.getY(),
                        editPane.getBounds().getWidth() + 1,
                        editPane.getBounds().getHeight() + 1);
                ProcessDrawUtils.drawShadow(shadowFrameEditor, g2);
                if (editPanel != null) {
                  Point absolute = new Point(editPanel.getX(), editPanel.getY());
                  Point relative =
                      ProcessDrawUtils.convertToRelativePoint(
                          absolute, rendererModel.getProcessIndex(process), rendererModel);
                  Rectangle2D shadowFramePanel =
                      new Rectangle2D.Double(
                          relative.getX(), relative.getY(), EDIT_PANEL_WIDTH, EDIT_PANEL_HEIGHT);
                  ProcessDrawUtils.drawShadow(shadowFramePanel, g2);
                }
              }
            }
          }
        }
      };

  /** draws annotation icons on operators */
  private OperatorDrawDecorator opAnnotationIconDrawer =
      new OperatorDrawDecorator() {

        @Override
        public void draw(
            final Operator operator,
            final Graphics2D g2,
            final ProcessRendererModel rendererModel) {
          draw(operator, g2, rendererModel, true);
        }

        @Override
        public void print(Operator operator, Graphics2D g2, ProcessRendererModel model) {
          draw(operator, g2, rendererModel, true);
        }

        /** Draws the annotation icon on operators. */
        private void draw(
            final Operator operator,
            final Graphics2D g2,
            final ProcessRendererModel rendererModel,
            final boolean printing) {
          // Draw annotation icons regardless of active state
          WorkflowAnnotations annotations = rendererModel.getOperatorAnnotations(operator);
          if (annotations == null || annotations.isEmpty()) {
            return;
          }
          Rectangle2D frame = rendererModel.getOperatorRect(operator);
          int xOffset = (IMAGE_ANNOTATION.getIconWidth() + 2) * 2;
          ProcessDrawUtils.getIcon(operator, IMAGE_ANNOTATION)
              .paintIcon(
                  null,
                  g2,
                  (int) (frame.getX() + frame.getWidth() - xOffset),
                  (int) (frame.getY() + frame.getHeight() - IMAGE_ANNOTATION.getIconHeight() - 1));
        }
      };

  /** listener which triggers color panel moving if required */
  private ComponentListener colorPanelMover =
      new ComponentAdapter() {

        @Override
        public void componentResized(ComponentEvent e) {
          updateColorPanelPosition();
        }

        @Override
        public void componentMoved(ComponentEvent e) {
          updateColorPanelPosition();
        }
      };

  /**
   * Creates a new workflow annotation decorator
   *
   * @param view the process renderer instance
   * @param visualizer the annotation visualizer instance
   * @param model the model backing this instance
   */
  public AnnotationsDecorator(
      final ProcessRendererView view,
      final AnnotationsVisualizer visualizer,
      final AnnotationsModel model) {
    this.view = view;
    this.model = model;
    this.rendererModel = view.getModel();
    this.drawer = new AnnotationDrawer(model, rendererModel);
    this.hook = new AnnotationEventHook(this, model, visualizer, drawer, view, rendererModel);
    this.visualizer = visualizer;
  }

  /**
   * Start inline editing of the selected annotation. If no annotation is selected, does nothing.
   */
  public void editSelected() {
    if (model.getSelected() == null) {
      return;
    }
    // editor to actually edit comment string
    removeEditor();
    createEditor();

    // panel to edit alignment and color
    createEditPanel();

    editPane.requestFocusInWindow();
    view.repaint();
  }

  /** Stop all editing and remove editors. */
  public void reset() {
    drawer.reset();
    removeEditor();
  }

  /** Registers the event hooks and draw decorators to the process renderer. */
  void registerEventHooks() {
    view.addDrawDecorator(processAnnotationDrawer, RenderPhase.ANNOTATIONS);
    view.addDrawDecorator(operatorAnnotationDrawer, RenderPhase.OPERATOR_ANNOTATIONS);
    view.addDrawDecorator(workflowAnnotationDrawerHighlight, RenderPhase.OVERLAY);
    view.addDrawDecorator(opAnnotationIconDrawer);

    view.getOverviewPanelDrawer().addDecorator(processAnnotationDrawer, RenderPhase.ANNOTATIONS);
    view.getOverviewPanelDrawer()
        .addDecorator(operatorAnnotationDrawer, RenderPhase.OPERATOR_ANNOTATIONS);

    hook.registerDecorators();

    // this listener makes the color edit panel move when required
    view.addComponentListener(colorPanelMover);
    ApplicationFrame.getApplicationFrame().addComponentListener(colorPanelMover);
  }

  /** Removes the event hooks and draw decorators from the process renderer. */
  void unregisterDecorators() {
    view.removeDrawDecorator(processAnnotationDrawer, RenderPhase.ANNOTATIONS);
    view.removeDrawDecorator(operatorAnnotationDrawer, RenderPhase.OPERATOR_ANNOTATIONS);
    view.removeDrawDecorator(workflowAnnotationDrawerHighlight, RenderPhase.OVERLAY);
    view.removeDrawDecorator(opAnnotationIconDrawer);

    view.getOverviewPanelDrawer().removeDecorator(processAnnotationDrawer, RenderPhase.ANNOTATIONS);
    view.getOverviewPanelDrawer()
        .removeDecorator(operatorAnnotationDrawer, RenderPhase.OPERATOR_ANNOTATIONS);

    hook.unregisterEventHooks();

    view.removeComponentListener(colorPanelMover);
    ApplicationFrame.getApplicationFrame().removeComponentListener(colorPanelMover);
  }

  /**
   * Creates and adds the JEditorPane for the currently selected annotation to the process renderer.
   */
  private void createEditor() {
    final WorkflowAnnotation selected = model.getSelected();
    Rectangle2D loc = selected.getLocation();

    // JEditorPane to edit the comment string
    editPane = new JEditorPane("text/html", "");
    editPane.setBorder(null);
    int paneX = (int) loc.getX();
    int paneY = (int) loc.getY();
    int index = view.getModel().getProcessIndex(selected.getProcess());
    Point absolute =
        ProcessDrawUtils.convertToAbsoluteProcessPoint(
            new Point(paneX, paneY), index, rendererModel);
    editPane.setBounds(
        (int) absolute.getX(), (int) absolute.getY(), (int) loc.getWidth(), (int) loc.getHeight());
    editPane.setText(AnnotationDrawUtils.createStyledCommentString(selected));
    // use proxy for paste actions to trigger reload of editor after paste
    Action pasteFromClipboard = editPane.getActionMap().get(PASTE_FROM_CLIPBOARD_ACTION_NAME);
    Action paste = editPane.getActionMap().get(PASTE_ACTION_NAME);
    if (pasteFromClipboard != null) {
      editPane
          .getActionMap()
          .put(
              PASTE_FROM_CLIPBOARD_ACTION_NAME,
              new PasteAnnotationProxyAction(pasteFromClipboard, this));
    }
    if (paste != null) {
      editPane.getActionMap().put(PASTE_ACTION_NAME, new PasteAnnotationProxyAction(paste, this));
    }
    // use proxy for transfer actions to convert e.g. HTML paste to plaintext paste
    editPane.setTransferHandler(new TransferHandlerAnnotationPlaintext(editPane));
    // IMPORTANT: Linebreaks do not work without the following!
    // this filter inserts a \r every time the user enters a newline
    // this signal is later used to convert newline to <br/>
    ((HTMLDocument) editPane.getDocument())
        .setDocumentFilter(
            new DocumentFilter() {

              @Override
              public void insertString(
                  DocumentFilter.FilterBypass fb, int offs, String str, AttributeSet a)
                  throws BadLocationException {
                // this is never called..
                super.insertString(
                    fb,
                    offs,
                    str.replaceAll("\n", "\n" + AnnotationDrawUtils.ANNOTATION_HTML_NEWLINE_SIGNAL),
                    a);
              }

              @Override
              public void replace(FilterBypass fb, int offs, int length, String str, AttributeSet a)
                  throws BadLocationException {
                if (selected instanceof OperatorAnnotation) {
                  // operator annotations have a character limit, enforce here
                  try {
                    int existingLength =
                        AnnotationDrawUtils.getPlaintextFromEditor(editPane, false).length()
                            - length;
                    if (existingLength + str.length() > OperatorAnnotation.MAX_CHARACTERS) {
                      // insert at beginning or end is fine, cut off excess characters
                      if (existingLength <= 0 || offs >= existingLength) {
                        int acceptableLength = OperatorAnnotation.MAX_CHARACTERS - existingLength;
                        int newLength = Math.max(acceptableLength, 0);
                        str = str.substring(0, newLength);
                      } else {
                        // inserting into middle, do NOT paste at all
                        return;
                      }
                    }
                  } catch (IOException e) {
                    // should not happen, if it does this is our smallest problem -> ignore
                  }
                }
                super.replace(
                    fb,
                    offs,
                    length,
                    str.replaceAll("\n", "\n" + AnnotationDrawUtils.ANNOTATION_HTML_NEWLINE_SIGNAL),
                    a);
              }
            });
    // set background color
    if (selected.getStyle().getAnnotationColor() == AnnotationColor.TRANSPARENT) {
      editPane.setBackground(Color.WHITE);
    } else {
      editPane.setBackground(selected.getStyle().getAnnotationColor().getColorHighlight());
    }
    editPane.addFocusListener(
        new FocusAdapter() {

          @Override
          public void focusLost(final FocusEvent e) {
            // right-click menu
            if (e.isTemporary()) {
              return;
            }
            if (editPane != null && e.getOppositeComponent() != null) {
              // style edit menu, no real focus loss
              if (SwingUtilities.isDescendingFrom(e.getOppositeComponent(), editPanel)) {
                return;
              }
              if (SwingUtilities.isDescendingFrom(e.getOppositeComponent(), colorOverlay)) {
                return;
              }
              if (colorOverlay.getParent() == e.getOppositeComponent()) {
                return;
              }

              saveEdit(selected);
              removeEditor();
            }
          }
        });
    editPane.addKeyListener(
        new KeyAdapter() {

          /** keep track of control down so Ctrl+Enter works but Enter+Ctrl not */
          private boolean controlDown;

          @Override
          public void keyPressed(final KeyEvent e) {
            if (e.getKeyCode() == KeyEvent.VK_CONTROL) {
              controlDown = true;
            }
            // consume so undo/redo etc are not passed to the process
            if (SwingTools.isControlOrMetaDown(e) && e.getKeyCode() == KeyEvent.VK_Z
                || e.getKeyCode() == KeyEvent.VK_Y) {
              e.consume();
            }
          }

          @Override
          public void keyReleased(final KeyEvent e) {
            switch (e.getKeyCode()) {
              case KeyEvent.VK_CONTROL:
                controlDown = false;
                break;
              case KeyEvent.VK_ENTER:
                if (!controlDown) {
                  updateEditorHeight(selected);
                } else {
                  // if control was down before Enter was pressed, save & exit
                  saveEdit(selected);
                  removeEditor();
                  model.setSelected(null);
                }
                break;
              case KeyEvent.VK_ESCAPE:
                // ignore changes on escape
                removeEditor();
                model.setSelected(null);
                break;
              default:
                break;
            }
          }
        });
    editPane
        .getDocument()
        .addDocumentListener(
            new DocumentListener() {

              @Override
              public void removeUpdate(DocumentEvent e) {
                updateEditorHeight(selected);
              }

              @Override
              public void insertUpdate(DocumentEvent e) {
                updateEditorHeight(selected);
              }

              @Override
              public void changedUpdate(DocumentEvent e) {
                updateEditorHeight(selected);
              }
            });
    view.add(editPane);
    editPane.selectAll();
  }

  /**
   * Creates and adds the edit panel for the currently selected annotation to the process renderer.
   */
  private void createEditPanel() {
    final WorkflowAnnotation selected = model.getSelected();
    Rectangle2D loc = selected.getLocation();

    // panel containing buttons
    editPanel = new JPanel();
    editPanel.setCursor(Cursor.getDefaultCursor());
    editPanel.setLayout(new BoxLayout(editPanel, BoxLayout.LINE_AXIS));
    updateEditPanelPosition(loc, false);
    editPanel.setOpaque(true);
    editPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    // consume mouse events so focus is not lost
    editPanel.addMouseListener(
        new MouseAdapter() {

          @Override
          public void mouseReleased(MouseEvent e) {
            e.consume();
          }

          @Override
          public void mousePressed(MouseEvent e) {
            e.consume();
          }

          @Override
          public void mouseClicked(MouseEvent e) {
            e.consume();
          }
        });

    // add alignment controls
    final List<JButton> alignmentButtonList = new LinkedList<JButton>();
    for (AnnotationAlignment align : AnnotationAlignment.values()) {
      final Action action = align.makeAlignmentChangeAction(model, model.getSelected());
      final JButton alignButton = new JButton();
      alignButton.setIcon((Icon) action.getValue(Action.SMALL_ICON));
      alignButton.setBorderPainted(false);
      alignButton.setBorder(null);
      alignButton.setFocusable(false);
      if (align == selected.getStyle().getAnnotationAlignment()) {
        alignButton.setBackground(Color.LIGHT_GRAY);
      }
      alignButton.addActionListener(
          new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
              removeColorPanel();
              colorButton.setBackground(null);
              for (JButton button : alignmentButtonList) {
                button.setBackground(null);
              }
              alignButton.setBackground(Color.LIGHT_GRAY);

              int caretPos = editPane.getCaretPosition();
              // remember if we were at last position because doc length can change after 1st
              // save
              boolean lastPos = caretPos == editPane.getDocument().getLength();
              int selStart = editPane.getSelectionStart();
              int selEnd = editPane.getSelectionEnd();
              // change alignment and save current comment
              action.actionPerformed(e);
              saveEdit(selected);
              // reload edit pane with changes
              editPane.setText(AnnotationDrawUtils.createStyledCommentString(selected));
              // special handling for documents of length 1 to avoid not being able to type
              if (editPane.getDocument().getLength() == 1) {
                caretPos = 1;
              } else if (lastPos) {
                caretPos = editPane.getDocument().getLength();
              } else {
                caretPos = Math.min(editPane.getDocument().getLength(), caretPos);
              }
              editPane.setCaretPosition(caretPos);
              if (selEnd - selStart > 0) {
                editPane.setSelectionStart(selStart);
                editPane.setSelectionEnd(selEnd);
              }
              editPane.requestFocusInWindow();
            }
          });
      editPanel.add(alignButton);
      alignmentButtonList.add(alignButton);
    }

    // add small empty space
    editPanel.add(Box.createHorizontalStrut(2));

    // add color controls
    colorOverlay = new JDialog(ApplicationFrame.getApplicationFrame());
    colorOverlay.setCursor(Cursor.getDefaultCursor());
    colorOverlay
        .getRootPane()
        .setLayout(new BoxLayout(colorOverlay.getRootPane(), BoxLayout.LINE_AXIS));
    colorOverlay.setUndecorated(true);
    colorOverlay.getRootPane().setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
    colorOverlay.setFocusable(false);
    colorOverlay.setAutoRequestFocus(false);
    // consume mouse events so focus is not lost
    colorOverlay.addMouseListener(
        new MouseAdapter() {

          @Override
          public void mouseReleased(MouseEvent e) {
            e.consume();
          }

          @Override
          public void mousePressed(MouseEvent e) {
            e.consume();
          }

          @Override
          public void mouseClicked(MouseEvent e) {
            e.consume();
          }
        });

    for (final AnnotationColor color : AnnotationColor.values()) {
      final Action action = color.makeColorChangeAction(model, selected);
      JButton colChangeButton = new JButton();
      colChangeButton.setText(null);
      colChangeButton.setBorderPainted(false);
      colChangeButton.setBorder(null);
      colChangeButton.setFocusable(false);
      final Icon icon =
          SwingTools.createIconFromColor(
              color.getColor(), Color.BLACK, 16, 16, new Rectangle2D.Double(1, 1, 14, 14));
      colChangeButton.setIcon(icon);
      colChangeButton.addActionListener(
          new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
              // change color and save current comment
              action.actionPerformed(e);
              saveEdit(selected);
              // set edit pane bg color
              editPane.requestFocusInWindow();
              if (color == AnnotationColor.TRANSPARENT) {
                editPane.setBackground(Color.WHITE);
              } else {
                editPane.setBackground(color.getColorHighlight());
              }

              // adapt color of main button, remove color panel
              colorButton.setIcon(icon);
              if (removeColorPanel()) {
                colorButton.setBackground(null);
                view.repaint();
              }
            }
          });

      colorOverlay.getRootPane().add(colChangeButton);
    }

    colorButton = new JButton("\u25BE");
    colorButton.setBorderPainted(false);
    colorButton.setFocusable(false);
    AnnotationColor color = selected.getStyle().getAnnotationColor();
    colorButton.setIcon(
        SwingTools.createIconFromColor(
            color.getColor(), Color.BLACK, 16, 16, new Rectangle2D.Double(1, 1, 14, 14)));
    colorButton.addActionListener(
        new ActionListener() {

          @Override
          public void actionPerformed(ActionEvent e) {
            if (removeColorPanel()) {
              colorButton.setBackground(null);
              view.repaint();
              return;
            }

            updateColorPanelPosition();
            colorOverlay.setVisible(true);
            colorButton.setBackground(Color.LIGHT_GRAY);
            editPane.requestFocusInWindow();
            view.repaint();
          }
        });
    editPanel.add(colorButton);

    // add separator
    JLabel separator =
        new JLabel() {

          private static final long serialVersionUID = 1L;

          @Override
          public void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;

            g2.setColor(Color.LIGHT_GRAY);
            g2.drawLine(2, 0, 2, 20);
          }
        };
    separator.setText(" "); // dummy text to show label
    editPanel.add(separator);

    // add delete button
    final JButton deleteButton =
        new JButton(
            I18N.getMessage(I18N.getGUIBundle(), "gui.action.workflow.annotation.delete.label"));
    deleteButton.setForeground(Color.RED);
    deleteButton.setContentAreaFilled(false);
    deleteButton.setFocusable(false);
    deleteButton.addActionListener(
        new ActionListener() {

          @Override
          public void actionPerformed(ActionEvent e) {
            model.deleteAnnotation(selected);
            removeEditor();
          }
        });
    deleteButton.addMouseListener(
        new MouseAdapter() {

          @Override
          @SuppressWarnings({"unchecked", "rawtypes"})
          public void mouseExited(MouseEvent e) {
            Font font = deleteButton.getFont();
            Map attributes = font.getAttributes();
            attributes.put(TextAttribute.UNDERLINE, -1);
            deleteButton.setFont(font.deriveFont(attributes));
          }

          @SuppressWarnings({"unchecked", "rawtypes"})
          @Override
          public void mouseEntered(MouseEvent e) {
            Font font = deleteButton.getFont();
            Map attributes = font.getAttributes();
            attributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
            deleteButton.setFont(font.deriveFont(attributes));
          }
        });
    editPanel.add(deleteButton);

    // add panel to view
    view.add(editPanel);
  }

  /**
   * Saves the content of the comment editor as the new comment for the given {@link
   * WorkflowAnnotation}.
   *
   * @param selected the annotation for which the content of the editor pane should be saved as new
   *     comment
   */
  private void saveEdit(final WorkflowAnnotation selected) {
    if (editPane == null) {
      return;
    }
    HTMLDocument document = (HTMLDocument) editPane.getDocument();
    StringWriter writer = new StringWriter();
    try {
      editPane.getEditorKit().write(writer, document, 0, document.getLength());
    } catch (IndexOutOfBoundsException | IOException | BadLocationException e1) {
      // should not happen
      LogService.getRoot()
          .log(
              Level.WARNING,
              "com.rapidminer.gui.flow.processrendering.annotations.AnnotationsDecorator.cannot_save");
    }
    String comment = writer.toString();
    comment = AnnotationDrawUtils.removeStyleFromComment(comment);
    Rectangle2D loc = selected.getLocation();
    Rectangle2D newLoc =
        new Rectangle2D.Double(
            loc.getX(),
            loc.getY(),
            editPane.getBounds().getWidth(),
            editPane.getBounds().getHeight());
    selected.setLocation(newLoc);

    boolean overflowing = false;
    int prefHeight =
        AnnotationDrawUtils.getContentHeight(
            AnnotationDrawUtils.createStyledCommentString(comment, selected.getStyle()),
            (int) newLoc.getWidth());
    if (prefHeight > newLoc.getHeight()) {
      overflowing = true;
    }
    selected.setOverflowing(overflowing);

    model.setAnnotationComment(selected, comment);
  }

  /**
   * Reloads the editor pane content to match editor and annotation styling. After this call, the
   * editor pane displays the annotation in the same way as it is displayed in the process renderer.
   */
  void updateEditorContent() {
    SwingUtilities.invokeLater(
        new Runnable() {

          @Override
          public void run() {
            if (editPane == null || model.getSelected() == null) {
              return;
            }
            HTMLDocument document = (HTMLDocument) editPane.getDocument();
            StringWriter writer = new StringWriter();
            try {
              editPane.getEditorKit().write(writer, document, 0, document.getLength());
            } catch (IndexOutOfBoundsException | IOException | BadLocationException e1) {
              // should not happen
              LogService.getRoot()
                  .log(
                      Level.WARNING,
                      "com.rapidminer.gui.flow.processrendering.annotations.AnnotationsDecorator.cannot_save");
            }
            String comment = writer.toString();
            comment = AnnotationDrawUtils.removeStyleFromComment(comment);
            int caretPos = editPane.getCaretPosition();
            boolean lastPos = caretPos == editPane.getDocument().getLength();
            editPane.setText(
                AnnotationDrawUtils.createStyledCommentString(
                    comment, model.getSelected().getStyle()));
            if (lastPos) {
              caretPos = editPane.getDocument().getLength();
            }
            caretPos = Math.min(caretPos, editPane.getDocument().getLength());
            editPane.setCaretPosition(caretPos);
            editPane.requestFocusInWindow();
          }
        });
  }

  /** Removes the annotation editor from the process renderer. */
  private void removeEditor() {
    if (editPane != null) {
      view.remove(editPane);
      editPane = null;
    }
    if (editPanel != null) {
      view.remove(editPanel);
      editPanel = null;
    }
    removeColorPanel();

    // this makes sure that pressing F2 afterwards works
    // otherwise nothing is focused until the next click
    view.requestFocusInWindow();
    view.repaint();
  }

  /** Tries to remove the color panel. If not found or not showing, does nothing. */
  private boolean removeColorPanel() {
    if (colorOverlay != null && colorOverlay.isShowing()) {
      colorOverlay.dispose();
      return true;
    }

    return false;
  }

  /**
   * Updates the position and size of the edit panel relative to the given location.
   *
   * @param loc the location the edit panel should be relative to
   * @param absolute if {@code true} the loc is treated as absolute position on the process
   *     renderer; if {@code false} it is treated as relative to the current process
   */
  private void updateEditPanelPosition(final Rectangle2D loc, final boolean absolute) {
    int panelX = (int) loc.getCenterX() - EDIT_PANEL_WIDTH / 2;
    int panelY = (int) loc.getY() - EDIT_PANEL_HEIGHT - ProcessDrawer.PADDING;
    // if panel would be outside process renderer, fix it
    if (panelX < WorkflowAnnotation.MIN_X) {
      panelX = WorkflowAnnotation.MIN_X;
    }
    if (panelY < 0) {
      panelY = (int) loc.getMaxY() + ProcessDrawer.PADDING;
    }
    // last fallback is cramped to the bottom. If that does not fit either, don't care
    if (panelY + EDIT_PANEL_HEIGHT > view.getSize().getHeight() - ProcessDrawer.PADDING * 2) {
      panelY = (int) loc.getMaxY();
    }
    int index = view.getModel().getProcessIndex(model.getSelected().getProcess());
    if (absolute) {
      editPanel.setBounds(panelX, panelY, EDIT_PANEL_WIDTH, EDIT_PANEL_HEIGHT);
    } else {
      Point absoluteP =
          ProcessDrawUtils.convertToAbsoluteProcessPoint(
              new Point(panelX, panelY), index, rendererModel);
      editPanel.setBounds(
          (int) absoluteP.getX(), (int) absoluteP.getY(), EDIT_PANEL_WIDTH, EDIT_PANEL_HEIGHT);
    }
  }

  /**
   * Makes sure the current editor height matches its content if the annotation was never resized.
   * If the annotation has been manually resized before, does nothing.
   *
   * @param anno the annotation currently in the editor
   */
  private void updateEditorHeight(final WorkflowAnnotation anno) {
    if (anno.wasResized()) {
      return;
    }

    Rectangle bounds = editPane.getBounds();
    // height is either the pref height or the current height, depending on what is bigger
    int prefHeight;
    if (anno instanceof ProcessAnnotation) {
      prefHeight =
          (int) Math.max(getContentHeightOfEditor((int) bounds.getWidth()), bounds.getHeight());
    } else {
      prefHeight =
          Math.max(
              getContentHeightOfEditor((int) bounds.getWidth()), OperatorAnnotation.MIN_HEIGHT);
    }
    Rectangle newBounds =
        new Rectangle(
            (int) bounds.getX(), (int) bounds.getY(), (int) bounds.getWidth(), prefHeight);
    if (!bounds.equals(newBounds)) {
      editPane.setBounds(newBounds);
      updateEditPanelPosition(newBounds, true);
      view.getModel().fireAnnotationMiscChanged(anno);
    }
  }

  /** Updates the location of the color edit panel (if shown). */
  private void updateColorPanelPosition() {
    if (editPanel != null && colorOverlay != null) {
      int colorPanelX = (int) editPanel.getLocationOnScreen().getX() + colorButton.getX();
      int colorPanelY =
          (int) (editPanel.getLocationOnScreen().getY() + editPanel.getBounds().getHeight());
      colorOverlay.setBounds(
          colorPanelX, colorPanelY, EDIT_COLOR_PANEL_WIDTH, EDIT_COLOR_PANEL_HEIGHT);
    }
  }

  /**
   * Calculates the preferred height of the editor pane with the given fixed width.
   *
   * @param width the width of the pane
   * @return the preferred height given the current editor pane content or {@code -1} if there was a
   *     problem. Value will never exceed {@link WorkflowAnnotation#MAX_HEIGHT}
   */
  private int getContentHeightOfEditor(final int width) {
    HTMLDocument document = (HTMLDocument) editPane.getDocument();
    StringWriter writer = new StringWriter();
    try {
      editPane.getEditorKit().write(writer, document, 0, document.getLength());
    } catch (IndexOutOfBoundsException | IOException | BadLocationException e1) {
      // should not happen
      return -1;
    }
    String comment = writer.toString();
    comment = AnnotationDrawUtils.removeStyleFromComment(comment);

    int maxHeight =
        model.getSelected() instanceof ProcessAnnotation
            ? ProcessAnnotation.MAX_HEIGHT
            : OperatorAnnotation.MAX_HEIGHT;
    return Math.min(
        AnnotationDrawUtils.getContentHeight(
            AnnotationDrawUtils.createStyledCommentString(comment, model.getSelected().getStyle()),
            width),
        maxHeight);
  }
}
/**
 * The colors used for the RapidLook look and feel.
 *
 * @author Ingo Mierswa
 */
public class Colors {

  public static ColorUIResource white = new ColorUIResource(255, 255, 255);

  public static ColorUIResource black = new ColorUIResource(0, 0, 0);

  // set via UIManager.setColor("VLDocking.highlight", ...)
  public static ColorUIResource vlDockingHighlight = new ColorUIResource(255, 0, 0);

  // set via UIManager.setColor("VLDocking.shadow", ...)
  public static ColorUIResource vlDockingShadow = new ColorUIResource(0, 255, 0);

  private ColorUIResource[] tableHeaderColors =
      new ColorUIResource[] {
        new ColorUIResource(210, 210, 230),
        new ColorUIResource(220, 220, 240),
        new ColorUIResource(225, 225, 245),
        new ColorUIResource(235, 235, 255),
        new ColorUIResource(245, 145, 0), // highlight 1
        new ColorUIResource(245, 145, 0), // hightlight 2
        new ColorUIResource(250, 250, 255),
        new ColorUIResource(200, 200, 220),
        new ColorUIResource(250, 250, 255),
        new ColorUIResource(230, 230, 250),
        new ColorUIResource(225, 225, 245),
        new ColorUIResource(215, 215, 235),
        new ColorUIResource(210, 210, 230),
        new ColorUIResource(190, 190, 210)
      };

  private ColorUIResource[] buttonSkinColors =
      new ColorUIResource[] {
        new ColorUIResource(253, 254, 255), // begin pressed // 0
        new ColorUIResource(253, 253, 255), // both
        new ColorUIResource(249, 251, 255), // both
        new ColorUIResource(248, 250, 255), // both
        new ColorUIResource(254, 254, 255), // both
        new ColorUIResource(234, 234, 235), // 5
        new ColorUIResource(230, 232, 235),
        new ColorUIResource(224, 229, 235),
        new ColorUIResource(209, 221, 234), // end pressed
        new ColorUIResource(254, 254, 255),
        new ColorUIResource(253, 254, 255), // 10
        new ColorUIResource(246, 249, 255),
        new ColorUIResource(243, 247, 255),
        new ColorUIResource(239, 244, 255),
        new ColorUIResource(233, 240, 255),
        new ColorUIResource(225, 235, 255), // 15
        new ColorUIResource(217, 230, 255),
        new ColorUIResource(252, 253, 255),
        new ColorUIResource(247, 251, 255),
        new ColorUIResource(224, 228, 235), // start down
        new ColorUIResource(239, 244, 255), // 20
        new ColorUIResource(218, 230, 240) // 21
      };

  /*
   	private ColorUIResource[] buttonSkinColors = new ColorUIResource[] {
  		new ColorUIResource(253, 254, 255), // begin pressed
  		new ColorUIResource(253, 253, 255),
  		new ColorUIResource(249, 251, 255),
  		new ColorUIResource(248, 250, 255),
  		new ColorUIResource(254, 254, 255),
  		new ColorUIResource(254, 254, 255),
  		new ColorUIResource(250, 252, 255),
  		new ColorUIResource(244, 249, 255),
  		new ColorUIResource(229, 241, 254), // end pressed
  		new ColorUIResource(254, 254, 255),
  		new ColorUIResource(253, 254, 255),
  		new ColorUIResource(246, 249, 255),
  		new ColorUIResource(243, 247, 255),
  		new ColorUIResource(239, 244, 255),
  		new ColorUIResource(233, 240, 255),
  		new ColorUIResource(225, 235, 255),
  		new ColorUIResource(217, 230, 255),
  		new ColorUIResource(252, 253, 255),
  		new ColorUIResource(247, 251, 255)
  };
   */

  private ColorUIResource[] tabbedPaneColors =
      new ColorUIResource[] {
        // new ColorUIResource(220, 225, 230), // 0
        new ColorUIResource(200, 205, 210), // 0
        new ColorUIResource(215, 220, 225),
        new ColorUIResource(170, 170, 190),
        new ColorUIResource(200, 200, 220),
        new ColorUIResource(190, 200, 220),
        new ColorUIResource(250, 250, 250),
        new ColorUIResource(255, 255, 255),
        new ColorUIResource(210, 210, 230),
        new ColorUIResource(180, 190, 210),
        new ColorUIResource(200, 200, 220),
        new ColorUIResource(210, 210, 230), // 10
        new ColorUIResource(220, 220, 240),
        new ColorUIResource(230, 230, 250),
        new ColorUIResource(235, 235, 255),
        new ColorUIResource(240, 240, 255),
        new ColorUIResource(245, 245, 255),
        new ColorUIResource(250, 250, 255),
        new ColorUIResource(255, 255, 255),
        new ColorUIResource(255, 255, 255),
        new ColorUIResource(210, 210, 230),
        new ColorUIResource(240, 240, 255), // 20
        new ColorUIResource(245, 145, 0), // highlight
      };

  private ColorUIResource[] spinnerColors =
      new ColorUIResource[] {
        new ColorUIResource(230, 230, 250),
        new ColorUIResource(170, 170, 190),
        new ColorUIResource(240, 240, 255),
        new ColorUIResource(235, 235, 255),
        new ColorUIResource(220, 220, 240),
        new ColorUIResource(220, 220, 240),
        new ColorUIResource(210, 210, 230),
        new ColorUIResource(170, 170, 190),
        new ColorUIResource(230, 230, 250),
        new ColorUIResource(110, 110, 110),
        new ColorUIResource(195, 195, 195)
      };

  private ColorUIResource[][] buttonBorderColors =
      new ColorUIResource[][] {
        { // gray
          new ColorUIResource(100, 100, 100),
          new ColorUIResource(80, 80, 80),
          new ColorUIResource(150, 150, 150),
          new ColorUIResource(200, 200, 200),
          new ColorUIResource(150, 150, 150),
          new ColorUIResource(115, 115, 115),
          new ColorUIResource(125, 125, 125),
          new ColorUIResource(190, 190, 190),
          new ColorUIResource(100, 100, 100),
          new ColorUIResource(215, 215, 215),
          new ColorUIResource(235, 235, 235)
        },
        { // orange hover
          new ColorUIResource(200, 80, 20),
          new ColorUIResource(180, 60, 0),
          new ColorUIResource(230, 110, 45),
          new ColorUIResource(255, 205, 175),
          new ColorUIResource(230, 115, 50),
          new ColorUIResource(220, 105, 40),
          new ColorUIResource(230, 115, 50),
          new ColorUIResource(230, 125, 45),
          new ColorUIResource(205, 100, 20),
          new ColorUIResource(255, 200, 160),
          new ColorUIResource(255, 225, 205)
        },
        { // orange focus
          new ColorUIResource(180, 60, 0),
          new ColorUIResource(160, 40, 0),
          new ColorUIResource(210, 90, 25),
          new ColorUIResource(235, 185, 155),
          new ColorUIResource(210, 95, 30),
          new ColorUIResource(200, 85, 20),
          new ColorUIResource(210, 95, 30),
          new ColorUIResource(210, 105, 25),
          new ColorUIResource(185, 80, 0),
          new ColorUIResource(235, 180, 140),
          new ColorUIResource(235, 205, 185)
        },
        { // gray 2
          new ColorUIResource(170, 170, 170),
          new ColorUIResource(150, 150, 150),
          new ColorUIResource(200, 200, 200),
          new ColorUIResource(220, 220, 220),
          new ColorUIResource(200, 200, 200),
          new ColorUIResource(180, 180, 180),
          new ColorUIResource(185, 185, 185),
          new ColorUIResource(220, 220, 220),
          new ColorUIResource(150, 150, 150),
          new ColorUIResource(230, 230, 230),
          new ColorUIResource(240, 240, 240)
        },
        { // default
          new ColorUIResource(100, 100, 100),
          new ColorUIResource(80, 80, 80),
          new ColorUIResource(150, 150, 150),
          new ColorUIResource(200, 200, 200),
          new ColorUIResource(150, 150, 150),
          new ColorUIResource(115, 115, 115),
          new ColorUIResource(125, 125, 125),
          new ColorUIResource(140, 140, 160),
          new ColorUIResource(50, 50, 70),
          new ColorUIResource(165, 165, 185),
          new ColorUIResource(185, 185, 205)
        }
      };

  private ColorUIResource[] toolbarButtonColors =
      new ColorUIResource[] {
        new ColorUIResource(170, 170, 170),
        new ColorUIResource(250, 250, 250),
        new ColorUIResource(190, 190, 190),
        new ColorUIResource(230, 230, 230),
        new ColorUIResource(240, 240, 240),
        new ColorUIResource(200, 200, 200),
        new ColorUIResource(215, 215, 215),
        new ColorUIResource(235, 235, 235),
        new ColorUIResource(220, 220, 220),
        new ColorUIResource(225, 225, 225)
      };

  private static ColorUIResource[][] radioButtonColors =
      new ColorUIResource[][] {
        {
          new ColorUIResource(242, 242, 242),
          new ColorUIResource(197, 197, 197),
          new ColorUIResource(172, 172, 172),
          new ColorUIResource(153, 153, 153),
          new ColorUIResource(215, 215, 215)
        },
        { // orange border hover
          new ColorUIResource(255, 230, 200),
          new ColorUIResource(230, 185, 160),
          new ColorUIResource(220, 155, 160),
          new ColorUIResource(210, 135, 100),
          new ColorUIResource(240, 205, 190)
        },
        {
          new ColorUIResource(240, 245, 255),
          new ColorUIResource(255, 255, 255),
          new ColorUIResource(253, 253, 253),
          new ColorUIResource(251, 251, 251),
          new ColorUIResource(249, 249, 249),
          new ColorUIResource(247, 247, 247),
          new ColorUIResource(245, 245, 245),
          new ColorUIResource(243, 243, 243),
          new ColorUIResource(240, 240, 240),
          new ColorUIResource(238, 238, 238)
        },
        { // gray bullet
          new ColorUIResource(210, 210, 230),
          new ColorUIResource(200, 200, 220),
          new ColorUIResource(180, 180, 200),
          new ColorUIResource(170, 170, 190),
          new ColorUIResource(160, 160, 180),
          new ColorUIResource(150, 150, 170),
          new ColorUIResource(140, 140, 160),
          new ColorUIResource(120, 120, 140),
          new ColorUIResource(205, 205, 205)
        }
      };

  private static ColorUIResource[][] checkBoxButtonColors =
      new ColorUIResource[][] {
        {
          new ColorUIResource(200, 200, 200),
          new ColorUIResource(145, 145, 145),
          new ColorUIResource(105, 105, 105),
          new ColorUIResource(255, 255, 255),
          new ColorUIResource(252, 252, 252),
          new ColorUIResource(248, 248, 248),
          new ColorUIResource(245, 245, 245),
          new ColorUIResource(241, 241, 241),
          new ColorUIResource(238, 238, 238)
        },
        {
          new ColorUIResource(205, 215, 233),
          new ColorUIResource(170, 185, 215),
          new ColorUIResource(80, 110, 173),
          new ColorUIResource(238, 245, 255),
          new ColorUIResource(215, 225, 245)
        },
        {
          new ColorUIResource(235, 235, 235),
          new ColorUIResource(205, 205, 205),
          new ColorUIResource(180, 180, 180),
          new ColorUIResource(240, 240, 240),
          new ColorUIResource(190, 190, 190)
        },
        {
          new ColorUIResource(235, 165, 120),
          new ColorUIResource(255, 220, 190),
          new ColorUIResource(230, 180, 130),
          new ColorUIResource(225, 145, 80),
          new ColorUIResource(200, 130, 70),
          new ColorUIResource(215, 160, 105),
          new ColorUIResource(240, 190, 155),
          new ColorUIResource(210, 135, 70),
          new ColorUIResource(245, 170, 100),
          new ColorUIResource(235, 185, 140),
          new ColorUIResource(210, 135, 70)
        }
      };

  private ColorUIResource[][] textFieldBorderColors =
      new ColorUIResource[][] {
        { // focus
          new ColorUIResource(200, 125, 50),
          new ColorUIResource(235, 210, 130),
          new ColorUIResource(255, 195, 160),
          new ColorUIResource(230, 160, 110)
        },
        {
          new ColorUIResource(110, 110, 110),
          new ColorUIResource(220, 220, 220),
          new ColorUIResource(200, 200, 200),
          new ColorUIResource(160, 160, 160)
        },
        {
          new ColorUIResource(160, 160, 160),
          new ColorUIResource(225, 225, 225),
          new ColorUIResource(211, 211, 211),
          new ColorUIResource(175, 175, 175)
        }
      };

  private ColorUIResource[][] internalFrameTitlePaneColors =
      new ColorUIResource[][] {
        {
          new ColorUIResource(160, 175, 200),
          new ColorUIResource(125, 150, 190),
          new ColorUIResource(122, 148, 194),
          new ColorUIResource(85, 123, 187),
          new ColorUIResource(75, 115, 185),
          new ColorUIResource(85, 123, 191),
          new ColorUIResource(172, 180, 205),
          new ColorUIResource(85, 123, 191),
          new ColorUIResource(95, 137, 192),
          new ColorUIResource(85, 123, 191),
          new ColorUIResource(130, 155, 197),
          new ColorUIResource(188, 201, 226),
          new ColorUIResource(153, 172, 206),
          new ColorUIResource(125, 150, 192)
        },
        {
          new ColorUIResource(160, 175, 200),
          new ColorUIResource(125, 150, 190),
          new ColorUIResource(122, 148, 194),
          new ColorUIResource(85, 123, 187),
          new ColorUIResource(75, 115, 185),
          new ColorUIResource(85, 123, 191),
          new ColorUIResource(85, 125, 193),
          new ColorUIResource(85, 123, 191),
          new ColorUIResource(172, 180, 205),
          new ColorUIResource(84, 122, 189),
          new ColorUIResource(95, 137, 192),
          new ColorUIResource(81, 119, 187),
          new ColorUIResource(79, 118, 185),
          new ColorUIResource(77, 116, 183),
          new ColorUIResource(75, 113, 181),
          new ColorUIResource(73, 112, 179),
          new ColorUIResource(72, 110, 177),
          new ColorUIResource(70, 108, 176),
          new ColorUIResource(68, 107, 174),
          new ColorUIResource(67, 105, 172),
          new ColorUIResource(65, 104, 171),
          new ColorUIResource(63, 102, 169),
          new ColorUIResource(62, 100, 167),
          new ColorUIResource(61, 99, 165),
          new ColorUIResource(59, 96, 162),
          new ColorUIResource(56, 93, 157),
          new ColorUIResource(49, 85, 148),
          new ColorUIResource(43, 80, 143),
          new ColorUIResource(117, 120, 130),
          new ColorUIResource(130, 155, 197),
          new ColorUIResource(188, 201, 226),
          new ColorUIResource(153, 172, 206),
          new ColorUIResource(125, 150, 192)
        }
      };

  private ColorUIResource[][] bordersColors =
      new ColorUIResource[][] {
        {new ColorUIResource(205, 160, 130), new ColorUIResource(175, 110, 70)}
      };

  private ColorUIResource[][] progressBarColors =
      new ColorUIResource[][] {
        {
          new ColorUIResource(245, 170, 120),
          new ColorUIResource(255, 215, 150),
          new ColorUIResource(255, 210, 170),
          new ColorUIResource(250, 180, 140),
          new ColorUIResource(255, 165, 100),
          new ColorUIResource(250, 155, 100),
          new ColorUIResource(250, 140, 80),
          new ColorUIResource(250, 170, 130),
          new ColorUIResource(250, 180, 140),
          new ColorUIResource(255, 160, 105),
          new ColorUIResource(250, 185, 155),
          new ColorUIResource(255, 160, 95),
          new ColorUIResource(230, 160, 120)
        },
        {
          new ColorUIResource(255, 180, 130),
          new ColorUIResource(255, 225, 160),
          new ColorUIResource(255, 220, 180),
          new ColorUIResource(255, 190, 150),
          new ColorUIResource(255, 175, 110),
          new ColorUIResource(255, 165, 110),
          new ColorUIResource(255, 150, 90),
          new ColorUIResource(255, 180, 140),
          new ColorUIResource(255, 190, 150),
          new ColorUIResource(255, 170, 115),
          new ColorUIResource(255, 195, 165),
          new ColorUIResource(255, 170, 105),
          new ColorUIResource(240, 170, 130)
        },
      };

  private ColorUIResource[][] scrollBarColors =
      new ColorUIResource[][] {
        {
          new ColorUIResource(180, 180, 180),
          new ColorUIResource(240, 240, 240),
          new ColorUIResource(245, 245, 245),
          new ColorUIResource(248, 248, 248)
        },
        {
          new ColorUIResource(180, 180, 200),
          new ColorUIResource(200, 200, 220),
          new ColorUIResource(195, 195, 215),
          new ColorUIResource(190, 190, 210),
          new ColorUIResource(185, 185, 205),
          new ColorUIResource(180, 180, 200),
          new ColorUIResource(175, 175, 195),
          new ColorUIResource(170, 170, 190),
          new ColorUIResource(165, 165, 185),
          new ColorUIResource(160, 160, 180),
          new ColorUIResource(200, 200, 220),
          new ColorUIResource(180, 180, 200),
          new ColorUIResource(220, 220, 240),
          new ColorUIResource(200, 200, 220)
        }
      };

  private ColorUIResource[][] arrowButtonColors =
      new ColorUIResource[][] {
        {
          new ColorUIResource(220, 220, 240),
          new ColorUIResource(160, 160, 180),
          new ColorUIResource(210, 210, 230),
          new ColorUIResource(190, 190, 210),
          new ColorUIResource(160, 160, 180),
          new ColorUIResource(180, 180, 200),
          new ColorUIResource(210, 210, 230),
          new ColorUIResource(220, 220, 250)
        },
        {
          new ColorUIResource(230, 230, 250),
          new ColorUIResource(230, 230, 250),
          new ColorUIResource(200, 200, 220),
          new ColorUIResource(180, 180, 200),
          new ColorUIResource(220, 220, 240),
          new ColorUIResource(170, 170, 190),
          new ColorUIResource(200, 200, 220),
          new ColorUIResource(150, 150, 170),
          new ColorUIResource(215, 215, 235),
          new ColorUIResource(180, 180, 200),
          new ColorUIResource(160, 160, 180),
          new ColorUIResource(150, 150, 170),
          new ColorUIResource(170, 170, 190),
          new ColorUIResource(200, 200, 220),
          new ColorUIResource(170, 170, 190),
          new ColorUIResource(160, 160, 180),
          new ColorUIResource(220, 220, 240)
        }
      };

  private ColorUIResource[] fileChooserColors =
      new ColorUIResource[] {
        new ColorUIResource(255, 200, 200), new ColorUIResource(230, 170, 170)
      };

  private ColorUIResource[] toolbarColors =
      new ColorUIResource[] {new ColorUIResource(240, 240, 245)};

  private ImageIconUIResource sliderImage =
      new ImageIconUIResource(SwingTools.createImage("plaf/slider.png").getImage());

  private ColorUIResource[][] sliderColors = new ColorUIResource[][] {{}};

  private ColorUIResource desktopBackgroundColor = new ColorUIResource(180, 195, 220);

  private static ColorUIResource commonBackground = new ColorUIResource(240, 240, 245);

  private static ColorUIResource commonForeground = new ColorUIResource(0, 0, 0);

  private static ColorUIResource commonFocusColor = new ColorUIResource(205, 85, 0);

  public static ColorUIResource getWhite() {
    return white;
  }

  public static ColorUIResource getBlack() {
    return black;
  }

  public ColorUIResource getMenuItemBackground() {
    return new ColorUIResource(UIManager.getColor("MenuItem.background"));
  }

  public ColorUIResource getMenuItemSelectionBackground() {
    return new ColorUIResource(UIManager.getColor("MenuItem.selectionBackground"));
  }

  public ColorUIResource getMenuItemFadingColor() {
    return new ColorUIResource(UIManager.getColor("MenuItem.fadingColor"));
  }

  public String getName() {
    return "Colors";
  }

  public void addCustomEntriesToTable(UIDefaults table) {
    Object[] values =
        new Object[] {
          "MenuItem.background", getWhite(),
          "MenuItem.selectionBackground", new ColorUIResource(150, 150, 170),
          "MenuItem.fadingColor", new ColorUIResource(235, 235, 255),
          "ToolTip.background", new ColorUIResource(250, 240, 225),
          "ToolTip.borderColor", new ColorUIResource(113, 103, 74)
        };
    table.putDefaults(values);
  }

  public ColorUIResource getCommonFocusColor() {
    return commonFocusColor;
  }

  public ColorUIResource getTextHighlightBackColor() {
    return new ColorUIResource(150, 150, 170);
  }

  public ColorUIResource[] getButtonSkinColors() {
    return this.buttonSkinColors;
  }

  public ColorUIResource[] getToolbarButtonColors() {
    return this.toolbarButtonColors;
  }

  public ColorUIResource[][] getButtonBorderColors() {
    return this.buttonBorderColors;
  }

  public ColorUIResource getCommonBackground() {
    return commonBackground;
  }

  public ColorUIResource getCommonForeground() {
    return commonForeground;
  }

  public ColorUIResource[][] getRadioButtonColors() {
    return radioButtonColors;
  }

  public ColorUIResource[][] getCheckBoxButtonColors() {
    return checkBoxButtonColors;
  }

  public ColorUIResource[][] getTextFieldBorderColors() {
    return this.textFieldBorderColors;
  }

  public ColorUIResource[][] getInternalFrameTitlePaneColors() {
    return this.internalFrameTitlePaneColors;
  }

  public ColorUIResource[][] getBorderColors() {
    return this.bordersColors;
  }

  public ColorUIResource[][] getProgressBarColors() {
    return this.progressBarColors;
  }

  public ColorUIResource[][] getScrollBarColors() {
    return this.scrollBarColors;
  }

  public ColorUIResource[][] getArrowButtonColors() {
    return this.arrowButtonColors;
  }

  public ColorUIResource[][] getSliderColors() {
    return this.sliderColors;
  }

  public ImageIconUIResource getSliderImage() {
    return this.sliderImage;
  }

  public ColorUIResource[] getSpinnerColors() {
    return this.spinnerColors;
  }

  public ColorUIResource[] getTabbedPaneColors() {
    return this.tabbedPaneColors;
  }

  public ColorUIResource[] getTableHeaderColors() {
    return this.tableHeaderColors;
  }

  public ColorUIResource[] getFileChooserColors() {
    return this.fileChooserColors;
  }

  public ColorUIResource getDesktopBackgroundColor() {
    return this.desktopBackgroundColor;
  }

  public ColorUIResource[] getToolbarColors() {
    return this.toolbarColors;
  }
}
  /**
   * Creates and adds the edit panel for the currently selected annotation to the process renderer.
   */
  private void createEditPanel() {
    final WorkflowAnnotation selected = model.getSelected();
    Rectangle2D loc = selected.getLocation();

    // panel containing buttons
    editPanel = new JPanel();
    editPanel.setCursor(Cursor.getDefaultCursor());
    editPanel.setLayout(new BoxLayout(editPanel, BoxLayout.LINE_AXIS));
    updateEditPanelPosition(loc, false);
    editPanel.setOpaque(true);
    editPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    // consume mouse events so focus is not lost
    editPanel.addMouseListener(
        new MouseAdapter() {

          @Override
          public void mouseReleased(MouseEvent e) {
            e.consume();
          }

          @Override
          public void mousePressed(MouseEvent e) {
            e.consume();
          }

          @Override
          public void mouseClicked(MouseEvent e) {
            e.consume();
          }
        });

    // add alignment controls
    final List<JButton> alignmentButtonList = new LinkedList<JButton>();
    for (AnnotationAlignment align : AnnotationAlignment.values()) {
      final Action action = align.makeAlignmentChangeAction(model, model.getSelected());
      final JButton alignButton = new JButton();
      alignButton.setIcon((Icon) action.getValue(Action.SMALL_ICON));
      alignButton.setBorderPainted(false);
      alignButton.setBorder(null);
      alignButton.setFocusable(false);
      if (align == selected.getStyle().getAnnotationAlignment()) {
        alignButton.setBackground(Color.LIGHT_GRAY);
      }
      alignButton.addActionListener(
          new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
              removeColorPanel();
              colorButton.setBackground(null);
              for (JButton button : alignmentButtonList) {
                button.setBackground(null);
              }
              alignButton.setBackground(Color.LIGHT_GRAY);

              int caretPos = editPane.getCaretPosition();
              // remember if we were at last position because doc length can change after 1st
              // save
              boolean lastPos = caretPos == editPane.getDocument().getLength();
              int selStart = editPane.getSelectionStart();
              int selEnd = editPane.getSelectionEnd();
              // change alignment and save current comment
              action.actionPerformed(e);
              saveEdit(selected);
              // reload edit pane with changes
              editPane.setText(AnnotationDrawUtils.createStyledCommentString(selected));
              // special handling for documents of length 1 to avoid not being able to type
              if (editPane.getDocument().getLength() == 1) {
                caretPos = 1;
              } else if (lastPos) {
                caretPos = editPane.getDocument().getLength();
              } else {
                caretPos = Math.min(editPane.getDocument().getLength(), caretPos);
              }
              editPane.setCaretPosition(caretPos);
              if (selEnd - selStart > 0) {
                editPane.setSelectionStart(selStart);
                editPane.setSelectionEnd(selEnd);
              }
              editPane.requestFocusInWindow();
            }
          });
      editPanel.add(alignButton);
      alignmentButtonList.add(alignButton);
    }

    // add small empty space
    editPanel.add(Box.createHorizontalStrut(2));

    // add color controls
    colorOverlay = new JDialog(ApplicationFrame.getApplicationFrame());
    colorOverlay.setCursor(Cursor.getDefaultCursor());
    colorOverlay
        .getRootPane()
        .setLayout(new BoxLayout(colorOverlay.getRootPane(), BoxLayout.LINE_AXIS));
    colorOverlay.setUndecorated(true);
    colorOverlay.getRootPane().setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
    colorOverlay.setFocusable(false);
    colorOverlay.setAutoRequestFocus(false);
    // consume mouse events so focus is not lost
    colorOverlay.addMouseListener(
        new MouseAdapter() {

          @Override
          public void mouseReleased(MouseEvent e) {
            e.consume();
          }

          @Override
          public void mousePressed(MouseEvent e) {
            e.consume();
          }

          @Override
          public void mouseClicked(MouseEvent e) {
            e.consume();
          }
        });

    for (final AnnotationColor color : AnnotationColor.values()) {
      final Action action = color.makeColorChangeAction(model, selected);
      JButton colChangeButton = new JButton();
      colChangeButton.setText(null);
      colChangeButton.setBorderPainted(false);
      colChangeButton.setBorder(null);
      colChangeButton.setFocusable(false);
      final Icon icon =
          SwingTools.createIconFromColor(
              color.getColor(), Color.BLACK, 16, 16, new Rectangle2D.Double(1, 1, 14, 14));
      colChangeButton.setIcon(icon);
      colChangeButton.addActionListener(
          new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
              // change color and save current comment
              action.actionPerformed(e);
              saveEdit(selected);
              // set edit pane bg color
              editPane.requestFocusInWindow();
              if (color == AnnotationColor.TRANSPARENT) {
                editPane.setBackground(Color.WHITE);
              } else {
                editPane.setBackground(color.getColorHighlight());
              }

              // adapt color of main button, remove color panel
              colorButton.setIcon(icon);
              if (removeColorPanel()) {
                colorButton.setBackground(null);
                view.repaint();
              }
            }
          });

      colorOverlay.getRootPane().add(colChangeButton);
    }

    colorButton = new JButton("\u25BE");
    colorButton.setBorderPainted(false);
    colorButton.setFocusable(false);
    AnnotationColor color = selected.getStyle().getAnnotationColor();
    colorButton.setIcon(
        SwingTools.createIconFromColor(
            color.getColor(), Color.BLACK, 16, 16, new Rectangle2D.Double(1, 1, 14, 14)));
    colorButton.addActionListener(
        new ActionListener() {

          @Override
          public void actionPerformed(ActionEvent e) {
            if (removeColorPanel()) {
              colorButton.setBackground(null);
              view.repaint();
              return;
            }

            updateColorPanelPosition();
            colorOverlay.setVisible(true);
            colorButton.setBackground(Color.LIGHT_GRAY);
            editPane.requestFocusInWindow();
            view.repaint();
          }
        });
    editPanel.add(colorButton);

    // add separator
    JLabel separator =
        new JLabel() {

          private static final long serialVersionUID = 1L;

          @Override
          public void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;

            g2.setColor(Color.LIGHT_GRAY);
            g2.drawLine(2, 0, 2, 20);
          }
        };
    separator.setText(" "); // dummy text to show label
    editPanel.add(separator);

    // add delete button
    final JButton deleteButton =
        new JButton(
            I18N.getMessage(I18N.getGUIBundle(), "gui.action.workflow.annotation.delete.label"));
    deleteButton.setForeground(Color.RED);
    deleteButton.setContentAreaFilled(false);
    deleteButton.setFocusable(false);
    deleteButton.addActionListener(
        new ActionListener() {

          @Override
          public void actionPerformed(ActionEvent e) {
            model.deleteAnnotation(selected);
            removeEditor();
          }
        });
    deleteButton.addMouseListener(
        new MouseAdapter() {

          @Override
          @SuppressWarnings({"unchecked", "rawtypes"})
          public void mouseExited(MouseEvent e) {
            Font font = deleteButton.getFont();
            Map attributes = font.getAttributes();
            attributes.put(TextAttribute.UNDERLINE, -1);
            deleteButton.setFont(font.deriveFont(attributes));
          }

          @SuppressWarnings({"unchecked", "rawtypes"})
          @Override
          public void mouseEntered(MouseEvent e) {
            Font font = deleteButton.getFont();
            Map attributes = font.getAttributes();
            attributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
            deleteButton.setFont(font.deriveFont(attributes));
          }
        });
    editPanel.add(deleteButton);

    // add panel to view
    view.add(editPanel);
  }
Example #24
0
 static {
   int counter = 0;
   for (IconSize size : IconSize.values()) {
     ICONS[counter++] = SwingTools.createIcon(size.getSize() + "/" + ICON_NAME);
   }
 }
/** @author Simon Fischer */
public class ErrorTable extends JPanel implements Dockable, ProcessEditor {

  private static final long serialVersionUID = -954934789614113138L;

  private static final ImageIcon IMAGE_WARNING = SwingTools.createIcon("16/sign_warning.png");

  private static final ImageIcon IMAGE_ERROR = SwingTools.createIcon("16/error.png");

  private static final ImageIcon IMAGE_NO_QUICKFIX =
      SwingTools.createIcon(
          "16/"
              + I18N.getMessage(I18N.getGUIBundle(), "gui.errortable.no_quickfix_available.icon"));

  private static final ImageIcon IMAGE_QUICKFIX =
      SwingTools.createIcon(
          "16/" + I18N.getMessage(I18N.getGUIBundle(), "gui.errortable.choose_quickfix.icon"));

  private static final String[] COLUMN_NAMES = {
    I18N.getMessage(I18N.getGUIBundle(), "gui.errortable.header.message.label"),
    I18N.getMessage(I18N.getGUIBundle(), "gui.errortable.header.fixes.label"),
    I18N.getMessage(I18N.getGUIBundle(), "gui.errortable.header.location.label")
  };

  private static final String[] COLUMN_TOOLTIPS = {
    I18N.getMessage(I18N.getGUIBundle(), "gui.errortable.header.message.tip"),
    I18N.getMessage(I18N.getGUIBundle(), "gui.errortable.header.fixes.tip"),
    I18N.getMessage(I18N.getGUIBundle(), "gui.errortable.header.location.tip")
  };

  private final MainFrame mainFrame;

  private final TableCellRenderer iconRenderer =
      new DefaultTableCellRenderer() {
        private static final long serialVersionUID = 1L;

        @Override
        public Component getTableCellRendererComponent(
            JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
          if (value instanceof ProcessSetupError) {
            JLabel label =
                (JLabel)
                    super.getTableCellRendererComponent(
                        table,
                        ((ProcessSetupError) value).getMessage(),
                        isSelected,
                        hasFocus,
                        row,
                        column);
            switch (((ProcessSetupError) value).getSeverity()) {
              case WARNING:
                label.setIcon(IMAGE_WARNING);
                break;
              case ERROR:
                label.setIcon(IMAGE_ERROR);
                break;
              default:
                label.setIcon(null); // cannot happen				
            }

            return label;
          } else if (value instanceof Port) {
            JLabel label =
                (JLabel)
                    super.getTableCellRendererComponent(
                        table, ((Port) value).getSpec(), isSelected, hasFocus, row, column);
            label.setIcon(
                ((Port) value)
                    .getPorts()
                    .getOwner()
                    .getOperator()
                    .getOperatorDescription()
                    .getSmallIcon());
            return label;
          } else if (value instanceof Operator) {
            JLabel label =
                (JLabel)
                    super.getTableCellRendererComponent(
                        table, ((Operator) value).getName(), isSelected, hasFocus, row, column);
            label.setIcon(((Operator) value).getOperatorDescription().getSmallIcon());
            return label;
          } else {
            if (column == 1) {
              JLabel label =
                  (JLabel)
                      super.getTableCellRendererComponent(
                          table, value, isSelected, hasFocus, row, column);
              if (value == null) {
                label.setIcon(IMAGE_NO_QUICKFIX);
                label.setText(
                    I18N.getMessage(
                        I18N.getGUIBundle(), "gui.errortable.no_quickfix_available.label"));
              }
              if (value instanceof List) {
                label.setIcon(IMAGE_QUICKFIX);
                label.setText(
                    I18N.getMessage(
                        I18N.getGUIBundle(),
                        "gui.errortable.choose_quickfix.label",
                        ((List) value).size()));
              }
              if (value instanceof QuickFix) {
                QuickFix quickFix = (QuickFix) value;
                label.setIcon((Icon) quickFix.getAction().getValue(Action.SMALL_ICON));
                label.setText(quickFix.toString());
              }
              return label;
            } else {
              JLabel label =
                  (JLabel)
                      super.getTableCellRendererComponent(
                          table, value, isSelected, hasFocus, row, column);
              label.setIcon(null);
              return label;
            }
          }
        }
      };

  private final ExtendedJTable table =
      new ExtendedJTable() {
        private static final long serialVersionUID = 3731781319040565353L;

        @Override
        public TableCellRenderer getCellRenderer(int row, int column) {
          return iconRenderer;
        }

        @Override
        public void populatePopupMenu(JPopupMenu menu) {
          List<? extends QuickFix> fixes = errors.get(getSelectedRow()).getQuickFixes();
          if (!fixes.isEmpty()) {
            JMenu fixMenu = new ResourceMenu("quick_fixes");
            for (QuickFix fix : fixes) {
              fixMenu.add(fix.getAction());
            }
            menu.add(fixMenu);
            menu.addSeparator();
          }
          super.populatePopupMenu(menu);
        }

        @Override
        protected JTableHeader createDefaultTableHeader() {
          return new JTableHeader(columnModel) {
            private static final long serialVersionUID = -2000774622129683602L;

            @Override
            public String getToolTipText(MouseEvent e) {
              java.awt.Point p = e.getPoint();
              int index = columnModel.getColumnIndexAtX(p.x);
              int realIndex = columnModel.getColumn(index).getModelIndex();
              return COLUMN_TOOLTIPS[realIndex];
            };
          };
        };

        @Override
        public String getToolTipText(MouseEvent e) {
          Point p = e.getPoint();
          int realColumnIndex = convertColumnIndexToModel(columnAtPoint(p));
          int rowIndex = rowAtPoint(p);
          if (rowIndex >= 0 && rowIndex < getRowCount() && realColumnIndex == 1) {
            Object value = getModel().getValueAt(rowIndex, realColumnIndex);
            if (value == null) {
              return I18N.getMessage(
                  I18N.getGUIBundle(), "gui.errortable.no_quickfix_available.tip");
            }
            if (value instanceof List) {
              return I18N.getMessage(
                  I18N.getGUIBundle(), "gui.errortable.choose_quickfix.tip", ((List) value).size());
            }
            if (value instanceof QuickFix) {
              return ((QuickFix) value).toString();
            }
          }
          return super.getToolTipText(e);
        }
      };
  private final JLabel headerLabel = new JLabel();

  private final JToggleButton onlyCurrent =
      new JToggleButton(
          new ResourceAction(true, "error_table_only_current") {
            private static final long serialVersionUID = -1454330266199555397L;

            @Override
            public void actionPerformed(ActionEvent e) {
              updateErrors();
            }
          });

  private List<ProcessSetupError> errors = new LinkedList<ProcessSetupError>();

  private final AbstractTableModel model =
      new AbstractTableModel() {
        private static final long serialVersionUID = 1L;

        @Override
        public String getColumnName(int col) {
          return COLUMN_NAMES[col];
        }

        @Override
        public boolean isCellEditable(int row, int col) {
          return false;
        }

        @Override
        public int getColumnCount() {
          return 3;
        }

        @Override
        public int getRowCount() {
          return errors.size();
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
          ProcessSetupError error = errors.get(rowIndex);
          switch (columnIndex) {
            case 0:
              return error;
            case 1:
              List<? extends QuickFix> fixes = error.getQuickFixes();
              if (fixes.size() > 1) {
                return fixes;
              }
              if (fixes.size() == 1) {
                return fixes.get(0);
              }
              return null;
            case 2:
              if (error instanceof MetaDataError) {
                return ((MetaDataError) error).getPort();
              } else {
                return error.getOwner().getOperator();
              }
            default:
              return null;
          }
        }
      };
  private Process currentProcess;

  public ErrorTable(final MainFrame mainFrame) {
    super(new BorderLayout());
    this.mainFrame = mainFrame;
    onlyCurrent.setSelected(false);
    table.setShowVerticalLines(false);
    table.setModel(model);
    table.installToolTip();

    table.getColumnModel().getColumn(0).setPreferredWidth(400);
    table.getColumnModel().getColumn(1).setPreferredWidth(200);
    table.getColumnModel().getColumn(2).setPreferredWidth(150);

    headerLabel.setHorizontalAlignment(SwingConstants.CENTER);
    headerLabel.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));

    table.setBorder(null);
    JScrollPane scrollPane = new ExtendedJScrollPane(table);
    scrollPane.setBorder(null);
    add(scrollPane, BorderLayout.CENTER);
    ViewToolBar toolBar = new ViewToolBar();
    toolBar.add(onlyCurrent);
    onlyCurrent.setText(null);
    toolBar.add(headerLabel);
    add(toolBar, BorderLayout.NORTH);

    table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    table.addMouseListener(
        new MouseAdapter() {
          @Override
          public void mouseClicked(MouseEvent e) {
            if (e.getClickCount() == 2) {
              switch (table.getSelectedColumn()) {
                  // quick fixes
                case 1:
                  List<? extends QuickFix> quickFixes =
                      errors.get(table.getSelectedRow()).getQuickFixes();
                  if (quickFixes.size() == 1) {
                    quickFixes.get(0).apply();
                  }
                  if (quickFixes.size() > 1) {
                    new QuickFixDialog(quickFixes).setVisible(true);
                  }
                  break;
                default:
                  ProcessSetupError error = errors.get(table.getSelectedRow());
                  Operator op = error.getOwner().getOperator();
                  ErrorTable.this.mainFrame.selectOperator(op);
                  // other
              }
            }
          }
        });
  }

  private void updateErrors() {
    if ((currentOperator != null) && onlyCurrent.isSelected()) {
      fill(currentOperator);
    } else {
      if (currentProcess != null) {
        fill(currentProcess.getRootOperator());
      }
    }
  }

  private void fill(Operator root) {
    int numTotal = root.getProcess().getRootOperator().getErrorList().size();
    errors = root.getErrorList();
    String errorString;
    switch (errors.size()) {
      case 0:
        errorString = "No problems found";
        break;
      case 1:
        errorString = "One potential problem";
        break;
      default:
        errorString = errors.size() + " potential problems";
        break;
    }
    if (errors.size() != numTotal) {
      errorString = errorString + " (" + (numTotal - errors.size()) + " Filtered)";
    }
    headerLabel.setText(errorString);
    model.fireTableDataChanged();
  }

  @Override
  public void processChanged(Process process) {
    currentProcess = process;
    updateErrors();
  }

  @Override
  public void processUpdated(Process process) {
    currentProcess = process;
    updateErrors();
  }

  @Override
  public void setSelection(List<Operator> selection) {
    this.currentOperator = selection.isEmpty() ? null : selection.get(0);
    updateErrors();
  }

  public static final String ERROR_TABLE_DOCK_KEY = "error_table";
  private final DockKey DOCK_KEY = new ResourceDockKey(ERROR_TABLE_DOCK_KEY);

  {
    DOCK_KEY.setDockGroup(MainFrame.DOCK_GROUP_ROOT);
  }

  private Operator currentOperator;

  @Override
  public Component getComponent() {
    return this;
  }

  @Override
  public DockKey getDockKey() {
    return DOCK_KEY;
  }
}
  private void storeInFolder(final Folder folder) {
    // get current process name (if present)
    String currentName = null;
    if (RapidMinerGUI.getMainFrame().getProcess().getProcessLocation() != null) {
      currentName = RapidMinerGUI.getMainFrame().getProcess().getProcessLocation().getShortName();
    }

    final String name = SwingTools.showRepositoryEntryInputDialog("store_process", currentName);
    if (name != null) {
      if (name.isEmpty()) {
        SwingTools.showVerySimpleErrorMessage("please_enter_non_empty_name");
        return;
      }
      try {
        // check if folder already contains entry with said name
        RepositoryLocation entryLocation = new RepositoryLocation(folder.getLocation(), name);
        if (folder.containsEntry(name)) {
          Entry existingEntry = entryLocation.locateEntry();
          if (!(existingEntry instanceof ProcessEntry)) {
            // existing entry is not a ProcessEntry, cannot overwrite
            SwingTools.showVerySimpleErrorMessage("repository_entry_already_exists", name);
            return;
          } else {
            // existing entry is ProcessEntry,let #overwriteProcess() handle it
            overwriteProcess((ProcessEntry) existingEntry);
            return;
          }
        }
      } catch (RepositoryException e1) {
        SwingTools.showSimpleErrorMessage("cannot_store_process_in_repository", e1, name);
        return;
      } catch (MalformedRepositoryLocationException e1) {
        SwingTools.showSimpleErrorMessage("cannot_store_process_in_repository", e1, name);
        return;
      }

      ProgressThread storeProgressThread =
          new ProgressThread("store_process") {

            public void run() {
              getProgressListener().setTotal(100);
              Process process = RapidMinerGUI.getMainFrame().getProcess();
              RepositoryProcessLocation processLocation = null;
              try {
                processLocation =
                    new RepositoryProcessLocation(
                        new RepositoryLocation(folder.getLocation(), name));
                getProgressListener().setCompleted(10);
                Process.checkIfSavable(process);
                folder.createProcessEntry(name, process.getRootOperator().getXML(false));
                process.setProcessLocation(processLocation);
                tree.expandPath(tree.getSelectionPath());
                RapidMinerGUI.addToRecentFiles(process.getProcessLocation());
                RapidMinerGUI.getMainFrame().processHasBeenSaved();
              } catch (Exception e) {
                SwingTools.showSimpleErrorMessage(
                    "cannot_save_process", e, processLocation, e.getMessage());
                RapidMinerGUI.getMainFrame().getProcess().setProcessLocation(null);
              } finally {
                getProgressListener().setCompleted(10);
                getProgressListener().complete();
              }
            }
          };
      storeProgressThread.start();
    }
  }
 static {
   resultIcon = SwingTools.createIcon("16/" + RESULT_ICON_NAME);
 }
  /** Setup the GUI. */
  private void setupGUI() {
    JPanel mainPanel = new JPanel();
    this.setContentPane(mainPanel);

    // start layout
    mainPanel.setLayout(new GridBagLayout());
    GridBagConstraints gbc = new GridBagConstraints();

    gbc.gridx = 0;
    gbc.gridy = 0;
    gbc.fill = GridBagConstraints.NONE;
    gbc.weightx = 0;
    gbc.anchor = GridBagConstraints.WEST;
    gbc.insets = new Insets(5, 5, 2, 5);
    JLabel valueLabel =
        new JLabel(
            I18N.getMessage(I18N.getGUIBundle(), "gui.action.edit_parallel_line.value.label"));
    this.add(valueLabel, gbc);

    gbc.gridx = 1;
    gbc.gridy = 0;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    gbc.weightx = 1;
    valueField = new JTextField();
    valueField.setInputVerifier(
        new InputVerifier() {

          @Override
          public boolean verify(JComponent input) {
            return verifyValueInput(input);
          }
        });
    valueField.setToolTipText(
        I18N.getMessage(I18N.getGUIBundle(), "gui.action.edit_parallel_line.value.tip"));
    this.add(valueField, gbc);

    gbc.gridx = 0;
    gbc.gridy = 1;
    gbc.fill = GridBagConstraints.NONE;
    gbc.weightx = 0;
    JLabel colorLabel =
        new JLabel(
            I18N.getMessage(I18N.getGUIBundle(), "gui.action.edit_parallel_line.color.label"));
    this.add(colorLabel, gbc);

    gbc.gridx = 1;
    gbc.gridy = 1;
    lineColorButton =
        new JButton(
            new ResourceAction(true, "edit_parallel_line.select_line_color") {

              private static final long serialVersionUID = 1L;

              @Override
              public void actionPerformed(ActionEvent e) {
                createLineColorDialog();
              }
            });
    this.add(lineColorButton, gbc);

    gbc.gridx = 0;
    gbc.gridy = 2;
    JLabel widthLabel =
        new JLabel(
            I18N.getMessage(I18N.getGUIBundle(), "gui.action.edit_parallel_line.width.label"));
    this.add(widthLabel, gbc);

    gbc.gridx = 1;
    gbc.gridy = 2;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    gbc.weightx = 1;
    widthField = new JTextField();
    widthField.setInputVerifier(
        new InputVerifier() {

          @Override
          public boolean verify(JComponent input) {
            return verifyWidthInput(input);
          }
        });
    widthField.setToolTipText(
        I18N.getMessage(I18N.getGUIBundle(), "gui.action.edit_parallel_line.width.tip"));
    this.add(widthField, gbc);

    gbc.gridx = 0;
    gbc.gridy = 3;
    gbc.fill = GridBagConstraints.NONE;
    gbc.weightx = 0;
    JLabel styleLabel =
        new JLabel(
            I18N.getMessage(I18N.getGUIBundle(), "gui.action.edit_parallel_line.line_style.label"));
    this.add(styleLabel, gbc);

    gbc.gridx = 1;
    gbc.gridy = 3;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    gbc.weightx = 1;
    lineStyleCombobox = new JComboBox(LineStyle.values());
    ((DefaultComboBoxModel) lineStyleCombobox.getModel()).removeElement(LineStyle.NONE);
    lineStyleCombobox.setToolTipText(
        I18N.getMessage(I18N.getGUIBundle(), "gui.action.edit_parallel_line.line_style.tip"));
    lineStyleCombobox.setSelectedItem(LineStyle.SOLID);
    this.add(lineStyleCombobox, gbc);

    gbc.gridx = 0;
    gbc.gridy = 4;
    gbc.gridwidth = 2;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    gbc.weightx = 1;
    gbc.weighty = 0;
    gbc.anchor = GridBagConstraints.CENTER;
    gbc.insets = new Insets(15, 5, 5, 5);
    this.add(new JSeparator(), gbc);

    gbc.gridx = 0;
    gbc.gridy = 5;
    gbc.gridwidth = 1;
    gbc.fill = GridBagConstraints.NONE;
    gbc.anchor = GridBagConstraints.WEST;
    gbc.insets = new Insets(5, 5, 5, 5);
    okButton =
        new JButton(I18N.getMessage(I18N.getGUIBundle(), "gui.action.edit_parallel_line.ok.label"));
    okButton.setToolTipText(
        I18N.getMessage(I18N.getGUIBundle(), "gui.action.edit_parallel_line.ok.tip"));
    okButton.setIcon(
        SwingTools.createIcon(
            "24/" + I18N.getMessage(I18N.getGUIBundle(), "gui.action.edit_parallel_line.ok.icon")));
    okButton.setMnemonic(
        I18N.getMessage(I18N.getGUIBundle(), "gui.action.edit_parallel_line.ok.mne")
            .toCharArray()[0]);
    okButton.addActionListener(
        new ActionListener() {

          @Override
          public void actionPerformed(ActionEvent e) {
            boolean successful = editLine();
            // don't dispose dialog if not successful
            if (!successful) {
              return;
            }

            EditParallelLineDialog.this.dispose();
          }
        });
    okButton.addKeyListener(
        new KeyAdapter() {

          @Override
          public void keyPressed(KeyEvent e) {
            if (e.getKeyCode() == KeyEvent.VK_ENTER) {
              okButton.doClick();
            }
          }
        });
    this.add(okButton, gbc);

    gbc.gridx = 1;
    gbc.gridy = 5;
    gbc.fill = GridBagConstraints.NONE;
    gbc.anchor = GridBagConstraints.EAST;
    cancelButton =
        new JButton(
            I18N.getMessage(I18N.getGUIBundle(), "gui.action.edit_parallel_line.cancel.label"));
    cancelButton.setToolTipText(
        I18N.getMessage(I18N.getGUIBundle(), "gui.action.edit_parallel_line.cancel.tip"));
    cancelButton.setIcon(
        SwingTools.createIcon(
            "24/"
                + I18N.getMessage(
                    I18N.getGUIBundle(), "gui.action.edit_parallel_line.cancel.icon")));
    cancelButton.setMnemonic(
        I18N.getMessage(I18N.getGUIBundle(), "gui.action.edit_parallel_line.cancel.mne")
            .toCharArray()[0]);
    cancelButton.addActionListener(
        new ActionListener() {

          @Override
          public void actionPerformed(ActionEvent e) {
            // cancel requested, close dialog
            EditParallelLineDialog.this.dispose();
          }
        });
    this.add(cancelButton, gbc);

    // misc settings
    this.setMinimumSize(new Dimension(275, 225));
    // center dialog
    this.setLocationRelativeTo(null);
    this.setTitle(
        I18N.getMessage(I18N.getGUIBundle(), "gui.action.edit_parallel_line.title.label"));
    this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
    this.setModal(true);
    this.addWindowListener(
        new WindowAdapter() {

          @Override
          public void windowActivated(WindowEvent e) {
            cancelButton.requestFocusInWindow();
          }
        });
  }
/**
 * This panel displays parameters of an operator. It refreshes in either of these cases:
 *
 * <ul>
 *   <li>A new operator is selected.
 *   <li>The {@link Parameters} of the current operator (which are observed) change in a way such
 *       that the parameter value differs from the one displayed by the editor. This should only
 *       happen if a parameter value is changed programmatically, e.g. by an operator.
 *   <li>{@link #processUpdated(Process)} is called and {@link #getProperties()} returns a different
 *       list than the one returned during the last {@link #setupComponents()}.
 *   <li>When changing to expert mode.
 * </ul>
 *
 * @author Simon Fischer, Tobias Malbrecht
 */
public class OperatorPropertyPanel extends PropertyPanel implements Dockable, ProcessEditor {

  private static final long serialVersionUID = 6056794546696461864L;

  private class BreakpointButton extends ToggleDropDownButton implements ToggleActionListener {

    private static final long serialVersionUID = 7364886954405951709L;

    private final Icon IMAGE_BREAKPOINTS = SwingTools.createIcon("16/breakpoints.png");
    private final Icon IMAGE_BREAKPOINT_BEFORE = SwingTools.createIcon("16/breakpoint_up.png");
    private final Icon IMAGE_BREAKPOINT_AFTER = SwingTools.createIcon("16/breakpoint_down.png");

    {
      for (int i = 0; i < mainFrame.getActions().TOGGLE_BREAKPOINT.length; i++) {
        mainFrame.getActions().TOGGLE_BREAKPOINT[i].addToggleActionListener(this);
      }
    }

    public BreakpointButton() {
      super(
          new ResourceAction(true, "breakpoint_after") {
            private static final long serialVersionUID = -8913366165786891652L;

            @Override
            public void actionPerformed(ActionEvent e) {
              if (mainFrame.getActions().TOGGLE_BREAKPOINT[0].isSelected()
                  || mainFrame.getActions().TOGGLE_BREAKPOINT[1].isSelected()) {
                mainFrame.getActions().TOGGLE_BREAKPOINT[0].resetAction(false);
                mainFrame.getActions().TOGGLE_BREAKPOINT[1].resetAction(false);
                return;
              }
              mainFrame.getActions().TOGGLE_BREAKPOINT[1].actionPerformed(null);
            }
          });
    }

    @Override
    public void setSelected(boolean selected) {
      Icon breakpointIcon;
      if (operator != null && operator.hasBreakpoint()) {
        super.setSelected(true);
        if (operator.getNumberOfBreakpoints() == 1) {
          if (operator.hasBreakpoint(BreakpointListener.BREAKPOINT_BEFORE)) {
            breakpointIcon = IMAGE_BREAKPOINT_BEFORE;
          } else {
            breakpointIcon = IMAGE_BREAKPOINT_AFTER;
          }
        } else {
          breakpointIcon = IMAGE_BREAKPOINTS;
        }
      } else {
        super.setSelected(false);
        breakpointIcon = IMAGE_BREAKPOINT_AFTER;
      }
      setIcon(breakpointIcon);
    }

    @Override
    protected JPopupMenu getPopupMenu() {
      JPopupMenu menu = new JPopupMenu();
      for (int i = 0; i < mainFrame.getActions().TOGGLE_BREAKPOINT.length; i++) {
        menu.add(mainFrame.getActions().TOGGLE_BREAKPOINT[i].createMenuItem());
      }
      return menu;
    }
  }

  private final BreakpointButton breakpointButton;

  private final MainFrame mainFrame;

  private static final Icon WARNING_ICON = SwingTools.createIcon("16/sign_warning.png");

  private final JLabel headerLabel = new JLabel("");

  private final Font selectedFont = headerLabel.getFont().deriveFont(Font.BOLD);

  private final Font unselectedFont = headerLabel.getFont();

  private final JLabel expertModeHintLabel = new JLabel("");

  private Operator operator;

  private final Observer<String> parameterObserver =
      new Observer<String>() {
        @Override
        public void update(Observable<String> observable, String key) {
          PropertyValueCellEditor editor = getEditorForKey(key);
          if (editor != null) {
            ParameterType type = operator.getParameters().getParameterType(key);
            String editorValue = type.toString(editor.getCellEditorValue());
            String opValue = operator.getParameters().getParameterOrNull(key);
            if (((opValue != null) && (editorValue == null))
                || ((opValue == null) && (editorValue != null))
                || ((opValue != null) && (editorValue != null) && !opValue.equals(editorValue))) {
              editor.getTableCellEditorComponent(null, opValue, false, 0, 1);
            }
          } else {
            setupComponents();
          }
        }
      };

  private JSpinner compatibilityLevelSpinner = new JSpinner(new CompatibilityLevelSpinnerModel());
  private ResourceLabel compatibilityLabel = new ResourceLabel("compatibility_level");
  private JPanel compatibilityPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));;

  public OperatorPropertyPanel(final MainFrame mainFrame) {
    super();
    this.mainFrame = mainFrame;
    breakpointButton = new BreakpointButton();
    headerLabel.setHorizontalAlignment(SwingConstants.CENTER);
    expertModeHintLabel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
    expertModeHintLabel.setIcon(WARNING_ICON);
    expertModeHintLabel.addMouseListener(
        new MouseListener() {
          public void mouseReleased(MouseEvent e) {
            mainFrame.TOGGLE_EXPERT_MODE_ACTION.actionPerformed(null);
          }

          public void mouseClicked(MouseEvent e) {}

          public void mouseEntered(MouseEvent e) {}

          public void mouseExited(MouseEvent e) {}

          public void mousePressed(MouseEvent e) {}
        });
    expertModeHintLabel.setCursor(new Cursor(Cursor.HAND_CURSOR));
    expertModeHintLabel.setHorizontalAlignment(SwingConstants.LEFT);
    setupComponents();

    compatibilityLevelSpinner.addChangeListener(
        new ChangeListener() {
          @Override
          public void stateChanged(ChangeEvent e) {
            // compatibility level
            OperatorVersion[] versionChanges = operator.getIncompatibleVersionChanges();
            if (versionChanges.length != 0) {
              OperatorVersion latestChange = versionChanges[versionChanges.length - 1];
              if (latestChange.isAtLeast(operator.getCompatibilityLevel())) {
                compatibilityLabel.setIcon(WARNING_ICON);
              } else {
                compatibilityLabel.setIcon(SwingTools.createIcon("16/ok.png"));
              }
            }
          }
        });
  }

  @Override
  protected String getValue(ParameterType type) {
    return operator.getParameters().getParameterOrNull(type.getKey());
  }

  @Override
  protected void setValue(Operator operator, ParameterType type, String value) {
    if (value.length() == 0) {
      value = null;
    }
    operator.setParameter(type.getKey(), value);
  }

  @Override
  protected List<ParameterType> getProperties() {
    List<ParameterType> visible = new LinkedList<ParameterType>();
    int hidden = 0;
    if (operator != null) {
      for (ParameterType type : operator.getParameters().getParameterTypes()) {
        if (type.isHidden()) {
          continue;
        }
        if (!isExpertMode() && type.isExpert()) {
          hidden++;
          continue;
        }
        visible.add(type);
      }
    }

    if (hidden > 0) {
      expertModeHintLabel.setText(hidden + " hidden expert parameter" + (hidden == 1 ? "" : "s"));
      expertModeHintLabel.setVisible(true);
    } else {
      expertModeHintLabel.setVisible(false);
    }
    return visible;
  }

  @Override
  public void processChanged(Process process) {}

  @Override
  public void processUpdated(Process process) {
    setNameFor(operator);
    // check if we have editors for the current parameters. If not, refresh.
    int count = 0; // count hits. If we have to many, also refresh
    List<ParameterType> properties = getProperties();
    if (properties.size() != getNumberOfEditors()) {
      setupComponents();
      return;
    }
    for (ParameterType type : properties) {
      if (hasEditorFor(type)) {
        count++;
      } else {
        setupComponents();
        return;
      }
    }
    if (count != properties.size()) {
      setupComponents();
    }
  }

  @Override
  public void setSelection(List<Operator> selection) {
    Operator operator = selection.isEmpty() ? null : selection.get(0);
    if (operator == this.operator) {
      return;
    }
    if (this.operator != null) {
      this.operator.getParameters().removeObserver(parameterObserver);
    }
    this.operator = operator;
    if (operator != null) {
      this.operator.getParameters().addObserver(parameterObserver, true);
      breakpointButton.setEnabled(true);

      // compatibility level
      OperatorVersion[] versionChanges = operator.getIncompatibleVersionChanges();
      if (versionChanges.length == 0) {
        // no incompatible versions exist
        compatibilityLevelSpinner.setVisible(false);
        compatibilityLabel.setVisible(false);
      } else {
        compatibilityLevelSpinner.setVisible(true);
        compatibilityLabel.setVisible(true);
        ((CompatibilityLevelSpinnerModel) compatibilityLevelSpinner.getModel())
            .setOperator(operator);
      }

    } else {
      breakpointButton.setEnabled(false);
    }
    setNameFor(operator);
    setupComponents();
  }

  private void setNameFor(Operator operator) {
    if (operator != null) {
      headerLabel.setFont(selectedFont);
      if (operator.getName().equals(operator.getOperatorDescription().getName())) {
        headerLabel.setText(operator.getName());
      } else {
        headerLabel.setText(
            operator.getName() + " (" + operator.getOperatorDescription().getName() + ")");
      }
      headerLabel.setIcon(operator.getOperatorDescription().getSmallIcon());

    } else {
      headerLabel.setFont(unselectedFont);
      headerLabel.setText("No Operator Selected");
      headerLabel.setIcon(null);
    }
  }

  @Override
  public Component getComponent() {
    if (dockableComponent == null) {
      JScrollPane scrollPane = new ExtendedJScrollPane(this);
      scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
      scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
      scrollPane.setBorder(null);

      dockableComponent = new JPanel(new BorderLayout());

      JPanel toolBarPanel = new JPanel(new BorderLayout());
      ViewToolBar toolBar = new ViewToolBar();
      JToggleButton toggleExpertModeButton =
          mainFrame.TOGGLE_EXPERT_MODE_ACTION.createToggleButton();
      toggleExpertModeButton.setText(null);
      toolBar.add(toggleExpertModeButton);
      Action infoOperatorAction =
          new InfoOperatorAction() {
            private static final long serialVersionUID = 6758272768665592429L;

            @Override
            protected Operator getOperator() {
              return mainFrame.getFirstSelectedOperator();
            }
          };
      toolBar.add(infoOperatorAction);
      JToggleButton enableOperatorButton =
          new ToggleActivationItem(mainFrame.getActions()).createToggleButton();
      enableOperatorButton.setText(null);
      toolBar.add(enableOperatorButton);
      Action renameOperatorAction =
          new ResourceAction(true, "rename_in_processrenderer") {
            {
              setCondition(OPERATOR_SELECTED, MANDATORY);
            }

            private static final long serialVersionUID = -3104160320178045540L;

            @Override
            public void actionPerformed(ActionEvent e) {
              Operator operator = mainFrame.getFirstSelectedOperator();
              String name = SwingTools.showInputDialog("rename_operator", operator.getName());
              if (name != null && name.length() > 0) {
                operator.rename(name);
              }
            }
          };
      toolBar.add(renameOperatorAction);
      toolBar.add(new DeleteOperatorAction());
      breakpointButton.addToToolBar(toolBar);
      //			toolBar.add(mainFrame.getActions().MAKE_DIRTY_ACTION);
      toolBarPanel.add(toolBar, BorderLayout.NORTH);

      JPanel headerPanel = new JPanel();
      headerPanel.setBackground(SwingTools.LIGHTEST_BLUE);
      headerPanel.add(headerLabel);
      headerPanel.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.LIGHT_GRAY));
      toolBarPanel.add(headerPanel, BorderLayout.SOUTH);

      dockableComponent.add(toolBarPanel, BorderLayout.NORTH);
      dockableComponent.add(scrollPane, BorderLayout.CENTER);

      // compatibility level and warnings
      JPanel southPanel = new JPanel(new BorderLayout());
      southPanel.add(expertModeHintLabel, BorderLayout.CENTER);
      compatibilityLabel.setLabelFor(compatibilityLevelSpinner);
      compatibilityLevelSpinner.setPreferredSize(
          new Dimension(80, (int) compatibilityLevelSpinner.getPreferredSize().getHeight()));
      compatibilityPanel.add(compatibilityLabel);
      compatibilityPanel.add(compatibilityLevelSpinner);
      southPanel.add(compatibilityPanel, BorderLayout.SOUTH);

      dockableComponent.add(southPanel, BorderLayout.SOUTH);
    }
    return dockableComponent;
  }

  // implements Dockable

  public static final String PROPERTY_EDITOR_DOCK_KEY = "property_editor";
  private final DockKey DOCK_KEY = new ResourceDockKey(PROPERTY_EDITOR_DOCK_KEY);

  {
    DOCK_KEY.setDockGroup(MainFrame.DOCK_GROUP_ROOT);
  }

  private JPanel dockableComponent;

  @Override
  public DockKey getDockKey() {
    return DOCK_KEY;
  }

  public boolean isExpertMode() {
    return mainFrame.TOGGLE_EXPERT_MODE_ACTION.isSelected();
  }

  @Override
  protected Operator getOperator() {
    return operator;
  }
}
  private class BreakpointButton extends ToggleDropDownButton implements ToggleActionListener {

    private static final long serialVersionUID = 7364886954405951709L;

    private final Icon IMAGE_BREAKPOINTS = SwingTools.createIcon("16/breakpoints.png");
    private final Icon IMAGE_BREAKPOINT_BEFORE = SwingTools.createIcon("16/breakpoint_up.png");
    private final Icon IMAGE_BREAKPOINT_AFTER = SwingTools.createIcon("16/breakpoint_down.png");

    {
      for (int i = 0; i < mainFrame.getActions().TOGGLE_BREAKPOINT.length; i++) {
        mainFrame.getActions().TOGGLE_BREAKPOINT[i].addToggleActionListener(this);
      }
    }

    public BreakpointButton() {
      super(
          new ResourceAction(true, "breakpoint_after") {
            private static final long serialVersionUID = -8913366165786891652L;

            @Override
            public void actionPerformed(ActionEvent e) {
              if (mainFrame.getActions().TOGGLE_BREAKPOINT[0].isSelected()
                  || mainFrame.getActions().TOGGLE_BREAKPOINT[1].isSelected()) {
                mainFrame.getActions().TOGGLE_BREAKPOINT[0].resetAction(false);
                mainFrame.getActions().TOGGLE_BREAKPOINT[1].resetAction(false);
                return;
              }
              mainFrame.getActions().TOGGLE_BREAKPOINT[1].actionPerformed(null);
            }
          });
    }

    @Override
    public void setSelected(boolean selected) {
      Icon breakpointIcon;
      if (operator != null && operator.hasBreakpoint()) {
        super.setSelected(true);
        if (operator.getNumberOfBreakpoints() == 1) {
          if (operator.hasBreakpoint(BreakpointListener.BREAKPOINT_BEFORE)) {
            breakpointIcon = IMAGE_BREAKPOINT_BEFORE;
          } else {
            breakpointIcon = IMAGE_BREAKPOINT_AFTER;
          }
        } else {
          breakpointIcon = IMAGE_BREAKPOINTS;
        }
      } else {
        super.setSelected(false);
        breakpointIcon = IMAGE_BREAKPOINT_AFTER;
      }
      setIcon(breakpointIcon);
    }

    @Override
    protected JPopupMenu getPopupMenu() {
      JPopupMenu menu = new JPopupMenu();
      for (int i = 0; i < mainFrame.getActions().TOGGLE_BREAKPOINT.length; i++) {
        menu.add(mainFrame.getActions().TOGGLE_BREAKPOINT[i].createMenuItem());
      }
      return menu;
    }
  }