Enhanced ribbon application menu in Flamingo 4.2

Flamingo component suite provides a pure Swing implementation of Office 2007 ribbon component, and the latest 4.2dev drop of the core library has enhanced the support for ribbon application menu to provide default content of the secondary menu panel.

The application menu button is a big round button in the top left corner of the ribbon:

https://flamingo.dev.java.net/release-info/4.2/ribbon-appmenu-notshowing.png

It is not a direct replacement for the usual application menu bar, but rather a place to hold actions that (as a general rule) do not affect the visual content of the document – such as saving, printing, sharing etc. When the application menu button is clicked, it shows a panel with two levels of actions:

  • Primary action
  • Secondary actions for the selected primary action

For example, a primary “Print” action will have a number of secondary actions to print the document as is, print from a dialog with all the options or open the print preview. In order to specify secondary actions, use theĀ RibbonApplicationMenuEntryPrimary.addSecondaryMenuGroup API:

RibbonApplicationMenuEntryPrimary amEntryPrint = new RibbonApplicationMenuEntryPrimary(
      new document_print(), "Print", new ActionListener() {
         @Override
         public void actionPerformed(ActionEvent e) {
            System.out.println("Invoked printing document");
         }
      }, CommandButtonKind.ACTION_AND_POPUP_MAIN_ACTION);
amEntryPrint.setActionKeyTip("P");
amEntryPrint.setPopupKeyTip("W");

RibbonApplicationMenuEntrySecondary amEntryPrintSelect = new RibbonApplicationMenuEntrySecondary(
      new printer(), "Print", null, CommandButtonKind.ACTION_ONLY);
amEntryPrintSelect
      .setDescriptionText("Select a printer, number of copies and other printing options before printing");
amEntryPrintSelect.setActionKeyTip("P");
RibbonApplicationMenuEntrySecondary amEntryPrintDefault = new RibbonApplicationMenuEntrySecondary(
      new document_print(), "Quick Print", null,
      CommandButtonKind.ACTION_ONLY);
amEntryPrintDefault
      .setDescriptionText("Send the document directly to the default printer without making changes");
amEntryPrintDefault.setActionKeyTip("Q");
RibbonApplicationMenuEntrySecondary amEntryPrintPreview = new RibbonApplicationMenuEntrySecondary(
      new document_print_preview(), "Print Preview", null,
      CommandButtonKind.ACTION_ONLY);
amEntryPrintPreview
      .setDescriptionText("Preview and make changes to the pages before printing");
amEntryPrintPreview.setActionKeyTip("V");

amEntryPrint.addSecondaryMenuGroup("Preview and print the document",
      amEntryPrintSelect, amEntryPrintDefault, amEntryPrintPreview);

At runtime when the user moves the mouse over the “Print” entry in the left panel, the matching secondary entries are shown on the right:

https://flamingo.dev.java.net/release-info/4.2/ribbon-appmenu-rollovermenu.png

While most of the primary entries have a predefined (static) list of secondary entries, some require dynamic content. For example, the “Open” entry shows the list of recently open documents. In order to associate dynamic secondary content, use the RibbonApplicationMenuEntryPrimary.setRolloverCallback API:

RibbonApplicationMenuEntryPrimary amEntryOpen = new RibbonApplicationMenuEntryPrimary(
      new document_open(), "Open", new ActionListener() {
         @Override
         public void actionPerformed(ActionEvent e) {
            System.out.println("Invoked opening document");
         }
      }, CommandButtonKind.ACTION_ONLY);
amEntryOpen
      .setRolloverCallback(new RibbonApplicationMenuEntryPrimary.PrimaryRolloverCallback() {
         @Override
         public void menuEntryActivated(JPanel targetPanel) {
            targetPanel.removeAll();
            JCommandButtonPanel openHistoryPanel = new JCommandButtonPanel(
                  CommandButtonDisplayState.MEDIUM);
            String groupName = "Recent Documents";
            openHistoryPanel.addButtonGroup(groupName);
            for (int i = 0; i < 5; i++) {
               JCommandButton historyButton = new JCommandButton(i
                     + "    " + "document" + i + ".html",
                     new text_html());
               historyButton
                     .setHorizontalAlignment(SwingUtilities.LEFT);
               openHistoryPanel
                     .addButtonToLastGroup(historyButton);
            }
            openHistoryPanel.setMaxButtonColumns(1);
            targetPanel.setLayout(new BorderLayout());
            targetPanel.add(openHistoryPanel, BorderLayout.CENTER);
         }
      });
amEntryOpen.setActionKeyTip("O");

Here, the application code is responsible for clearing and populating the contents of the secondary panel. At runtime when the user moves the mouse over the “Open” entry in the left panel, the application callback is invoked to populate the secondary panel:

https://flamingo.dev.java.net/release-info/4.2/ribbon-appmenu-rollovercontent.png

The latest 4.2dev drop of Flamingo core library also allows the application code to specify the default content of the secondary panel. This is done with the new RibbonApplicationMenu.setDefaultCallback API. When set, it will be called when the ribbon application menu is shown, and when the currently active (under mouse) primary entry has neither secondary entries, nor rollover callback. In Office 2007 the default content of the secondary panel is the list of recently opened documents, but this API allows you to provide a custom implementation if necessary:

applicationMenu
      .setDefaultCallback(new RibbonApplicationMenuEntryPrimary.PrimaryRolloverCallback() {
         @Override
         public void menuEntryActivated(JPanel targetPanel) {
            targetPanel.removeAll();
            JCommandButtonPanel openHistoryPanel = new JCommandButtonPanel(
                  CommandButtonDisplayState.MEDIUM);
            String groupName = "Default Documents";
            openHistoryPanel.addButtonGroup(groupName);
            for (int i = 0; i < 5; i++) {
               JCommandButton historyButton = new JCommandButton(i
                     + "    " + "default" + i + ".html",
                     new text_html());
               historyButton
                     .setHorizontalAlignment(SwingUtilities.LEFT);
               openHistoryPanel
                     .addButtonToLastGroup(historyButton);
            }
            openHistoryPanel.setMaxButtonColumns(1);
            targetPanel.setLayout(new BorderLayout());
            targetPanel.add(openHistoryPanel, BorderLayout.CENTER);
         }
      });

When the default callback is invoked at runtime (under one of the two scenarios mentioned above), it populates the secondary panel:

https://flamingo.dev.java.net/release-info/4.2/ribbon-appmenu-defaultcontent.png

If you want to see the enhanced application menu button in action, run the following WebStart demo:

The demo above works for the core look-and-feels. If you want to see this functionality under Substance, run the following WebStart demo:

If you want to test the new functionality in your applications, you would need the following (the last two only for applications running under Substance look-and-feel):


Related posts:

  1. Flamingo ribbon component: application menu button and taskbar I’ve been relatively quiet on this blog for the last couple of weeks, but i...
  2. Flamingo ribbon component: enhancing the application menu button and popups Following the extremely valuable feedback on the previous entry that introduced the application menu button...
  3. Flamingo ribbon component: small buttons in ribbon galleries As mentioned in the JavaOne presentation on the Flamingo ribbon component, there are a few...
  4. Flamingo ribbon component: minimizing the ribbon The latest addition in the Flamingo component suite is support for minimizing the ribbon. This...


5 Responses to “Enhanced ribbon application menu in Flamingo 4.2”

  • gervais.b Says:

    Hello Kirill,

    I’m reading your posts since a long time, and since some weeks I have the opportunity to use and derive your components..
    I like your job but something make me trouble : Why are you using “CallBack” instead of models for many of your components ?
    Before having to reuse your components I have writed two customs components from scratch and obviously I have read a little doc and It seems that a “good” (for a Sun point of view [1]) component will have a Model, a Component and one or many UiDelegate but I think that you prefer “CallbBack”s instead of “old” models.

    Thanks for your great work and your knowledges sharing

    [1] http://today.java.net/pub/a/today/2007/02/22/how-to-write-custom-swing-component.html

  • Kirill Grouchnikov Says:

    Gervais,

    Not sure that i follow your reasoning. RibbonApplicationMenu and RibbonApplicationMenuEntryPrimary are models – they don’t even extend the Component / JComponent. The components themselves have static behavior and dynamic behavior. The callbacks are used to provide the dynamic model behavior – and the UI delegates are calling the matching model APIs to populate the content dynamically at runtime.

    What is your approach to allowing the applications to populate the list of recently open files when the application menu is showing?

    Thanks
    Kirill (incidentally, i wrote that article and i don’t work for Sun)

  • Java desktop links of the week, October 26 | Jonathan Giles Says:

    [...] Grouchnikov clearly had Flamingo on his mind this week, with two blog posts discussing how he has enhanced the ribbon application menu in Flamingo 4.2, and improvements to the command buttons in Flamingo to support buttons with no text and/or [...]

  • gervais.b Says:

    Kirill,

    I’m sorry, I feel you a little angry but my questions isn’t a accusation or any other bad things. It’s just a question from a rookie to a more experienced (and respected) developper.

    I have only used your BreadCrumbBar (v 2.0) and constated that there was no “xxxModel” classes but only “CallBack”s.

    I have another approach to populate the list, but she isn’t so “sexy” a lighter than your “CallBacks”.

    A second time, I want to present all my respect and please don’t considers my questions as an accusatiuon about your work.

  • Kirill Grouchnikov Says:

    Gervais,

    That’s one of the problems with written communication – i was just asking you to clarify your question in order to better understand your reservations about the callbacks.

    Breadcrumb bar component is not all my doing – it was contributed a few years ago by a third party. While i have refactored some of the API and most of the UI delegates, some of the APIs remained the same. It’s a very dynamic component, and as such is driven entirely by application callbacks. It may indeed be refactored to fit the MVC paradigm a little better, but i’m afraid it will be some time before i get to it.

    You’re more than welcome to share your thoughts / code on the project “users” mailing list to see if the next major release is a good fit for the API facelift.

    Thanks
    Kirill