001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.gui.menu; 020 021import icy.action.GeneralActions; 022import icy.action.PreferencesActions; 023import icy.action.WindowActions; 024import icy.gui.component.button.IcyCommandButton; 025import icy.gui.component.button.IcyCommandMenuButton; 026import icy.gui.component.button.IcyCommandToggleButton; 027import icy.gui.component.button.IcyCommandToggleMenuButton; 028import icy.gui.frame.IcyFrame; 029import icy.gui.frame.progress.TaskFrame; 030import icy.gui.main.ActiveSequenceListener; 031import icy.gui.main.MainFrame; 032import icy.gui.menu.search.SearchBar; 033import icy.gui.plugin.PluginCommandButton; 034import icy.gui.util.LookAndFeelUtil; 035import icy.gui.util.RibbonUtil; 036import icy.gui.viewer.Viewer; 037import icy.imagej.ImageJWrapper; 038import icy.main.Icy; 039import icy.plugin.PluginDescriptor; 040import icy.plugin.PluginDescriptor.PluginClassNameSorter; 041import icy.plugin.PluginLoader; 042import icy.plugin.PluginLoader.PluginLoaderEvent; 043import icy.plugin.PluginLoader.PluginLoaderListener; 044import icy.preferences.GeneralPreferences; 045import icy.preferences.WorkspaceLocalPreferences; 046import icy.resource.ResourceUtil; 047import icy.resource.icon.IcyIcon; 048import icy.sequence.Sequence; 049import icy.sequence.SequenceEvent; 050import icy.sequence.SequenceEvent.SequenceEventSourceType; 051import icy.system.thread.ThreadUtil; 052import icy.workspace.Workspace; 053import icy.workspace.Workspace.TaskDefinition; 054import icy.workspace.Workspace.TaskDefinition.BandDefinition; 055import icy.workspace.Workspace.TaskDefinition.BandDefinition.ItemDefinition; 056import icy.workspace.WorkspaceInstaller; 057import icy.workspace.WorkspaceLoader; 058 059import java.awt.Component; 060import java.awt.event.ActionEvent; 061import java.awt.event.ActionListener; 062import java.beans.PropertyChangeEvent; 063import java.beans.PropertyChangeListener; 064import java.util.ArrayList; 065import java.util.Collections; 066import java.util.List; 067 068import javax.swing.JMenu; 069import javax.swing.JMenuItem; 070import javax.swing.JPopupMenu; 071import javax.swing.JSeparator; 072import javax.swing.SwingConstants; 073 074import org.pushingpixels.flamingo.api.common.AbstractCommandButton; 075import org.pushingpixels.flamingo.api.common.CommandToggleButtonGroup; 076import org.pushingpixels.flamingo.api.common.JCommandButton; 077import org.pushingpixels.flamingo.api.common.JCommandButton.CommandButtonKind; 078import org.pushingpixels.flamingo.api.common.RichTooltip; 079import org.pushingpixels.flamingo.api.common.popup.JCommandPopupMenu; 080import org.pushingpixels.flamingo.api.common.popup.JPopupPanel; 081import org.pushingpixels.flamingo.api.common.popup.PopupPanelCallback; 082import org.pushingpixels.flamingo.api.ribbon.JRibbon; 083import org.pushingpixels.flamingo.api.ribbon.JRibbonBand; 084import org.pushingpixels.flamingo.api.ribbon.RibbonElementPriority; 085import org.pushingpixels.flamingo.api.ribbon.RibbonTask; 086import org.pushingpixels.flamingo.api.ribbon.resize.CoreRibbonResizeSequencingPolicies; 087 088/** 089 * This class is used to separate ribbon construction from the ribbon frame 090 * 091 * @author Stephane 092 */ 093public class MainRibbon implements PluginLoaderListener, ActiveSequenceListener 094{ 095 /** 096 * TASK / BAND NAMES 097 */ 098 public static final String TASK_PLUGINS = "Plugins"; 099 public static final String BAND_SETUP = "Setup"; 100 public static final String BAND_NEW = "New"; 101 public static final String BAND_OTHERS = "Others"; 102 103 /** 104 * loaded workspaces 105 */ 106 private final ArrayList<Workspace> workspaces; 107 private Workspace systemWorkspace; 108 109 /** 110 * Search bar object 111 */ 112 SearchBar searchBar; 113 114 /** 115 * internals 116 */ 117 BandDefinition setupPluginsBandDef; 118 BandDefinition newPluginsBandDef; 119 BandDefinition othersPluginsBandDef; 120 121 private final JRibbon ribbon; 122 private final ApplicationMenu applicationMenu; 123 private final SequenceOperationTask sequenceOperationTask; 124 // use ToolRibbonTask constructor to preserve backward compatibility 125 private final ToolRibbonTask roiTask; 126 private final ImageJTask ijTask; 127 private final JRibbonBand setupPluginsBand; 128 private final JRibbonBand newPluginsBand; 129 final JMenu othersPluginsMenu; 130 131 CommandToggleButtonGroup multiWindowGroup; 132 IcyCommandToggleButton multiWindowButton; 133 134 /** 135 * @param ribbon 136 */ 137 public MainRibbon(JRibbon ribbon) 138 { 139 super(); 140 141 this.ribbon = ribbon; 142 143 workspaces = new ArrayList<Workspace>(); 144 othersPluginsMenu = new JMenu("Plugins"); 145 146 // APPLICATION MENU & MISC 147 148 applicationMenu = new ApplicationMenu(); 149 ribbon.setApplicationMenu(applicationMenu); 150 final RichTooltip toolTip = new RichTooltip("ICY Application menu", 151 "Load, close and save Sequence from there."); 152 ribbon.setApplicationMenuRichTooltip(toolTip); 153 // ribbon.configureHelp(new ICYResizableIcon(new IcyIcon("lightbulb"), 154 // new 155 // Help("Main_Page")); 156 157 // TASKBAR 158 159 buidlTaskBar(); 160 161 // FIXED TASKS 162 163 // load image task first as tools task need all plugins loaded... 164 sequenceOperationTask = new SequenceOperationTask(); 165 // use ToolRibbonTask constructor to preserve backward compatibility 166 roiTask = new ToolRibbonTask(); 167 ijTask = new ImageJTask(); 168 ribbon.addTask(sequenceOperationTask); 169 ribbon.addTask(roiTask); 170 ribbon.addTask(ijTask); 171 172 // WORKSPACES 173 174 // load workspace from files 175 loadWorkspaces(); 176 177 // store system band definition 178 setupPluginsBandDef = systemWorkspace.findBand(TASK_PLUGINS, BAND_SETUP); 179 newPluginsBandDef = systemWorkspace.findBand(TASK_PLUGINS, BAND_NEW); 180 othersPluginsBandDef = systemWorkspace.findBand(TASK_PLUGINS, BAND_OTHERS); 181 182 // build workspaces menu 183 buildWorkspaces(); 184 185 // store system band 186 final RibbonTask pluginTask = RibbonUtil.getTask(ribbon, TASK_PLUGINS); 187 setupPluginsBand = RibbonUtil.getBand(pluginTask, BAND_SETUP); 188 newPluginsBand = RibbonUtil.getBand(pluginTask, BAND_NEW); 189 // othersPluginsBand = RibbonUtil.getBand(pluginTask, BAND_OTHERS); 190 191 // build plugin setup band 192 buildSetupPluginBand(); 193 194 // save workspaces back so removed stuff are cleaned 195 // saveWorkspaces(); 196 197 PluginLoader.addListener(this); 198 Icy.getMainInterface().addActiveSequenceListener(this); 199 } 200 201 // some stuff which need to be initialized after ribbon creation 202 public void init() 203 { 204 ijTask.init(); 205 206 final MainFrame mainFrame = Icy.getMainInterface().getMainFrame(); 207 mainFrame.addPropertyChangeListener(MainFrame.PROPERTY_DETACHEDMODE, new PropertyChangeListener() 208 { 209 @Override 210 public void propertyChange(PropertyChangeEvent evt) 211 { 212 multiWindowGroup.setSelected(multiWindowButton, Icy.getMainInterface().isDetachedMode()); 213 } 214 }); 215 } 216 217 public ROITask getROIRibbonTask() 218 { 219 return roiTask; 220 } 221 222 /** 223 * @deprecated Use {@link #getROIRibbonTask()} instead 224 */ 225 @Deprecated 226 public ToolRibbonTask getToolRibbon() 227 { 228 return roiTask; 229 } 230 231 public SequenceOperationTask getSequenceOperationTask() 232 { 233 return sequenceOperationTask; 234 } 235 236 public ImageJTask getImageJTask() 237 { 238 return ijTask; 239 } 240 241 public ImageJWrapper getImageJ() 242 { 243 return ijTask.getImageJ(); 244 } 245 246 public SearchBar getSearchBar() 247 { 248 return searchBar; 249 } 250 251 private void loadWorkspaces() 252 { 253 ArrayList<String> workspacesName; 254 255 // load names from preference 256 workspacesName = WorkspaceLocalPreferences.getActivesWorkspace(); 257 258 // wait for workspace loader is ready 259 WorkspaceLoader.waitWhileLoading(); 260 261 // load workspaces 262 workspaces.clear(); 263 for (String name : workspacesName) 264 { 265 // get workspace from loader 266 final Workspace ws = WorkspaceLoader.getWorkspace(name); 267 268 // add to active workspace list if not empty 269 if (ws == null) 270 System.err.println("Workspace " + name + " not found !"); 271 else if (isInConflict(ws, true)) 272 System.err.println("Workspace '" + name + "' is discarded (conflict detected)"); 273 else 274 workspaces.add(ws); 275 } 276 277 // clean up invalid entries 278 workspacesName.clear(); 279 for (Workspace ws : workspaces) 280 workspacesName.add(ws.getName()); 281 282 // save back cleaned names to preference 283 WorkspaceLocalPreferences.setActivesWorkspace(workspacesName); 284 285 // always add the system workspace 286 systemWorkspace = new Workspace(Workspace.WORKSPACE_SYSTEM_NAME); 287 288 // recreate system workspace manually if needed 289 systemWorkspace.setDescription("System workspace"); 290 // this actually add only missing tasks and bands 291 systemWorkspace.addBand(MainRibbon.TASK_PLUGINS, MainRibbon.BAND_SETUP); 292 systemWorkspace.addBand(MainRibbon.TASK_PLUGINS, MainRibbon.BAND_NEW); 293 systemWorkspace.addBand(MainRibbon.TASK_PLUGINS, MainRibbon.BAND_OTHERS); 294 295 workspaces.add(systemWorkspace); 296 } 297 298 /** 299 * return true if specified workspace is in conflict with current actives workspace 300 */ 301 private boolean isInConflict(Workspace ws, boolean showAsError) 302 { 303 for (TaskDefinition task : ws.getTasks()) 304 { 305 for (BandDefinition band : task.getBands()) 306 { 307 // conflict : same task and same band in 2 different workspaces 308 if (findBand(task.getName(), band.getName()) != null) 309 { 310 if (showAsError) 311 System.err.println("Duplicated band : " + task.getName() + "/" + band.getName()); 312 313 return true; 314 } 315 } 316 } 317 318 return false; 319 } 320 321 /** 322 * get all tasks from actives workspace 323 */ 324 private List<TaskDefinition> getTasks() 325 { 326 final List<TaskDefinition> result = new ArrayList<TaskDefinition>(); 327 328 for (Workspace ws : workspaces) 329 for (TaskDefinition task : ws.getTasks()) 330 if (!Workspace.contains(result, task)) 331 result.add(task); 332 333 return result; 334 } 335 336 /** 337 * get all bands for a task from actives workspace 338 */ 339 private List<BandDefinition> getBands(String taskName) 340 { 341 final List<BandDefinition> result = new ArrayList<BandDefinition>(); 342 343 for (Workspace ws : workspaces) 344 for (TaskDefinition task : ws.getTasks()) 345 if (task.getName().equals(taskName)) 346 for (BandDefinition band : task.getBands()) 347 if (!Workspace.contains(result, band)) 348 result.add(band); 349 350 return result; 351 } 352 353 // private Workspace findWorkspace(String workspaceName) 354 // { 355 // for (Workspace ws : workspaces) 356 // if (ws.getName().equals(workspaceName)) 357 // return ws; 358 // 359 // return null; 360 // } 361 362 private BandDefinition findBand(String taskName, String bandName) 363 { 364 for (Workspace ws : workspaces) 365 { 366 final TaskDefinition task = ws.findTask(taskName); 367 if (task != null) 368 { 369 final BandDefinition band = task.findBand(bandName); 370 if (band != null) 371 return band; 372 } 373 } 374 375 return null; 376 } 377 378 /** 379 * Get all items from all active workspace 380 */ 381 private ArrayList<ItemDefinition> getAllItems() 382 { 383 final ArrayList<ItemDefinition> result = new ArrayList<ItemDefinition>(); 384 385 // get all items from active workspaces 386 for (Workspace workspace : workspaces) 387 result.addAll(workspace.getAllItems()); 388 389 return result; 390 } 391 392 ItemDefinition findItem(String className) 393 { 394 // search item in active workspaces 395 for (Workspace workspace : workspaces) 396 { 397 final ItemDefinition item = workspace.findItem(className); 398 if (item != null) 399 return item; 400 } 401 402 return null; 403 } 404 405 void addItem(String className) 406 { 407 addItem(PluginLoader.getPlugin(className)); 408 } 409 410 /** 411 * Add an item for the specified plugin. 412 */ 413 void addItem(PluginDescriptor plugin) 414 { 415 // check that plugin can be displayed in menu 416 if ((plugin != null) && plugin.isActionable()) 417 { 418 final IcyCommandButton pluginButton = PluginCommandButton.createButton(plugin); 419 420 // add it to the new installed plugins workspace and save it 421 newPluginsBandDef.addItem(plugin.getClassName(), RibbonElementPriority.TOP); 422 systemWorkspace.save(); 423 // add it to the new installed plugins band 424 newPluginsBand.addCommandButton(pluginButton, RibbonElementPriority.TOP); 425 } 426 } 427 428 void updateItem(String className) 429 { 430 updateItem(PluginLoader.getPlugin(className), findItem(className)); 431 } 432 433 void updateItem(PluginDescriptor plugin, ItemDefinition item) 434 { 435 // check that plugin can be displayed in menu 436 if ((plugin != null) && plugin.isActionable()) 437 { 438 if (item != null) 439 { 440 // find the corresponding button 441 final AbstractCommandButton button = RibbonUtil.findButton( 442 RibbonUtil.getBand(RibbonUtil.getTask(ribbon, item.getTaskName()), item.getBandName()), 443 item.getClassName()); 444 445 // button found --> update it 446 if (button != null) 447 PluginCommandButton.setButton(button, plugin); 448 } 449 else 450 { 451 final Workspace workspace = WorkspaceInstaller.getCurrentInstallingWorkspace(); 452 453 // check plugin wasn't installed from a workspace 454 if ((workspace == null) || (workspace.findItem(plugin.getClassName()) == null)) 455 // add a new item for this plugin 456 addItem(plugin); 457 } 458 } 459 } 460 461 void removeItem(String className) 462 { 463 removeItem(findItem(className)); 464 } 465 466 void removeItem(ItemDefinition item) 467 { 468 if (item != null) 469 { 470 // FIXME : unsafe (ribbon component is not supposed to support that) 471 RibbonUtil.removeButton( 472 RibbonUtil.getBand(RibbonUtil.getTask(ribbon, item.getTaskName()), item.getBandName()), 473 item.getClassName()); 474 // remove item and save workspace 475 item.remove(); 476 // save system workspace only, we want to preserve plugins organization 477 systemWorkspace.save(); 478 } 479 } 480 481 private void buildSetupPluginBand() 482 { 483 setupPluginsBand.addCommandButton(new IcyCommandButton(PreferencesActions.onlinePluginPreferencesAction), 484 RibbonElementPriority.TOP); 485 486 RibbonUtil.setFixedResizePolicies(setupPluginsBand); 487 } 488 489 // /** 490 // * Add a new installed plugin 491 // */ 492 // public void addNewPlugin(String className) 493 // { 494 // // get the corresponding plugin 495 // final PluginDescriptor plugin = PluginLoader.getPlugin(className); 496 // 497 // // check that menu can be displayed in menu 498 // if ((plugin == null) || !plugin.isActionable()) 499 // return; 500 // 501 // final IcyCommandButton pluginButton = buildPluginCommandButton(plugin); 502 // 503 // // add it to the new installed plugins workspace and save it 504 // newPluginsBandDef.addItem(plugin.getClassName(), RibbonElementPriority.TOP); 505 // systemWorkspace.save(); 506 // // add it to the new installed plugins band 507 // newPluginsBand.addCommandButton(pluginButton, RibbonElementPriority.TOP); 508 // } 509 510 private JRibbonBand[] createRibbonBands(TaskDefinition task) 511 { 512 final List<BandDefinition> bands = getBands(task.getName()); 513 final int size = bands.size(); 514 final JRibbonBand[] result = new JRibbonBand[size]; 515 516 for (int i = 0; i < size; i++) 517 { 518 final BandDefinition band = bands.get(i); 519 // TODO : get icon from BandDefinition 520 result[i] = new JRibbonBand(band.getName(), new IcyIcon(ResourceUtil.ICON_DOC)); 521 // use restrictive resize policy by default 522 RibbonUtil.setRestrictiveResizePolicies(result[i]); 523 } 524 525 return result; 526 } 527 528 private RibbonTask createRibbonTask(TaskDefinition task) 529 { 530 final String name = task.getName(); 531 532 final RibbonTask ribbonTask = RibbonUtil.getTask(ribbon, name); 533 if (ribbonTask != null) 534 { 535 System.out.println("Ribbon task " + name + " already exists..."); 536 return ribbonTask; 537 } 538 539 final RibbonTask result; 540 541 try 542 { 543 result = new RibbonTask(name, createRibbonBands(task)); 544 } 545 catch (IllegalArgumentException e) 546 { 547 return null; 548 } 549 550 // use roundRobin collapse policy 551 result.setResizeSequencingPolicy(new CoreRibbonResizeSequencingPolicies.RoundRobin(result)); 552 553 return result; 554 } 555 556 /** 557 * build ribbon from workspaces 558 */ 559 private void buildWorkspaces() 560 { 561 final ArrayList<PluginDescriptor> plugins = PluginLoader.getPlugins(false); 562 563 // get all TaskDefinition from all active workspace 564 for (TaskDefinition task : getTasks()) 565 { 566 // create the task with all needed bands 567 final RibbonTask ribbonTask = createRibbonTask(task); 568 569 // empty task --> ignore 570 if (ribbonTask == null) 571 continue; 572 573 for (BandDefinition band : getBands(task.getName())) 574 { 575 final JRibbonBand ribbonBand = RibbonUtil.getBand(ribbonTask, band.getName()); 576 577 if (ribbonBand != null) 578 { 579 // special case of OTHER plugins 580 if (band == othersPluginsBandDef) 581 { 582 final IcyCommandButton btn = new IcyCommandButton("Other Plugins", 583 new IcyIcon(ResourceUtil.ICON_COG)); 584 btn.setCommandButtonKind(CommandButtonKind.POPUP_ONLY); 585 btn.setPopupRichTooltip(new RichTooltip("Other plugins", 586 "You can find here all plugins which are not associated to a workspace")); 587 btn.setPopupCallback(new PopupPanelCallback() 588 { 589 @Override 590 public JPopupPanel getPopupPanel(JCommandButton commandButton) 591 { 592 final JPopupMenu popupMenu = othersPluginsMenu.getPopupMenu(); 593 594 // FIXME : set as heavy weight component for VTK (doesn't work) 595 // popupMenu.setLightWeightPopupEnabled(false); 596 popupMenu.show(btn, 0, btn.getHeight()); 597 598 return null; 599 } 600 }); 601 ribbonBand.addCommandButton(btn, RibbonElementPriority.TOP); 602 603 // refresh unassigned list 604 refreshOthersPluginsList(); 605 606 // adjust restrictive resize policy 607 RibbonUtil.setFixedResizePolicies(ribbonBand); 608 } 609 else 610 { 611 for (ItemDefinition item : band.getItems()) 612 { 613 // simple separator 614 if (item.isSeparator()) 615 ribbonBand.startGroup(); 616 else 617 { 618 final String className = item.getClassName(); 619 final PluginDescriptor plugin = PluginDescriptor.getPlugin(plugins, className); 620 621 // plugin found ? 622 if (plugin != null) 623 { 624 // check that menu can be displayed in menu 625 if (plugin.isActionable()) 626 ribbonBand.addCommandButton(PluginCommandButton.createButton(plugin), 627 item.getPriority()); 628 } 629 } 630 } 631 632 // adjust restrictive resize policy 633 RibbonUtil.setRestrictiveResizePolicies(ribbonBand); 634 } 635 } 636 } 637 638 // add task to ribbon only if not empty 639 if (ribbonTask.getBandCount() > 0) 640 ribbon.addTask(ribbonTask); 641 } 642 } 643 644 /** 645 * clean workspace (remove absent plug-in) 646 */ 647 public void cleanWorkspaces() 648 { 649 final ArrayList<PluginDescriptor> plugins = PluginLoader.getPlugins(false); 650 651 // get all items TaskDefinition from all active workspace 652 for (ItemDefinition item : getAllItems()) 653 { 654 // avoid separator 655 if (!item.isSeparator()) 656 { 657 final String className = item.getClassName(); 658 final PluginDescriptor plugin = PluginDescriptor.getPlugin(plugins, className); 659 660 // plugin not found --> remove from workspace 661 if (plugin == null) 662 item.remove(); 663 } 664 } 665 666 // save cleaned workspaces 667 saveWorkspaces(); 668 } 669 670 void refreshOthersPluginsList() 671 { 672 // build others plugin list 673 final ArrayList<PluginDescriptor> othersPlugins = new ArrayList<PluginDescriptor>(); 674 675 // scan all actionable plugins to find unassigned ones 676 for (PluginDescriptor plugin : PluginLoader.getActionablePlugins()) 677 { 678 final String className = plugin.getClassName(); 679 // search item in actives workspace 680 final ItemDefinition item = findItem(className); 681 682 // plugin not defined in active workspaces --> add it to the list 683 if ((item == null) || (item.getBandDefinition() == othersPluginsBandDef)) 684 othersPlugins.add(plugin); 685 } 686 687 // refresh unassigned plugins menu 688 builOthersPluginsMenu(othersPlugins); 689 690 // rebuild the unassigned workspace 691 othersPluginsBandDef.clear(); 692 for (PluginDescriptor plugin : othersPlugins) 693 othersPluginsBandDef.addItem(plugin.getClassName()); 694 695 // save the system workspace 696 systemWorkspace.save(); 697 } 698 699 private void builOthersPluginsMenu(ArrayList<PluginDescriptor> plugins) 700 { 701 othersPluginsMenu.removeAll(); 702 703 for (PluginDescriptor pluginDescriptor : plugins) 704 { 705 String pluginEntry = pluginDescriptor.getSimplePackageName(); 706 JMenu menuToPutPlugin = othersPluginsMenu; 707 708 while (pluginEntry != null) 709 { 710 final int index = pluginEntry.indexOf("."); 711 final String pluginDir; 712 713 if (index != -1) 714 { 715 pluginDir = pluginEntry.substring(0, index); 716 pluginEntry = pluginEntry.substring(index + 1); 717 } 718 else 719 { 720 pluginDir = pluginEntry; 721 pluginEntry = null; 722 } 723 724 // look if name is already a menu. 725 boolean menuExist = false; 726 for (Component component : menuToPutPlugin.getMenuComponents()) 727 { 728 if (component instanceof JMenu) 729 { 730 final JMenu menu = (JMenu) component; 731 732 if (menu.getText().equals(pluginDir)) 733 { 734 menuToPutPlugin = menu; 735 menuExist = true; 736 break; 737 } 738 } 739 } 740 741 if (menuExist == false) 742 { 743 // create Menu 744 final JMenu menu = new JMenu(pluginDir); 745 menuToPutPlugin.add(menu); 746 menuToPutPlugin = menu; 747 } 748 } 749 750 menuToPutPlugin.add(new PluginMenuItem(pluginDescriptor)); 751 } 752 753 if (plugins.isEmpty()) 754 othersPluginsMenu.add(new JMenuItem("No plugins")); 755 756 othersPluginsMenu.validate(); 757 } 758 759 /** 760 * save workspaces from menu 761 */ 762 void saveWorkspaces() 763 { 764 // save all active workspaces 765 for (Workspace workspace : workspaces) 766 workspace.save(); 767 } 768 769 /** 770 * build task bar (little bar with small icons over all at top) 771 */ 772 private void buidlTaskBar() 773 { 774 // PREFERENCES 775 ribbon.addTaskbarComponent(new IcyCommandButton(PreferencesActions.preferencesAction)); 776 777 // PLUGINS 778 ribbon.addTaskbarComponent(new IcyCommandButton(PreferencesActions.onlinePluginPreferencesAction)); 779 780 // SEPARATOR 781 ribbon.addTaskbarComponent(new JSeparator(SwingConstants.VERTICAL)); 782 783 // MULTI FRAME MODE 784 multiWindowGroup = new CommandToggleButtonGroup(); 785 multiWindowButton = new IcyCommandToggleButton(GeneralActions.detachedModeAction); 786 ribbon.addTaskbarComponent(multiWindowButton); 787 788 multiWindowGroup.add(multiWindowButton); 789 multiWindowGroup.setSelected(multiWindowButton, GeneralPreferences.getMultiWindowMode()); 790 791 // WINDOWS 792 final IcyCommandButton windowsButton = new IcyCommandButton(new IcyIcon("app_window")); 793 794 windowsButton.setPopupRichTooltip( 795 new RichTooltip("Windows", "Show specific windows and general windows setting...")); 796 windowsButton.setCommandButtonKind(CommandButtonKind.POPUP_ONLY); 797 windowsButton.setPopupCallback(new PopupPanelCallback() 798 { 799 @Override 800 public JPopupPanel getPopupPanel(JCommandButton commandButton) 801 { 802 final JCommandPopupMenu result = new JCommandPopupMenu(); 803 804 // ALWAYS ON TOP 805 final CommandToggleButtonGroup aotGroup = new CommandToggleButtonGroup(); 806 final IcyCommandToggleMenuButton aotButton = new IcyCommandToggleMenuButton( 807 WindowActions.stayOnTopAction); 808 result.addMenuButton(aotButton); 809 810 aotGroup.add(aotButton); 811 aotGroup.setSelected(aotButton, GeneralPreferences.getAlwaysOnTop()); 812 813 // SEPARATOR 814 result.addMenuSeparator(); 815 816 // LOOK AND FEEL 817 final IcyCommandMenuButton lafButton = new IcyCommandMenuButton("Appearance", 818 new IcyIcon(ResourceUtil.ICON_SMILEY_HAPPY)); 819 820 lafButton.setCommandButtonKind(CommandButtonKind.POPUP_ONLY); 821 lafButton.setPopupRichTooltip(new RichTooltip("Look and feel", "Change appearance of the interface")); 822 lafButton.setPopupCallback(new PopupPanelCallback() 823 { 824 @Override 825 public JPopupPanel getPopupPanel(JCommandButton commandButton) 826 { 827 // better to build it on request as it takes a bit of time 828 // and we want to speed up the initial loading 829 return LookAndFeelUtil.getLookAndFeelMenu(); 830 } 831 }); 832 result.addMenuButton(lafButton); 833 834 // SEPARATOR 835 result.addMenuSeparator(); 836 837 // SWIMMING POOL 838 final IcyCommandMenuButton spButton = new IcyCommandMenuButton(WindowActions.swimmingPoolAction); 839 result.addMenuButton(spButton); 840 841 // SCRIPT EDITOR 842 // TODO : reactivate when done 843 // final IcyCommandMenuButton seButton = new IcyCommandMenuButton("Script Editor", 844 // new 845 // ICYResizableIcon(new IcyIcon( 846 // "lighting")); 847 // seButton.addActionListener(new ActionListener() 848 // { 849 // @Override 850 // public void actionPerformed(ActionEvent e) 851 // { 852 // new ScriptEditor(); 853 // } 854 // }); 855 // result.addMenuButton(seButton); 856 857 // SEPARATOR 858 result.addMenuSeparator(); 859 860 // REORGANIZE TILE 861 final IcyCommandMenuButton tileButton = new IcyCommandMenuButton("Tile", new IcyIcon("2x2_grid")); 862 tileButton.setCommandButtonKind(CommandButtonKind.POPUP_ONLY); 863 tileButton.setPopupCallback(new PopupPanelCallback() 864 { 865 @Override 866 public JPopupPanel getPopupPanel(JCommandButton commandButton) 867 { 868 final JCommandPopupMenu result = new JCommandPopupMenu(); 869 870 // grid 871 result.addMenuButton(new IcyCommandMenuButton(WindowActions.gridTileAction)); 872 // horizontal 873 result.addMenuButton(new IcyCommandMenuButton(WindowActions.horizontalTileAction)); 874 // vertical 875 result.addMenuButton(new IcyCommandMenuButton(WindowActions.verticalTileAction)); 876 877 return result; 878 } 879 }); 880 result.addMenuButton(tileButton); 881 882 // REORGANIZE CASCADE 883 result.addMenuButton(new IcyCommandMenuButton(WindowActions.cascadeAction)); 884 885 // SEPARATOR 886 result.addMenuSeparator(); 887 888 // OPENED SEQUENCES 889 final ArrayList<Viewer> allViewers = Icy.getMainInterface().getViewers(); 890 final IcyCommandMenuButton sequencesButton = new IcyCommandMenuButton("Opened sequences", 891 new IcyIcon(ResourceUtil.ICON_PICTURE)); 892 sequencesButton.setPopupRichTooltip(new RichTooltip("Opened sequences", "Show the selected sequence")); 893 sequencesButton.setCommandButtonKind(CommandButtonKind.POPUP_ONLY); 894 sequencesButton.setPopupCallback(new PopupPanelCallback() 895 { 896 @Override 897 public JPopupPanel getPopupPanel(JCommandButton commandButton) 898 { 899 final JCommandPopupMenu result = new JCommandPopupMenu(); 900 901 // SEQUENCES 902 for (Viewer viewer : allViewers) 903 { 904 final Viewer v = viewer; 905 906 final IcyCommandMenuButton seqButton = new IcyCommandMenuButton(viewer.getTitle()); 907 seqButton.addActionListener(new ActionListener() 908 { 909 @Override 910 public void actionPerformed(ActionEvent e) 911 { 912 ThreadUtil.invokeLater(new Runnable() 913 { 914 @Override 915 public void run() 916 { 917 // remove minimized state 918 if (v.isMinimized()) 919 v.setMinimized(false); 920 // then grab focus 921 v.requestFocus(); 922 v.toFront(); 923 } 924 }); 925 } 926 }); 927 result.addMenuButton(seqButton); 928 } 929 930 return result; 931 } 932 }); 933 sequencesButton.setEnabled(allViewers.size() > 0); 934 result.addMenuButton(sequencesButton); 935 936 // OPENED FRAMES 937 final ArrayList<IcyFrame> allFrames = IcyFrame.getAllFrames(); 938 final IcyCommandMenuButton framesButton = new IcyCommandMenuButton("Opened frames", 939 new IcyIcon(ResourceUtil.ICON_WINDOW)); 940 framesButton.setPopupRichTooltip(new RichTooltip("Opened frames", "Show all frames")); 941 framesButton.setCommandButtonKind(CommandButtonKind.POPUP_ONLY); 942 framesButton.setPopupCallback(new PopupPanelCallback() 943 { 944 @Override 945 public JPopupPanel getPopupPanel(JCommandButton commandButton) 946 { 947 final JCommandPopupMenu result = new JCommandPopupMenu(); 948 949 // FRAMES 950 for (IcyFrame frame : allFrames) 951 { 952 if ((frame instanceof Viewer) || (frame instanceof TaskFrame) || !frame.isVisible()) 953 continue; 954 955 final IcyFrame f = frame; 956 957 final IcyCommandMenuButton frameButton = new IcyCommandMenuButton(frame.getTitle()); 958 frameButton.addActionListener(new ActionListener() 959 { 960 @Override 961 public void actionPerformed(ActionEvent e) 962 { 963 ThreadUtil.invokeLater(new Runnable() 964 { 965 @Override 966 public void run() 967 { 968 // remove minimized state 969 if (f.isMinimized()) 970 f.setMinimized(false); 971 // then grab focus 972 f.requestFocus(); 973 f.toFront(); 974 } 975 }); 976 } 977 }); 978 result.addMenuButton(frameButton); 979 } 980 981 return result; 982 } 983 }); 984 985 // check if we have visible frame 986 boolean hasVisibleFrame = false; 987 for (IcyFrame frame : allFrames) 988 if (!((frame instanceof Viewer) || (frame instanceof TaskFrame) || !frame.isVisible())) 989 hasVisibleFrame = true; 990 991 framesButton.setEnabled(hasVisibleFrame); 992 result.addMenuButton(framesButton); 993 994 return result; 995 } 996 }); 997 ribbon.addTaskbarComponent(windowsButton); 998 999 // SEPARATOR 1000 ribbon.addTaskbarComponent(new JSeparator(SwingConstants.VERTICAL)); 1001 1002 // SEARCH BAR 1003 searchBar = new SearchBar(); 1004 searchBar.setColumns(14); 1005 1006 ribbon.addTaskbarComponent(searchBar); 1007 1008 // HELP / INFOS 1009 final IcyCommandButton helpAndInfoButton = new IcyCommandButton(new IcyIcon(ResourceUtil.ICON_INFO)); 1010 1011 helpAndInfoButton.setPopupRichTooltip( 1012 new RichTooltip("General help and information", "Help, Updates and Informations about Icy.")); 1013 helpAndInfoButton.setCommandButtonKind(CommandButtonKind.POPUP_ONLY); 1014 helpAndInfoButton.setPopupCallback(new PopupPanelCallback() 1015 { 1016 @Override 1017 public JPopupPanel getPopupPanel(JCommandButton commandButton) 1018 { 1019 final JCommandPopupMenu result = new JCommandPopupMenu(); 1020 1021 // HELP 1022 result.addMenuButton(new IcyCommandMenuButton(GeneralActions.onlineHelpAction)); 1023 // WEB SITE 1024 result.addMenuButton(new IcyCommandMenuButton(GeneralActions.websiteAction)); 1025 // CHECK FOR UPDATE 1026 result.addMenuButton(new IcyCommandMenuButton(GeneralActions.checkUpdateAction)); 1027 // CHANGELOG 1028 result.addMenuButton(new IcyCommandMenuButton(GeneralActions.changeLogAction)); 1029 // ABOUT 1030 result.addMenuButton(new IcyCommandMenuButton(GeneralActions.aboutAction)); 1031 1032 return result; 1033 } 1034 }); 1035 ribbon.addTaskbarComponent(helpAndInfoButton); 1036 1037 // LINK 1038 // ribbon.addTaskbarComponent(new IcyCommandButton(GeneralActions.linkAction)); 1039 } 1040 1041 private void checkPluginsMenuCoherence() 1042 { 1043 // get plugins we have to display in menu 1044 final ArrayList<PluginDescriptor> plugins = PluginLoader.getActionablePlugins(); 1045 final ArrayList<ItemDefinition> items = getAllItems(); 1046 final PluginClassNameSorter pluginsSorter = PluginClassNameSorter.instance; 1047 1048 // sort plugins on classname 1049 Collections.sort(plugins, pluginsSorter); 1050 1051 final PluginDescriptor keyPlugin = new PluginDescriptor(); 1052 1053 ThreadUtil.invokeLater(new Runnable() 1054 { 1055 @Override 1056 public void run() 1057 { 1058 // find removed plugins 1059 for (ItemDefinition item : items) 1060 { 1061 if (!item.isSeparator() && (item.getBandDefinition() != othersPluginsBandDef)) 1062 { 1063 // set the className for searched element 1064 keyPlugin.getIdent().setClassName(item.getClassName()); 1065 1066 // not found in plugin list --> remove it 1067 if (Collections.binarySearch(plugins, keyPlugin, pluginsSorter) < 0) 1068 removeItem(item); 1069 } 1070 } 1071 1072 // update or add plugin button 1073 for (PluginDescriptor plugin : plugins) 1074 updateItem(plugin, findItem(plugin.getClassName())); 1075 1076 refreshOthersPluginsList(); 1077 } 1078 }); 1079 } 1080 1081 @Override 1082 public void pluginLoaderChanged(PluginLoaderEvent e) 1083 { 1084 // update menu according to plugins change 1085 checkPluginsMenuCoherence(); 1086 } 1087 1088 @Override 1089 public void sequenceActivated(Sequence sequence) 1090 { 1091 sequenceOperationTask.onSequenceChange(); 1092 roiTask.onSequenceActivationChange(); 1093 ijTask.onSequenceActivationChange(); 1094 applicationMenu.onSequenceActivationChange(); 1095 } 1096 1097 @Override 1098 public void sequenceDeactivated(Sequence sequence) 1099 { 1100 // nothing here 1101 } 1102 1103 @Override 1104 public void activeSequenceChanged(SequenceEvent event) 1105 { 1106 final SequenceEventSourceType type = event.getSourceType(); 1107 1108 if ((type == SequenceEventSourceType.SEQUENCE_DATA) || (type == SequenceEventSourceType.SEQUENCE_TYPE)) 1109 sequenceOperationTask.onSequenceChange(); 1110 if (type == SequenceEventSourceType.SEQUENCE_ROI) 1111 { 1112 sequenceOperationTask.onSequenceChange(); 1113 roiTask.onSequenceChange(); 1114 } 1115 } 1116}