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 } }
/** @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; } }
static { resultIcon = SwingTools.createIcon("16/" + RESULT_ICON_NAME); }
/** * 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); } }
/** @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; } }
/** 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(); } }); }
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; } }
/** * 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; } }
static { int counter = 0; for (IconSize size : IconSize.values()) { ICONS[counter++] = SwingTools.createIcon(size.getSize() + "/" + ICON_NAME); } }
static { icon = SwingTools.createIcon("48/" + ICON_NAME); }
/** * A dialog to create and edit regular expressions. Can be created with a given predefined regular * expression (normally a previously set value). A collection of item strings can be given to the * dialog which are then available as shortcuts. Additionally, a list shows which of these items * match the regular expression. If the item collection is null, both lists will not be visible. * * <p>The dialog shows an inline preview displaying where the given pattern matches. It also shows a * list of matches, together with their matching groups. * * @author Tobias Malbrecht, Dominik Halfkann, Simon Fischer */ public class RegexpPropertyDialog extends ButtonDialog { private static final long serialVersionUID = 5396725165122306231L; private RegexpSearchStyledDocument inlineSearchDocument = null; private RegexpReplaceStyledDocument inlineReplaceDocument = null; private JTabbedPane testExp = null; private DefaultListModel<RegExpResult> resultsListModel = new DefaultListModel<RegExpResult>(); private static String[][] regexpConstructs = { { ".", I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.constructs.any_character") }, { "[]", I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.constructs.bracket_expression") }, { "[^]", I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.constructs.not_bracket_expression") }, { "()", I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.constructs.capturing_group") }, { "?", I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.constructs.zero_one_quantifier") }, { "*", I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.constructs.zero_more_quantifier") }, { "+", I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.constructs.one_more_quantifier") }, { "{n}", I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.constructs.exact_quantifier") }, { "{min,}", I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.constructs.min_quantifier") }, { "{min,max}", I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.constructs.min_max_quantifier") }, { "|", I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.constructs.disjunction") }, }; // adjust the caret by this amount upon insertion private static int[] regexpConstructInsertionCaretAdjustment = { 0, -1, -1, -1, 0, 0, 0, -1, -2, -1, -5, 0, }; // select these construct characters upon insertion private static int[][] regexpConstructInsertionSelectionIndices = { {1, 1}, {1, 1}, {2, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 2}, {1, 4}, {1, 8}, {1, 1}, }; // enclose selected by construct private static boolean[] regexpConstructInsertionEncloseSelected = { false, true, true, true, false, false, false, false, false, false, false, }; private static String[][] regexpShortcuts = { {".*", I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.shortcuts.arbitrary")}, { "[a-zA-Z]", I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.shortcuts.letter") }, { "[a-z]", I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.shortcuts.lowercase_letter") }, { "[A-Z]", I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.shortcuts.uppercase_letter") }, {"[0-9]", I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.shortcuts.digit")}, {"\\w", I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.shortcuts.word")}, {"\\W", I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.shortcuts.non_word")}, { "\\s", I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.shortcuts.whitespace") }, { "\\S", I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.shortcuts.non_whitespace") }, { "[-!\"#$%&'()*+,./:;<=>?@\\[\\\\\\]_`{|}~]", I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.shortcuts.punctuation") }, }; private static final String ERROR_MESSAGE = I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.error.label"); private static final Icon ERROR_ICON = SwingTools.createIcon( "16/" + I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.error.icon")); private static final String NO_ERROR_MESSAGE = I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.no_error.label"); private static final Icon NO_ERROR_ICON = SwingTools.createIcon( "16/" + I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.no_error.icon")); private String infoText; private final JTextField regexpTextField; private final JTextField replacementTextField; private JList<String> itemShortcutsList; private DefaultListModel<String> matchedItemsListModel; private final Collection<String> items; private boolean supportsItems = false; private final JLabel errorMessage; private JButton okButton; JCheckBox cbCaseInsensitive; JCheckBox cbComments; JCheckBox cbMultiline; JCheckBox cbDotall; JCheckBox cbUnicodeCase; /** Class representing a single regexp search result. * */ private class RegExpResult { private String match; private String[] groups; private int number; private boolean empty = false; public RegExpResult(String match, String[] groups, int number) { this.match = match; this.groups = groups; this.number = number; } public RegExpResult() { // empty result empty = true; } @Override public String toString() { String output = ""; if (!empty) { output += "<html>" + "<span style=\"font-size:11px;margin:2px 0 2px 4px;\">" + // "Match "+number+": <b>'"+match+"'</b>" + I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.result_list.match", number, "<b>'" + Tools.escapeHTML(match) + "'</b>") + "</span>"; if (groups.length > 0) { output += "<ol style=\"margin:1px 0 0 24px\">"; for (int i = 0; i < groups.length; i++) { // output += "<li>Group matches: <b>'" + groups[i] +"'</b></li>"; output += "<li>" + I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.result_list.group_match", "<b>'" + Tools.escapeHTML(groups[i]) + "'</b>") + "</li>"; } output += "</ul>"; } output += "</html>"; } else { output += "<html>" + "<span style=\"font-size:11px;margin:2px 0 2px 4px;\">" + I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.result_list.empty") + "</span>"; output += "</html>"; } return output; } } /** A StyledDocument providing a live regexp search * */ private class RegexpSearchStyledDocument extends DefaultStyledDocument { private static final long serialVersionUID = 1L; private Matcher matcher = Pattern.compile("").matcher(""); Style keyStyle; Style rootStyle; { rootStyle = addStyle("root", null); keyStyle = addStyle("key", rootStyle); StyleConstants.setBackground(keyStyle, Color.YELLOW); } @Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { super.insertString(offs, str, a); checkDocument(); } @Override public void remove(int offs, int len) throws BadLocationException { super.remove(offs, len); checkDocument(); } private void checkDocument() { setCharacterAttributes(0, getLength(), rootStyle, true); try { matcher.reset(getText(0, getLength())); int count = 0; resultsListModel.clear(); while (matcher.find()) { if (matcher.end() <= matcher.start()) { continue; } setCharacterAttributes(matcher.start(), matcher.end() - matcher.start(), keyStyle, true); String[] groups = new String[matcher.groupCount()]; for (int i = 1; i <= matcher.groupCount(); i++) { groups[i - 1] = matcher.group(i); } resultsListModel.addElement( new RegExpResult( this.getText(matcher.start(), matcher.end() - matcher.start()), groups, count + 1)); count++; } if (count == 0) { // add empty element resultsListModel.addElement(new RegExpResult()); } testExp.setTitleAt( 1, I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.result_list.title") + " (" + count + ")"); inlineReplaceDocument.setText(matcher.replaceAll(replacementTextField.getText())); updateRegexpOptions(); } catch (BadLocationException ex) { LogService.getRoot() .log(Level.WARNING, RegexpPropertyDialog.class.getName() + ".bad_location", ex); } } public void updatePattern(String pattern) { this.matcher = Pattern.compile(pattern).matcher(""); checkDocument(); } public void clearResults() { resultsListModel.clear(); resultsListModel.addElement(new RegExpResult()); testExp.setTitleAt( 1, I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.result_list.title") + " (0)"); setCharacterAttributes(0, getLength(), rootStyle, true); } } /** A StyledDocument with an added setText() method for interting the replaced text * */ private class RegexpReplaceStyledDocument extends DefaultStyledDocument { private static final long serialVersionUID = 1L; public RegexpReplaceStyledDocument() { super(); } public void setText(String text) { try { remove(0, getLength()); insertString(0, text, null); } catch (BadLocationException e) { LogService.getRoot() .log(Level.WARNING, RegexpPropertyDialog.class.getName() + ".bad_location", e); } } } public RegexpPropertyDialog( final Collection<String> items, String predefinedRegexp, String description) { super( ApplicationFrame.getApplicationFrame(), "parameter.regexp", ModalityType.APPLICATION_MODAL, new Object[] {}); this.items = items; this.supportsItems = items != null; this.infoText = "<html>" + I18N.getMessage(I18N.getGUIBundle(), getKey() + ".title") + ": <br/>" + description + "</html>"; Dimension size = new Dimension(420, 500); this.setMinimumSize(size); this.setPreferredSize(size); JPanel panel = new JPanel(createGridLayout(1, supportsItems ? 2 : 1)); // create regexp text field regexpTextField = new JTextField(predefinedRegexp); regexpTextField.setToolTipText( I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.tip")); regexpTextField.addKeyListener( new KeyListener() { @Override public void keyPressed(KeyEvent e) {} @Override public void keyReleased(KeyEvent e) { fireRegularExpressionUpdated(); } @Override public void keyTyped(KeyEvent e) {} }); regexpTextField.requestFocus(); // create replacement text field replacementTextField = new JTextField(); replacementTextField.setToolTipText( I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.replacement.tip")); replacementTextField.addKeyListener( new KeyListener() { @Override public void keyPressed(KeyEvent e) {} @Override public void keyReleased(KeyEvent e) { fireRegularExpressionUpdated(); } @Override public void keyTyped(KeyEvent e) {} }); // create inline search documents inlineSearchDocument = new RegexpSearchStyledDocument(); inlineReplaceDocument = new RegexpReplaceStyledDocument(); // create search results list DefaultListCellRenderer resultCellRenderer = new DefaultListCellRenderer() { private static final long serialVersionUID = 1L; @Override public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); setBackground(list.getBackground()); setForeground(list.getForeground()); setBorder(getNoFocusBorder()); return this; } private Border getNoFocusBorder() { Border border = BorderFactory.createMatteBorder(0, 0, 1, 0, Color.gray); return border; } }; JList<RegExpResult> regexpFindingsList = new JList<RegExpResult>(resultsListModel); regexpFindingsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); regexpFindingsList.setLayoutOrientation(JList.VERTICAL); regexpFindingsList.setCellRenderer(resultCellRenderer); // regexp panel on left side of dialog JPanel regexpPanel = new JPanel(new GridBagLayout()); regexpPanel.setBorder( createTitledBorder( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.border"))); GridBagConstraints c = new GridBagConstraints(); c.insets = new Insets(4, 4, 4, 0); c.gridx = 0; c.gridy = 0; c.weightx = 1; c.fill = GridBagConstraints.BOTH; regexpPanel.add(regexpTextField, c); // make shortcut button final Action nullAction = new DefaultAction(); PlainArrowDropDownButton autoWireDropDownButton = PlainArrowDropDownButton.makeDropDownButton(nullAction); for (String[] popupItem : (String[][]) ArrayUtils.addAll(regexpConstructs, regexpShortcuts)) { String shortcut = popupItem[0].length() > 14 ? popupItem[0].substring(0, 14) + "..." : popupItem[0]; autoWireDropDownButton.add( new InsertionAction( "<html><table border=0 cellpadding=0 cellspacing=0><tr><td width=100>" + shortcut + "</td><td>" + popupItem[1] + "</td></tr></table></html>", popupItem[0])); } c.insets = new Insets(4, 0, 4, 0); c.gridx = 1; c.weightx = 0; c.fill = GridBagConstraints.HORIZONTAL; regexpPanel.add(autoWireDropDownButton.getDropDownArrowButton(), c); // make delete button c.insets = new Insets(4, 0, 4, 4); c.gridx = 2; c.weightx = 0; c.fill = GridBagConstraints.HORIZONTAL; JButton clearRegexpTextFieldButton = new JButton(SwingTools.createIcon("16/delete2.png")); clearRegexpTextFieldButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { regexpTextField.setText(""); fireRegularExpressionUpdated(); regexpTextField.requestFocusInWindow(); } }); regexpPanel.add(clearRegexpTextFieldButton, c); errorMessage = new JLabel(NO_ERROR_MESSAGE, NO_ERROR_ICON, SwingConstants.LEFT); errorMessage.setFocusable(false); c.insets = new Insets(4, 8, 4, 4); c.gridx = 0; c.gridy = 1; c.weightx = 0; c.weighty = 0; c.gridwidth = GridBagConstraints.REMAINDER; regexpPanel.add(errorMessage, c); // create replacement panel JPanel replacementPanel = new JPanel(new GridBagLayout()); replacementPanel.setBorder( createTitledBorder( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.replacement.border"))); JPanel testerPanel = new JPanel(new GridBagLayout()); c.insets = new Insets(4, 4, 4, 0); c.gridx = 0; c.gridy = 0; c.weightx = 1; c.fill = GridBagConstraints.HORIZONTAL; replacementPanel.add(replacementTextField, c); // create inline search panel JPanel inlineSearchPanel = new JPanel(new GridBagLayout()); c.insets = new Insets(8, 4, 4, 4); c.gridx = 0; c.gridy = 0; c.weightx = 1; c.weighty = 0; c.fill = GridBagConstraints.HORIZONTAL; inlineSearchPanel.add( new JLabel( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.inline_search.search")), c); c.insets = new Insets(0, 0, 0, 0); c.gridx = 0; c.gridy = 1; c.weightx = 1; c.weighty = 1; c.fill = GridBagConstraints.BOTH; inlineSearchPanel.add(new JScrollPane(new JTextPane(inlineSearchDocument)), c); c.insets = new Insets(8, 4, 4, 4); c.gridx = 0; c.gridy = 2; c.weightx = 1; c.weighty = 0; c.fill = GridBagConstraints.HORIZONTAL; inlineSearchPanel.add( new JLabel( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.inline_search.replaced")), c); c.insets = new Insets(0, 0, 0, 0); c.gridx = 0; c.gridy = 3; c.weightx = 1; c.weighty = 1; c.fill = GridBagConstraints.BOTH; JTextPane replaceTextPane = new JTextPane(inlineReplaceDocument); replaceTextPane.setEditable(false); inlineSearchPanel.add(new JScrollPane(replaceTextPane), c); // create regexp options panel ItemListener defaultOptionListener = new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { fireRegexpOptionsChanged(); } }; cbCaseInsensitive = new JCheckBox( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.regexp_options.case_insensitive")); cbCaseInsensitive.setToolTipText( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.regexp_options.case_insensitive.tip")); cbCaseInsensitive.addItemListener(defaultOptionListener); cbMultiline = new JCheckBox( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.regexp_options.multiline_mode")); cbMultiline.setToolTipText( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.regexp_options.multiline_mode.tip")); cbMultiline.addItemListener(defaultOptionListener); cbDotall = new JCheckBox( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.regexp_options.dotall_mode")); cbDotall.setToolTipText( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.regexp_options.dotall_mode.tip")); cbDotall.addItemListener(defaultOptionListener); cbUnicodeCase = new JCheckBox( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.regexp_options.unicode_case")); cbUnicodeCase.setToolTipText( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.regexp_options.unicode_case.tip")); cbUnicodeCase.addItemListener(defaultOptionListener); JPanel regexpOptionsPanelWrapper = new JPanel(new BorderLayout()); JPanel regexpOptionsPanel = new JPanel(new GridBagLayout()); regexpOptionsPanelWrapper.add(regexpOptionsPanel, BorderLayout.NORTH); c.insets = new Insets(12, 4, 0, 4); c.gridx = 0; c.gridy = 0; c.weightx = 1; c.weighty = 0; c.fill = GridBagConstraints.HORIZONTAL; regexpOptionsPanel.add(cbMultiline, c); c.insets = new Insets(8, 4, 0, 4); c.gridy = 1; regexpOptionsPanel.add(cbCaseInsensitive, c); c.gridy = 2; regexpOptionsPanel.add(cbUnicodeCase, c); c.gridy = 3; regexpOptionsPanel.add(cbDotall, c); // create tabbed panel c.insets = new Insets(8, 4, 4, 4); c.gridx = 0; c.gridy = 0; c.weightx = 1; c.weighty = 1; c.gridwidth = GridBagConstraints.REMAINDER; c.fill = GridBagConstraints.BOTH; testExp = new JTabbedPane(); testExp.add( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.inline_search.title"), new JScrollPane(inlineSearchPanel)); testExp.add( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.result_list.title"), new JScrollPane(regexpFindingsList)); testExp.add( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.regexp_options.title"), regexpOptionsPanelWrapper); testerPanel.add(testExp, c); JPanel groupPanel = new JPanel(new GridBagLayout()); c.insets = new Insets(4, 4, 4, 4); c.gridx = 0; c.gridy = 0; c.weightx = 1; c.weighty = 0; c.fill = GridBagConstraints.HORIZONTAL; groupPanel.add(regexpPanel, c); c.insets = new Insets(4, 4, 4, 4); c.gridx = 0; c.gridy = 1; c.weightx = 1; c.weighty = 0; c.fill = GridBagConstraints.HORIZONTAL; groupPanel.add(replacementPanel, c); c.insets = new Insets(4, 4, 4, 4); c.gridx = 0; c.gridy = 2; c.weightx = 1; c.weighty = 1; c.fill = GridBagConstraints.BOTH; groupPanel.add(testerPanel, c); panel.add(groupPanel, 1, 0); if (supportsItems) { // item shortcuts list itemShortcutsList = new JList<String>(items.toArray(new String[items.size()])); itemShortcutsList.setToolTipText( I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.item_shortcuts.tip")); itemShortcutsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); itemShortcutsList.addMouseListener( new MouseListener() { @Override public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { String text = regexpTextField.getText(); int cursorPosition = regexpTextField.getCaretPosition(); int index = itemShortcutsList.getSelectedIndex(); if (index > -1 && index < itemShortcutsList.getModel().getSize()) { String insertionString = itemShortcutsList.getModel().getElementAt(index).toString(); String newText = text.substring(0, cursorPosition) + insertionString + (cursorPosition < text.length() ? text.substring(cursorPosition) : ""); regexpTextField.setText(newText); regexpTextField.setCaretPosition(cursorPosition + insertionString.length()); regexpTextField.requestFocus(); fireRegularExpressionUpdated(); } } } @Override public void mouseEntered(MouseEvent e) {} @Override public void mouseExited(MouseEvent e) {} @Override public void mousePressed(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) {} }); JScrollPane itemShortcutsPane = new JScrollPane(itemShortcutsList); itemShortcutsPane.setBorder( createTitledBorder( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.item_shortcuts.border"))); // matched items list matchedItemsListModel = new DefaultListModel<String>(); JList<String> matchedItemsList = new JList<String>(matchedItemsListModel); matchedItemsList.setToolTipText( I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.matched_items.tip")); // add custom cell renderer to disallow selections matchedItemsList.setCellRenderer( new DefaultListCellRenderer() { private static final long serialVersionUID = -5795848004756768378L; @Override public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { return super.getListCellRendererComponent(list, value, index, false, false); } }); JScrollPane matchedItemsPanel = new JScrollPane(matchedItemsList); matchedItemsPanel.setBorder( createTitledBorder( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.matched_items.border"))); // item panel on right side of dialog JPanel itemPanel = new JPanel(createGridLayout(1, 2)); itemPanel.add(itemShortcutsPane, 0, 0); itemPanel.add(matchedItemsPanel, 0, 1); panel.add(itemPanel, 0, 1); } okButton = makeOkButton("regexp_property_dialog_apply"); fireRegularExpressionUpdated(); layoutDefault(panel, supportsItems ? NORMAL : NARROW, okButton, makeCancelButton()); } private void updateRegexpOptions() { boolean multiline = cbMultiline.isSelected(); boolean caseInsensitive = cbCaseInsensitive.isSelected(); boolean dotall = cbDotall.isSelected(); boolean unicodeCase = cbUnicodeCase.isSelected(); String flags = getFlags(regexpTextField.getText()); if (multiline != flags.contains("m")) { cbMultiline.setSelected(flags.contains("m")); } if (caseInsensitive != flags.contains("i")) { cbCaseInsensitive.setSelected(flags.contains("i")); } if (dotall != flags.contains("s")) { cbDotall.setSelected(flags.contains("s")); } if (unicodeCase != flags.contains("u")) { cbUnicodeCase.setSelected(flags.contains("u")); } } private String getFlags(String pattern) { if (!pattern.startsWith("(?")) { return ""; } if (pattern.startsWith("(?-")) { return ""; } if (pattern.indexOf(")") == -1) { return ""; } String flags = pattern.substring(2, pattern.indexOf(")")); return flags.split("-")[0]; } private void fireRegexpOptionsChanged() { boolean multiline = cbMultiline.isSelected(); boolean caseInsensitive = cbCaseInsensitive.isSelected(); boolean dotall = cbDotall.isSelected(); boolean unicodeCase = cbUnicodeCase.isSelected(); String pattern = regexpTextField.getText(); String flags = getFlags(pattern); if (flags.contains("m")) { if (!multiline) { flags = flags.replace("m", ""); } } else { if (multiline) { flags += "m"; } } if (flags.contains("i")) { if (!caseInsensitive) { flags = flags.replace("i", ""); } } else { if (caseInsensitive) { flags += "i"; } } if (flags.contains("u")) { if (!unicodeCase) { flags = flags.replace("u", ""); } } else { if (unicodeCase) { flags += "u"; } } if (flags.contains("s")) { if (!dotall) { flags = flags.replace("s", ""); } } else { if (dotall) { flags += "s"; } } if (!flags.equals("") || pattern.startsWith("(?") && getFlags(pattern).equals("")) { flags = "(?" + flags + ")"; } if (pattern.startsWith("(?") && !pattern.startsWith("(?-")) { int oldFlagsEnd = pattern.indexOf(")"); if (oldFlagsEnd == -1) { oldFlagsEnd = 1; } oldFlagsEnd++; pattern = flags + pattern.substring(oldFlagsEnd); } else { pattern = flags + pattern; } int caretPosition = regexpTextField.getCaretPosition(); regexpTextField.setText(pattern); if (caretPosition < pattern.length()) { regexpTextField.setCaretPosition(caretPosition); } else { regexpTextField.setCaretPosition(pattern.length()); } fireRegularExpressionUpdated(); } private void fireRegularExpressionUpdated() { boolean regularExpressionValid = false; Pattern pattern = null; try { pattern = Pattern.compile(regexpTextField.getText()); regularExpressionValid = true; } catch (PatternSyntaxException e) { regularExpressionValid = false; } if (supportsItems) { matchedItemsListModel.clear(); if (regularExpressionValid && pattern != null) { for (String previewString : items) { if (pattern.matcher(previewString).matches()) { matchedItemsListModel.addElement(previewString); } } } } if (regularExpressionValid) { errorMessage.setText(NO_ERROR_MESSAGE); errorMessage.setIcon(NO_ERROR_ICON); okButton.setEnabled(true); inlineSearchDocument.updatePattern(regexpTextField.getText()); } else { errorMessage.setText(ERROR_MESSAGE); errorMessage.setIcon(ERROR_ICON); okButton.setEnabled(false); inlineSearchDocument.clearResults(); } } private class InsertionAction extends AbstractAction { private static final long serialVersionUID = -5185173378762191200L; private final String insertionString; public InsertionAction(String title, String insertionString) { putValue(Action.NAME, title); this.insertionString = insertionString; } @Override public void actionPerformed(ActionEvent e) { String text = regexpTextField.getText(); // is shortcut a construct? boolean isConstruct = false; int row = -1; for (int i = 0; i < regexpConstructs.length; i++) { if (regexpConstructs[i][0].equals(insertionString)) { isConstruct = true; row = i; break; } } if (isConstruct) { if (regexpConstructInsertionEncloseSelected[row] && regexpTextField.getSelectedText() != null) { int selectionStart = regexpTextField.getSelectionStart(); int selectionEnd = regexpTextField.getSelectionEnd(); String newText = text.substring(0, selectionStart) + insertionString.substring(0, regexpConstructInsertionSelectionIndices[row][0]) + text.substring(selectionStart, selectionEnd) + insertionString.substring( regexpConstructInsertionSelectionIndices[row][0], insertionString.length()) + text.substring(selectionEnd, text.length()); regexpTextField.setText(newText); regexpTextField.setCaretPosition( selectionEnd - regexpConstructInsertionCaretAdjustment[row]); regexpTextField.setSelectionStart( selectionStart + regexpConstructInsertionSelectionIndices[row][0]); regexpTextField.setSelectionEnd( selectionEnd + regexpConstructInsertionSelectionIndices[row][1]); } else { int cursorPosition = regexpTextField.getCaretPosition(); String newText = text.substring(0, cursorPosition) + insertionString + (cursorPosition < text.length() ? text.substring(cursorPosition) : ""); regexpTextField.setText(newText); regexpTextField.setCaretPosition( cursorPosition + insertionString.length() + regexpConstructInsertionCaretAdjustment[row]); regexpTextField.setSelectionStart( cursorPosition + regexpConstructInsertionSelectionIndices[row][0]); regexpTextField.setSelectionEnd( cursorPosition + regexpConstructInsertionSelectionIndices[row][1]); } } else { int cursorPosition = regexpTextField.getCaretPosition(); String newText = text.substring(0, cursorPosition) + insertionString + (cursorPosition < text.length() ? text.substring(cursorPosition) : ""); regexpTextField.setText(newText); regexpTextField.setCaretPosition(cursorPosition + insertionString.length()); } regexpTextField.requestFocus(); fireRegularExpressionUpdated(); } } /** * Sets the text of the search field. * * @param text */ public void setSearchFieldText(String text) { try { this.inlineSearchDocument.insertString(0, text, new SimpleAttributeSet()); } catch (BadLocationException e) { } } public String getRegexp() { return regexpTextField.getText(); } @Override protected String getInfoText() { return infoText; } }
public RegexpPropertyDialog( final Collection<String> items, String predefinedRegexp, String description) { super( ApplicationFrame.getApplicationFrame(), "parameter.regexp", ModalityType.APPLICATION_MODAL, new Object[] {}); this.items = items; this.supportsItems = items != null; this.infoText = "<html>" + I18N.getMessage(I18N.getGUIBundle(), getKey() + ".title") + ": <br/>" + description + "</html>"; Dimension size = new Dimension(420, 500); this.setMinimumSize(size); this.setPreferredSize(size); JPanel panel = new JPanel(createGridLayout(1, supportsItems ? 2 : 1)); // create regexp text field regexpTextField = new JTextField(predefinedRegexp); regexpTextField.setToolTipText( I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.tip")); regexpTextField.addKeyListener( new KeyListener() { @Override public void keyPressed(KeyEvent e) {} @Override public void keyReleased(KeyEvent e) { fireRegularExpressionUpdated(); } @Override public void keyTyped(KeyEvent e) {} }); regexpTextField.requestFocus(); // create replacement text field replacementTextField = new JTextField(); replacementTextField.setToolTipText( I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.replacement.tip")); replacementTextField.addKeyListener( new KeyListener() { @Override public void keyPressed(KeyEvent e) {} @Override public void keyReleased(KeyEvent e) { fireRegularExpressionUpdated(); } @Override public void keyTyped(KeyEvent e) {} }); // create inline search documents inlineSearchDocument = new RegexpSearchStyledDocument(); inlineReplaceDocument = new RegexpReplaceStyledDocument(); // create search results list DefaultListCellRenderer resultCellRenderer = new DefaultListCellRenderer() { private static final long serialVersionUID = 1L; @Override public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); setBackground(list.getBackground()); setForeground(list.getForeground()); setBorder(getNoFocusBorder()); return this; } private Border getNoFocusBorder() { Border border = BorderFactory.createMatteBorder(0, 0, 1, 0, Color.gray); return border; } }; JList<RegExpResult> regexpFindingsList = new JList<RegExpResult>(resultsListModel); regexpFindingsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); regexpFindingsList.setLayoutOrientation(JList.VERTICAL); regexpFindingsList.setCellRenderer(resultCellRenderer); // regexp panel on left side of dialog JPanel regexpPanel = new JPanel(new GridBagLayout()); regexpPanel.setBorder( createTitledBorder( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.border"))); GridBagConstraints c = new GridBagConstraints(); c.insets = new Insets(4, 4, 4, 0); c.gridx = 0; c.gridy = 0; c.weightx = 1; c.fill = GridBagConstraints.BOTH; regexpPanel.add(regexpTextField, c); // make shortcut button final Action nullAction = new DefaultAction(); PlainArrowDropDownButton autoWireDropDownButton = PlainArrowDropDownButton.makeDropDownButton(nullAction); for (String[] popupItem : (String[][]) ArrayUtils.addAll(regexpConstructs, regexpShortcuts)) { String shortcut = popupItem[0].length() > 14 ? popupItem[0].substring(0, 14) + "..." : popupItem[0]; autoWireDropDownButton.add( new InsertionAction( "<html><table border=0 cellpadding=0 cellspacing=0><tr><td width=100>" + shortcut + "</td><td>" + popupItem[1] + "</td></tr></table></html>", popupItem[0])); } c.insets = new Insets(4, 0, 4, 0); c.gridx = 1; c.weightx = 0; c.fill = GridBagConstraints.HORIZONTAL; regexpPanel.add(autoWireDropDownButton.getDropDownArrowButton(), c); // make delete button c.insets = new Insets(4, 0, 4, 4); c.gridx = 2; c.weightx = 0; c.fill = GridBagConstraints.HORIZONTAL; JButton clearRegexpTextFieldButton = new JButton(SwingTools.createIcon("16/delete2.png")); clearRegexpTextFieldButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { regexpTextField.setText(""); fireRegularExpressionUpdated(); regexpTextField.requestFocusInWindow(); } }); regexpPanel.add(clearRegexpTextFieldButton, c); errorMessage = new JLabel(NO_ERROR_MESSAGE, NO_ERROR_ICON, SwingConstants.LEFT); errorMessage.setFocusable(false); c.insets = new Insets(4, 8, 4, 4); c.gridx = 0; c.gridy = 1; c.weightx = 0; c.weighty = 0; c.gridwidth = GridBagConstraints.REMAINDER; regexpPanel.add(errorMessage, c); // create replacement panel JPanel replacementPanel = new JPanel(new GridBagLayout()); replacementPanel.setBorder( createTitledBorder( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.replacement.border"))); JPanel testerPanel = new JPanel(new GridBagLayout()); c.insets = new Insets(4, 4, 4, 0); c.gridx = 0; c.gridy = 0; c.weightx = 1; c.fill = GridBagConstraints.HORIZONTAL; replacementPanel.add(replacementTextField, c); // create inline search panel JPanel inlineSearchPanel = new JPanel(new GridBagLayout()); c.insets = new Insets(8, 4, 4, 4); c.gridx = 0; c.gridy = 0; c.weightx = 1; c.weighty = 0; c.fill = GridBagConstraints.HORIZONTAL; inlineSearchPanel.add( new JLabel( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.inline_search.search")), c); c.insets = new Insets(0, 0, 0, 0); c.gridx = 0; c.gridy = 1; c.weightx = 1; c.weighty = 1; c.fill = GridBagConstraints.BOTH; inlineSearchPanel.add(new JScrollPane(new JTextPane(inlineSearchDocument)), c); c.insets = new Insets(8, 4, 4, 4); c.gridx = 0; c.gridy = 2; c.weightx = 1; c.weighty = 0; c.fill = GridBagConstraints.HORIZONTAL; inlineSearchPanel.add( new JLabel( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.inline_search.replaced")), c); c.insets = new Insets(0, 0, 0, 0); c.gridx = 0; c.gridy = 3; c.weightx = 1; c.weighty = 1; c.fill = GridBagConstraints.BOTH; JTextPane replaceTextPane = new JTextPane(inlineReplaceDocument); replaceTextPane.setEditable(false); inlineSearchPanel.add(new JScrollPane(replaceTextPane), c); // create regexp options panel ItemListener defaultOptionListener = new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { fireRegexpOptionsChanged(); } }; cbCaseInsensitive = new JCheckBox( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.regexp_options.case_insensitive")); cbCaseInsensitive.setToolTipText( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.regexp_options.case_insensitive.tip")); cbCaseInsensitive.addItemListener(defaultOptionListener); cbMultiline = new JCheckBox( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.regexp_options.multiline_mode")); cbMultiline.setToolTipText( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.regexp_options.multiline_mode.tip")); cbMultiline.addItemListener(defaultOptionListener); cbDotall = new JCheckBox( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.regexp_options.dotall_mode")); cbDotall.setToolTipText( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.regexp_options.dotall_mode.tip")); cbDotall.addItemListener(defaultOptionListener); cbUnicodeCase = new JCheckBox( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.regexp_options.unicode_case")); cbUnicodeCase.setToolTipText( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.regexp_options.unicode_case.tip")); cbUnicodeCase.addItemListener(defaultOptionListener); JPanel regexpOptionsPanelWrapper = new JPanel(new BorderLayout()); JPanel regexpOptionsPanel = new JPanel(new GridBagLayout()); regexpOptionsPanelWrapper.add(regexpOptionsPanel, BorderLayout.NORTH); c.insets = new Insets(12, 4, 0, 4); c.gridx = 0; c.gridy = 0; c.weightx = 1; c.weighty = 0; c.fill = GridBagConstraints.HORIZONTAL; regexpOptionsPanel.add(cbMultiline, c); c.insets = new Insets(8, 4, 0, 4); c.gridy = 1; regexpOptionsPanel.add(cbCaseInsensitive, c); c.gridy = 2; regexpOptionsPanel.add(cbUnicodeCase, c); c.gridy = 3; regexpOptionsPanel.add(cbDotall, c); // create tabbed panel c.insets = new Insets(8, 4, 4, 4); c.gridx = 0; c.gridy = 0; c.weightx = 1; c.weighty = 1; c.gridwidth = GridBagConstraints.REMAINDER; c.fill = GridBagConstraints.BOTH; testExp = new JTabbedPane(); testExp.add( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.inline_search.title"), new JScrollPane(inlineSearchPanel)); testExp.add( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.result_list.title"), new JScrollPane(regexpFindingsList)); testExp.add( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.regular_expression.regexp_options.title"), regexpOptionsPanelWrapper); testerPanel.add(testExp, c); JPanel groupPanel = new JPanel(new GridBagLayout()); c.insets = new Insets(4, 4, 4, 4); c.gridx = 0; c.gridy = 0; c.weightx = 1; c.weighty = 0; c.fill = GridBagConstraints.HORIZONTAL; groupPanel.add(regexpPanel, c); c.insets = new Insets(4, 4, 4, 4); c.gridx = 0; c.gridy = 1; c.weightx = 1; c.weighty = 0; c.fill = GridBagConstraints.HORIZONTAL; groupPanel.add(replacementPanel, c); c.insets = new Insets(4, 4, 4, 4); c.gridx = 0; c.gridy = 2; c.weightx = 1; c.weighty = 1; c.fill = GridBagConstraints.BOTH; groupPanel.add(testerPanel, c); panel.add(groupPanel, 1, 0); if (supportsItems) { // item shortcuts list itemShortcutsList = new JList<String>(items.toArray(new String[items.size()])); itemShortcutsList.setToolTipText( I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.item_shortcuts.tip")); itemShortcutsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); itemShortcutsList.addMouseListener( new MouseListener() { @Override public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { String text = regexpTextField.getText(); int cursorPosition = regexpTextField.getCaretPosition(); int index = itemShortcutsList.getSelectedIndex(); if (index > -1 && index < itemShortcutsList.getModel().getSize()) { String insertionString = itemShortcutsList.getModel().getElementAt(index).toString(); String newText = text.substring(0, cursorPosition) + insertionString + (cursorPosition < text.length() ? text.substring(cursorPosition) : ""); regexpTextField.setText(newText); regexpTextField.setCaretPosition(cursorPosition + insertionString.length()); regexpTextField.requestFocus(); fireRegularExpressionUpdated(); } } } @Override public void mouseEntered(MouseEvent e) {} @Override public void mouseExited(MouseEvent e) {} @Override public void mousePressed(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) {} }); JScrollPane itemShortcutsPane = new JScrollPane(itemShortcutsList); itemShortcutsPane.setBorder( createTitledBorder( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.item_shortcuts.border"))); // matched items list matchedItemsListModel = new DefaultListModel<String>(); JList<String> matchedItemsList = new JList<String>(matchedItemsListModel); matchedItemsList.setToolTipText( I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.parameter.regexp.matched_items.tip")); // add custom cell renderer to disallow selections matchedItemsList.setCellRenderer( new DefaultListCellRenderer() { private static final long serialVersionUID = -5795848004756768378L; @Override public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { return super.getListCellRendererComponent(list, value, index, false, false); } }); JScrollPane matchedItemsPanel = new JScrollPane(matchedItemsList); matchedItemsPanel.setBorder( createTitledBorder( I18N.getMessage( I18N.getGUIBundle(), "gui.dialog.parameter.regexp.matched_items.border"))); // item panel on right side of dialog JPanel itemPanel = new JPanel(createGridLayout(1, 2)); itemPanel.add(itemShortcutsPane, 0, 0); itemPanel.add(matchedItemsPanel, 0, 1); panel.add(itemPanel, 0, 1); } okButton = makeOkButton("regexp_property_dialog_apply"); fireRegularExpressionUpdated(); layoutDefault(panel, supportsItems ? NORMAL : NARROW, okButton, makeCancelButton()); }
static { icon = SwingTools.createIcon( "48/" + I18N.getMessage(I18N.getGUIBundle(), "gui.action.welcome.tutorial.icon")); }