Branding Support for TopComponents

In yesterday's blog entry, you saw how a menu item can be created, in this case with the label "Brand", especially for Java classes that extend TopComponent:

And, as you can see here, it's not about the name of the class, i.e., not because the class above is named "BlaTopComponent" because below the "Brand" men item is also available for the class named "Bla":

Both the files BlaTopComponent.java and Bla.java have the "Brand" menu item available, because both extend the "org.openide.windows.TopComponent"  class, as shown yesterday.

Now we continue by creating a new JPanel, with checkboxes for each part of a TopComponent that we consider to be brandable. In my case, this is the end result, at deployment, when the Brand menu item is clicked for the Bla class:


When the user (who, in this case, is a developer) clicks OK, a constructor is created and the related client properties are added, depending on which of the checkboxes are clicked:

public Bla() {
    putClientProperty(TopComponent.PROP_SLIDING_DISABLED, false);
    putClientProperty(TopComponent.PROP_UNDOCKING_DISABLED, true);
    putClientProperty(TopComponent.PROP_MAXIMIZATION_DISABLED, false);
    putClientProperty(TopComponent.PROP_CLOSING_DISABLED, true);
    putClientProperty(TopComponent.PROP_DRAGGING_DISABLED, false);
}

At this point, no check is done to see whether a constructor already exists, nor whether the client properties are already available. That's for an upcoming blog entry! Right now, the constructor is always created, regardless of whether it already exists, and the client properties are always added.

The key to all this is the 'actionPeformed' of the TopComponent, which was left empty yesterday. We start by creating a JDialog from the JPanel and we retrieve the selected state of the checkboxes defined in the JPanel:

@Override
public void actionPerformed(ActionEvent ev) {
    String msg = dobj.getName() + " Branding";
    final BrandTopComponentPanel brandTopComponentPanel = new BrandTopComponentPanel();
    dd = new DialogDescriptor(brandTopComponentPanel, msg, true, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            Object result = dd.getValue();
            if (DialogDescriptor.OK_OPTION == result) {
                isClosing = brandTopComponentPanel.getClosingCheckBox().isSelected();
                isDragging = brandTopComponentPanel.getDraggingCheckBox().isSelected();
                isMaximization = brandTopComponentPanel.getMaximizationCheckBox().isSelected();
                isSliding = brandTopComponentPanel.getSlidingCheckBox().isSelected();
                isUndocking = brandTopComponentPanel.getUndockingCheckBox().isSelected();
                JavaSource javaSource = JavaSource.forFileObject(dobj.getPrimaryFile());
                try {
                    javaSource.runUserActionTask(new ScanTask(javaSource), true);
                } catch (IOException ex) {
                    Exceptions.printStackTrace(ex);
                }
            }
        }
    });
    DialogDisplayer.getDefault().createDialog(dd).setVisible(true);
} 

Then we start a scan process, which introduces the branding. We're already doing a scan process for identifying whether a class is a TopComponent. So, let's combine those two scans, branching out based on which one we're doing:

private class ScanTask implements Task<CompilationController> {

    private BrandTopComponentAction action = null;
    private JavaSource js = null;

    private ScanTask(JavaSource js) {
        this.js = js;
    }

    private ScanTask(BrandTopComponentAction action) {
        this.action = action;
    }

    @Override
    public void run(final CompilationController info) throws Exception {
        info.toPhase(Phase.ELEMENTS_RESOLVED);
        if (action != null) {
            new EnableIfTopComponentScanner(info, action).scan(
                    info.getCompilationUnit(), null);
        } else {
            introduceBranding();
        }
    }

    private void introduceBranding() throws IOException {
        CancellableTask task = new CancellableTask<WorkingCopy>() {
            @Override
            public void run(WorkingCopy workingCopy) throws IOException {
                workingCopy.toPhase(Phase.RESOLVED);
                CompilationUnitTree cut = workingCopy.getCompilationUnit();
                TreeMaker treeMaker = workingCopy.getTreeMaker();
                for (Tree typeDecl : cut.getTypeDecls()) {
                    if (Tree.Kind.CLASS == typeDecl.getKind()) {
                        ClassTree clazz = (ClassTree) typeDecl;
                        ModifiersTree methodModifiers = treeMaker.Modifiers(Collections.<Modifier>singleton(Modifier.PUBLIC));
                        MethodTree newMethod =
                                treeMaker.Method(methodModifiers,
                                "<init>",
                                treeMaker.PrimitiveType(TypeKind.VOID),
                                Collections.<TypeParameterTree>emptyList(),
                                Collections.EMPTY_LIST,
                                Collections.<ExpressionTree>emptyList(),
                                "{ putClientProperty(TopComponent.PROP_SLIDING_DISABLED, " + isSliding + ");\n"+
                                "  putClientProperty(TopComponent.PROP_UNDOCKING_DISABLED, " + isUndocking + ");\n"+
                                "  putClientProperty(TopComponent.PROP_MAXIMIZATION_DISABLED, " + isMaximization + ");\n"+
                                "  putClientProperty(TopComponent.PROP_CLOSING_DISABLED, " + isClosing + ");\n"+
                                "  putClientProperty(TopComponent.PROP_DRAGGING_DISABLED, " + isDragging + "); }\n",
                                null);
                        ClassTree modifiedClazz = treeMaker.addClassMember(clazz, newMethod);
                        workingCopy.rewrite(clazz, modifiedClazz);
                    }
                }
            }
            @Override
            public void cancel() {
            }
        };
        ModificationResult result = js.runModificationTask(task);
        result.commit();
    }
}

private static class EnableIfTopComponentScanner extends TreePathScanner<Void, Void> {

    private CompilationInfo info;
    private final AbstractAction action;

    public EnableIfTopComponentScanner(CompilationInfo info, AbstractAction action) {
        this.info = info;
        this.action = action;
    }

    @Override
    public Void visitClass(ClassTree t, Void v) {
        Element el = info.getTrees().getElement(getCurrentPath());
        if (el != null) {
            TypeElement te = (TypeElement) el;
            if (te.getSuperclass().toString().equals("org.openide.windows.TopComponent")) {
                action.setEnabled(true);
            } else {
                action.setEnabled(false);
            }
        }
        return null;
    }

}
Comments:

Post a Comment:
  • HTML Syntax: NOT allowed
About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
12
13
14
24
25
26
27
28
29
30
   
       
Today