001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2008-2010 Sun Microsystems, Inc.
015 * Portions Copyright 2014-2015 ForgeRock AS.
016 */
017
018package org.opends.guitools.controlpanel.ui;
019
020import static org.opends.messages.AdminToolMessages.*;
021
022import java.awt.Component;
023import java.awt.Dimension;
024import java.awt.GridBagConstraints;
025import java.awt.Insets;
026import java.awt.Point;
027import java.awt.Window;
028import java.awt.event.ActionEvent;
029import java.awt.event.ActionListener;
030import java.awt.event.ItemEvent;
031import java.awt.event.ItemListener;
032import java.util.ArrayList;
033import java.util.HashMap;
034
035import javax.swing.Box;
036import javax.swing.DefaultComboBoxModel;
037import javax.swing.ImageIcon;
038import javax.swing.JButton;
039import javax.swing.JComboBox;
040import javax.swing.JLabel;
041import javax.swing.JMenuItem;
042import javax.swing.JPopupMenu;
043import javax.swing.JScrollPane;
044import javax.swing.JSeparator;
045import javax.swing.JSplitPane;
046import javax.swing.JTree;
047import javax.swing.SwingUtilities;
048import javax.swing.border.EmptyBorder;
049import javax.swing.event.TreeSelectionEvent;
050import javax.swing.event.TreeSelectionListener;
051import javax.swing.tree.DefaultMutableTreeNode;
052import javax.swing.tree.DefaultTreeModel;
053import javax.swing.tree.TreeNode;
054import javax.swing.tree.TreePath;
055
056import org.opends.guitools.controlpanel.browser.IconPool;
057import org.opends.guitools.controlpanel.datamodel.AbstractIndexDescriptor;
058import org.opends.guitools.controlpanel.datamodel.BackendDescriptor;
059import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
060import org.opends.guitools.controlpanel.datamodel.IndexDescriptor;
061import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
062import org.opends.guitools.controlpanel.datamodel.VLVIndexDescriptor;
063import org.opends.guitools.controlpanel.event.*;
064import org.opends.guitools.controlpanel.task.DeleteIndexTask;
065import org.opends.guitools.controlpanel.task.Task;
066import org.opends.guitools.controlpanel.ui.components.CustomTree;
067import org.opends.guitools.controlpanel.ui.components.TreePanel;
068import org.opends.guitools.controlpanel.ui.nodes.AbstractIndexTreeNode;
069import org.opends.guitools.controlpanel.ui.nodes.CategoryTreeNode;
070import org.opends.guitools.controlpanel.ui.nodes.IndexTreeNode;
071import org.opends.guitools.controlpanel.ui.nodes.VLVIndexTreeNode;
072import org.opends.guitools.controlpanel.ui.renderer.TreeCellRenderer;
073import org.opends.guitools.controlpanel.util.Utilities;
074import org.opends.guitools.controlpanel.util.ViewPositions;
075import org.forgerock.i18n.LocalizableMessage;
076
077/**
078 * The pane that is displayed when the user clicks on 'Browse Indexes'.
079 *
080 */
081public class BrowseIndexPanel extends StatusGenericPanel
082implements IndexModifiedListener
083{
084  private static final long serialVersionUID = 4560020571983291585L;
085
086  private JComboBox backends;
087  private JLabel lNoBackendsFound;
088
089  private IndexBrowserRightPanel entryPane;
090  private TreePanel treePane;
091
092  private JScrollPane treeScroll;
093
094  private JButton newIndex;
095  private JButton newVLVIndex;
096
097  private CategoryTreeNode standardIndexes = new CategoryTreeNode(
098      INFO_CTRL_PANEL_INDEXES_CATEGORY_NODE.get());
099  private CategoryTreeNode vlvIndexes = new CategoryTreeNode(
100      INFO_CTRL_PANEL_VLV_INDEXES_CATEGORY_NODE.get());
101
102  private AbstractIndexDescriptor lastCreatedIndex;
103
104  private TreePath lastIndexTreePath;
105
106  private CategoryTreeNode[] categoryNodes = {
107      standardIndexes, vlvIndexes
108  };
109
110  private JMenuItem deleteMenuItem;
111
112  private GenericDialog newIndexDialog;
113  private NewIndexPanel newIndexPanel;
114  private GenericDialog newVLVIndexDialog;
115  private NewVLVIndexPanel newVLVIndexPanel;
116
117  private boolean ignoreSelectionEvents;
118
119  private boolean firstTreeRepopulate = true;
120
121  /**
122   * Default constructor.
123   *
124   */
125  public BrowseIndexPanel()
126  {
127    super();
128    createLayout();
129  }
130
131  /** {@inheritDoc} */
132  public boolean requiresBorder()
133  {
134    return false;
135  }
136
137  /** {@inheritDoc} */
138  public boolean requiresScroll()
139  {
140    return false;
141  }
142
143  /** {@inheritDoc} */
144  public void toBeDisplayed(boolean visible)
145  {
146    super.toBeDisplayed(visible);
147    Window w = Utilities.getParentDialog(this);
148    if (w instanceof GenericDialog)
149    {
150      ((GenericDialog)w).getRootPane().setDefaultButton(null);
151    }
152    else if (w instanceof GenericFrame)
153    {
154      ((GenericFrame)w).getRootPane().setDefaultButton(null);
155    }
156  }
157
158  /**
159   * Creates the layout of the panel (but the contents are not populated here).
160   */
161  private void createLayout()
162  {
163    setBackground(ColorAndFontConstants.greyBackground);
164    GridBagConstraints gbc = new GridBagConstraints();
165    gbc.anchor = GridBagConstraints.WEST;
166    gbc.gridx = 0;
167    gbc.gridy = 0;
168    gbc.gridwidth = 5;
169    gbc.weightx = 1.0;
170    gbc.fill = GridBagConstraints.BOTH;
171    addErrorPane(gbc);
172
173    gbc.gridy ++;
174    gbc.gridwidth = 1;
175    gbc.weightx = 0;
176    gbc.fill = GridBagConstraints.NONE;
177    gbc.gridx = 0;
178    gbc.fill = GridBagConstraints.HORIZONTAL;
179    gbc.insets = new Insets(10, 10, 0, 0);
180    JLabel lBackend =
181      Utilities.createPrimaryLabel(INFO_CTRL_PANEL_BACKEND_LABEL.get());
182    add(lBackend, gbc);
183
184    backends = Utilities.createComboBox();
185    backends.setModel(new DefaultComboBoxModel(new String[]{}));
186    ItemListener comboListener = new ItemListener()
187    {
188      /** {@inheritDoc} */
189      public void itemStateChanged(ItemEvent ev)
190      {
191        if (!ignoreSelectionEvents &&
192            ev.getStateChange() == ItemEvent.SELECTED)
193        {
194          repopulateTree(treePane.getTree());
195        }
196      }
197    };
198    backends.addItemListener(comboListener);
199    gbc.insets.left = 5;
200    gbc.gridx ++;
201    add(backends, gbc);
202    lNoBackendsFound = Utilities.createDefaultLabel(
203        INFO_CTRL_PANEL_NO_BACKENDS_FOUND_LABEL.get());
204    add(lNoBackendsFound, gbc);
205    lNoBackendsFound.setVisible(false);
206
207    newIndex = Utilities.createButton(
208        INFO_CTRL_PANEL_NEW_INDEX_BUTTON_LABEL.get());
209    newIndex.setOpaque(false);
210    newIndex.addActionListener(new ActionListener()
211    {
212      /** {@inheritDoc} */
213      public void actionPerformed(ActionEvent ev)
214      {
215        newIndexClicked();
216      }
217    });
218    gbc.gridx ++;
219    gbc.insets.left = 10;
220    add(newIndex, gbc);
221
222    newVLVIndex = Utilities.createButton(
223        INFO_CTRL_PANEL_NEW_VLV_INDEX_BUTTON_LABEL.get());
224    newVLVIndex.setOpaque(false);
225    newVLVIndex.addActionListener(new ActionListener()
226    {
227      /** {@inheritDoc} */
228      public void actionPerformed(ActionEvent ev)
229      {
230        newVLVIndexClicked();
231      }
232    });
233    gbc.gridx ++;
234    gbc.insets.right = 10;
235    add(newVLVIndex, gbc);
236    gbc.gridx ++;
237    gbc.weightx = 1.0;
238    add(Box.createHorizontalGlue(), gbc);
239
240    gbc.insets = new Insets(10, 0, 0, 0);
241    gbc.gridx = 0;
242    gbc.gridy ++;
243    gbc.weightx = 1.0;
244    gbc.weighty = 1.0;
245    gbc.fill = GridBagConstraints.BOTH;
246    gbc.gridwidth = 5;
247    add(createSplitPane(), gbc);
248  }
249
250  /** {@inheritDoc} */
251  public LocalizableMessage getTitle()
252  {
253    return INFO_CTRL_PANEL_MANAGE_INDEXES_TITLE.get();
254  }
255
256  /** {@inheritDoc} */
257  public Component getPreferredFocusComponent()
258  {
259    return backends;
260  }
261
262  /** {@inheritDoc} */
263  public void closeClicked()
264  {
265    super.closeClicked();
266  }
267
268  /** {@inheritDoc} */
269  public void okClicked()
270  {
271    // No ok button
272  }
273
274  /** {@inheritDoc} */
275  public GenericDialog.ButtonType getButtonType()
276  {
277    return GenericDialog.ButtonType.CLOSE;
278  }
279
280  private Component createSplitPane()
281  {
282    JSplitPane pane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
283    pane.setOpaque(true); //content panes must be opaque
284
285    treePane = new TreePanel();
286    Utilities.setBorder(treePane, new EmptyBorder(10, 0, 10, 0));
287
288    entryPane = new IndexBrowserRightPanel();
289    treeScroll = Utilities.createScrollPane(treePane);
290
291    entryPane.addIndexSelectionListener(new IndexSelectionListener()
292    {
293      /** {@inheritDoc} */
294      public void indexSelected(IndexSelectionEvent ev)
295      {
296        AbstractIndexDescriptor index = ev.getIndex();
297        TreeNode parentNode;
298        if (index instanceof IndexDescriptor)
299        {
300          parentNode = standardIndexes;
301        }
302        else
303        {
304          parentNode = vlvIndexes;
305        }
306        DefaultTreeModel model =
307          (DefaultTreeModel)treePane.getTree().getModel();
308        int n = model.getChildCount(parentNode);
309        for (int i=0; i<n; i++)
310        {
311          AbstractIndexTreeNode node =
312            (AbstractIndexTreeNode)model.getChild(parentNode, i);
313          if (node.getName().equals(index.getName()))
314          {
315            TreePath newSelectionPath = new TreePath(node.getPath());
316            treePane.getTree().setSelectionPath(newSelectionPath);
317            treePane.getTree().scrollPathToVisible(newSelectionPath);
318            break;
319          }
320        }
321      }
322    });
323
324
325//  Create a split pane
326    pane.setLeftComponent(treeScroll);
327    pane.setRightComponent(entryPane);
328    pane.setResizeWeight(0.0);
329
330    treePane.getTree().addTreeSelectionListener(new TreeSelectionListener()
331    {
332      /** {@inheritDoc} */
333      public void valueChanged(TreeSelectionEvent ev)
334      {
335        if (!ignoreSelectionEvents)
336        {
337          TreePath[] paths = treePane.getTree().getSelectionPaths();
338
339          if (entryPane.mustCheckUnsavedChanges())
340          {
341            ignoreSelectionEvents = true;
342            treePane.getTree().setSelectionPath(lastIndexTreePath);
343            switch (entryPane.checkUnsavedChanges())
344            {
345            case DO_NOT_SAVE:
346              break;
347            case SAVE:
348              break;
349            case CANCEL:
350              ignoreSelectionEvents = false;
351              return;
352            }
353            if (paths != null)
354            {
355              treePane.getTree().setSelectionPaths(paths);
356            }
357            else
358            {
359              treePane.getTree().clearSelection();
360            }
361            ignoreSelectionEvents = false;
362          }
363
364
365          boolean deletableElementsSelected = false;
366          boolean nonDeletableElementsSelected = false;
367          if (paths != null)
368          {
369            for (TreePath path : paths)
370            {
371              Object node = path.getLastPathComponent();
372              if (node instanceof IndexTreeNode)
373              {
374                IndexDescriptor index = ((IndexTreeNode)node).getIndex();
375                if (index.isDatabaseIndex())
376                {
377                  nonDeletableElementsSelected = true;
378                }
379                else
380                {
381                  deletableElementsSelected = true;
382                }
383              }
384              else if (node instanceof VLVIndexTreeNode)
385              {
386                deletableElementsSelected = true;
387              }
388            }
389          }
390          deleteMenuItem.setEnabled(deletableElementsSelected &&
391              !nonDeletableElementsSelected);
392          updateEntryPane();
393        }
394      }
395    });
396    DefaultMutableTreeNode root = new DefaultMutableTreeNode("Tree root");
397    for (DefaultMutableTreeNode node : categoryNodes)
398    {
399      root.add(node);
400    }
401    DefaultTreeModel model = new DefaultTreeModel(root);
402    JTree tree = treePane.getTree();
403    tree.setModel(model);
404    tree.setRootVisible(false);
405    tree.setVisibleRowCount(20);
406    tree.expandPath(new TreePath(root));
407    tree.setCellRenderer(new IndexTreeCellRenderer());
408    addPopupMenu();
409
410    treeScroll.setPreferredSize(
411        new Dimension(2 * treeScroll.getPreferredSize().width,
412            8 * treeScroll.getPreferredSize().height));
413    entryPane.setBorder(getRightPanelBorder());
414    entryPane.setPreferredSize(
415        new Dimension((treeScroll.getPreferredSize().width * 5) / 2,
416        treeScroll.getPreferredSize().height));
417    pane.setDividerLocation(treeScroll.getPreferredSize().width);
418    entryPane.displayVoid();
419    return pane;
420  }
421
422  /** {@inheritDoc} */
423  public void setInfo(ControlPanelInfo info)
424  {
425    super.setInfo(info);
426    treePane.setInfo(info);
427    entryPane.setInfo(info);
428    info.addIndexModifiedListener(this);
429  }
430
431  /** {@inheritDoc} */
432  public void configurationChanged(ConfigurationChangeEvent ev)
433  {
434    ignoreSelectionEvents = true;
435    ServerDescriptor desc = ev.getNewDescriptor();
436    updateSimpleBackendComboBoxModel(backends, lNoBackendsFound,
437        desc);
438    refreshContents(desc);
439  }
440
441  /**
442   * Adds a pop up menu.
443   *
444   */
445  private void addPopupMenu()
446  {
447    final JPopupMenu popup = new JPopupMenu();
448    JMenuItem menuItem = Utilities.createMenuItem(
449        INFO_CTRL_PANEL_NEW_INDEX_MENU.get());
450    menuItem.addActionListener(new ActionListener()
451    {
452      /** {@inheritDoc} */
453      public void actionPerformed(ActionEvent ev)
454      {
455        newIndexClicked();
456      }
457    });
458    popup.add(menuItem);
459    menuItem = Utilities.createMenuItem(
460        INFO_CTRL_PANEL_NEW_VLV_INDEX_MENU.get());
461    menuItem.addActionListener(new ActionListener()
462    {
463      /** {@inheritDoc} */
464      public void actionPerformed(ActionEvent ev)
465      {
466        newVLVIndexClicked();
467      }
468    });
469    popup.add(menuItem);
470    popup.add(new JSeparator());
471    deleteMenuItem = Utilities.createMenuItem(
472        INFO_CTRL_PANEL_DELETE_INDEX_MENU.get());
473    deleteMenuItem.addActionListener(new ActionListener()
474    {
475      /** {@inheritDoc} */
476      public void actionPerformed(ActionEvent ev)
477      {
478        deleteClicked();
479      }
480    });
481    popup.add(deleteMenuItem);
482    deleteMenuItem.setEnabled(false);
483
484    ((CustomTree)treePane.getTree()).setPopupMenu(popup);
485  }
486
487  /**
488   * Refresh the contents of the tree.
489   * @param desc the descriptor containing the index configuration.
490   */
491  private void refreshContents(final ServerDescriptor desc)
492  {
493    SwingUtilities.invokeLater(new Runnable()
494    {
495      /** {@inheritDoc} */
496      public void run()
497      {
498        repopulateTree(treePane.getTree());
499        ignoreSelectionEvents = false;
500        boolean userBackendsDefined = backends.getModel().getSize() > 0;
501        newIndex.setEnabled(userBackendsDefined);
502        newVLVIndex.setEnabled(userBackendsDefined);
503        if (!userBackendsDefined)
504        {
505          entryPane.displayVoid();
506          updateErrorPane(errorPane,
507              ERR_CTRL_PANEL_NO_BACKENDS_FOUND_TITLE.get(),
508              ColorAndFontConstants.errorTitleFont,
509              ERR_CTRL_PANEL_NO_BACKENDS_FOUND_DETAILS.get(),
510              ColorAndFontConstants.defaultFont);
511          errorPane.setVisible(true);
512        }
513        else
514        {
515          errorPane.setVisible(false);
516        }
517      }
518    });
519  }
520
521  /** {@inheritDoc} */
522  public void indexModified(IndexModifiedEvent ev)
523  {
524    refreshContents(getInfo().getServerDescriptor());
525  }
526
527  /** {@inheritDoc} */
528  public void backendIndexesModified(IndexModifiedEvent ev)
529  {
530    refreshContents(getInfo().getServerDescriptor());
531  }
532
533  /**
534   * Repopulates the contents of the tree.
535   * @param tree the tree to be repopulated.
536   */
537  private void repopulateTree(JTree tree)
538  {
539    ignoreSelectionEvents = true;
540
541    final Point currentPosition = treeScroll.getViewport().getViewPosition();
542    DefaultMutableTreeNode root = getRoot(tree);
543
544    TreePath path = tree.getSelectionPath();
545    DefaultMutableTreeNode lastSelectedNode = null;
546    if (path != null)
547    {
548      lastSelectedNode = (DefaultMutableTreeNode)path.getLastPathComponent();
549    }
550    TreePath newSelectionPath = null;
551
552    BackendDescriptor backend = null;
553    String backendName = (String)backends.getSelectedItem();
554    if (backendName != null)
555    {
556      for (BackendDescriptor b : getInfo().getServerDescriptor().getBackends())
557      {
558        if (b.getBackendID().equalsIgnoreCase(backendName))
559        {
560          backend = b;
561          break;
562        }
563      }
564    }
565
566    ArrayList<ArrayList<? extends AbstractIndexTreeNode>> nodes = new ArrayList<>();
567    ArrayList<IndexTreeNode> standardIndexNodes = new ArrayList<>();
568    ArrayList<VLVIndexTreeNode> vlvIndexNodes = new ArrayList<>();
569    nodes.add(standardIndexNodes);
570    nodes.add(vlvIndexNodes);
571
572    if (backend != null)
573    {
574      for (IndexDescriptor index : backend.getIndexes())
575      {
576        standardIndexNodes.add(new IndexTreeNode(index.getName(), index));
577      }
578      for (VLVIndexDescriptor index : backend.getVLVIndexes())
579      {
580        vlvIndexNodes.add(new VLVIndexTreeNode(index.getName(), index));
581      }
582    }
583
584
585    DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
586    int i = 0;
587    int positionUnderRoot = 0;
588    for (DefaultMutableTreeNode parent : categoryNodes)
589    {
590      if (nodes.get(i).isEmpty())
591      {
592        if (root.getIndex(parent) != -1)
593        {
594          model.removeNodeFromParent(parent);
595          parent.removeAllChildren();
596        }
597      }
598      else
599      {
600        boolean expand = true;
601        if (root.getIndex(parent) == -1)
602        {
603          model.insertNodeInto(parent, root, positionUnderRoot);
604        }
605        else
606        {
607          expand = tree.isExpanded(new TreePath(parent)) || parent.getChildCount() == 0;
608          parent.removeAllChildren();
609        }
610        for (AbstractIndexTreeNode node : nodes.get(i))
611        {
612          parent.add(node);
613          if (newSelectionPath == null &&
614              (lastSelectedNode != null || lastCreatedIndex != null))
615          {
616            if (lastCreatedIndex != null)
617            {
618              if (node instanceof IndexTreeNode &&
619                  lastCreatedIndex instanceof IndexDescriptor)
620              {
621                if (node.getName().equals(lastCreatedIndex.getName()))
622                {
623                  newSelectionPath = new TreePath(node.getPath());
624                  lastCreatedIndex = null;
625                }
626              }
627              else if (node instanceof VLVIndexTreeNode
628                  && lastCreatedIndex instanceof VLVIndexDescriptor
629                  && node.getName().equals(lastCreatedIndex.getName()))
630              {
631                newSelectionPath = new TreePath(node.getPath());
632                lastCreatedIndex = null;
633              }
634            }
635            else if (node.getName().equals(lastSelectedNode.getUserObject()))
636            {
637              newSelectionPath = new TreePath(node.getPath());
638            }
639          }
640        }
641        model.nodeStructureChanged(parent);
642        if (expand)
643        {
644          tree.expandPath(new TreePath(parent.getPath()));
645        }
646        positionUnderRoot++;
647      }
648      i++;
649    }
650
651    if (newSelectionPath == null && firstTreeRepopulate)
652    {
653      newSelectionPath = new TreePath(standardIndexes.getPath());
654    }
655    if (newSelectionPath != null)
656    {
657      tree.setSelectionPath(newSelectionPath);
658      tree.scrollPathToVisible(newSelectionPath);
659    }
660
661    updateEntryPane();
662
663    SwingUtilities.invokeLater(new Runnable()
664    {
665      public void run()
666      {
667        if (firstTreeRepopulate)
668        {
669          treeScroll.getViewport().setViewPosition(new Point(0, 0));
670        }
671        else
672        {
673          treeScroll.getViewport().setViewPosition(currentPosition);
674        }
675      }
676    });
677    firstTreeRepopulate = false;
678    ignoreSelectionEvents = false;
679  }
680
681  /**
682   * Updates the contents of the right panel.
683   *
684   */
685  private void updateEntryPane()
686  {
687    ViewPositions pos = Utilities.getViewPositions(entryPane);
688    TreePath[] paths = treePane.getTree().getSelectionPaths();
689    TreePath path = null;
690    if (paths != null && paths.length == 1)
691    {
692      path = paths[0];
693    }
694    lastIndexTreePath = path;
695    if (path != null)
696    {
697      Object node = path.getLastPathComponent();
698      if (node instanceof IndexTreeNode)
699      {
700        entryPane.updateStandardIndex(
701            ((IndexTreeNode)node).getIndex());
702      }
703      else if (node instanceof VLVIndexTreeNode)
704      {
705        entryPane.updateVLVIndex(((VLVIndexTreeNode)node).getIndex());
706      }
707      else if (node == standardIndexes)
708      {
709        String backendName = (String)backends.getSelectedItem();
710        entryPane.updateBackendIndexes(backendName);
711      }
712      else if (node == vlvIndexes)
713      {
714        String backendName = (String)backends.getSelectedItem();
715        entryPane.updateBackendVLVIndexes(backendName);
716      }
717      else
718      {
719        entryPane.displayVoid();
720      }
721    }
722    else
723    {
724      if (paths != null && paths.length > 1)
725      {
726        entryPane.displayMultiple();
727      }
728      else
729      {
730        entryPane.displayVoid();
731      }
732    }
733    Utilities.updateViewPositions(pos);
734  }
735
736  private DefaultMutableTreeNode getRoot(JTree tree)
737  {
738    return (DefaultMutableTreeNode)tree.getModel().getRoot();
739  }
740
741  private void newIndexClicked()
742  {
743    if (newIndexPanel == null)
744    {
745      newIndexPanel =
746        new NewIndexPanel((String)backends.getSelectedItem(),
747          Utilities.getParentDialog(this));
748      newIndexPanel.setInfo(getInfo());
749      newIndexDialog = new GenericDialog(null, newIndexPanel);
750      Utilities.centerGoldenMean(newIndexDialog,
751          Utilities.getParentDialog(this));
752      newIndexPanel.addConfigurationElementCreatedListener(
753          new ConfigurationElementCreatedListener()
754          {
755            public void elementCreated(ConfigurationElementCreatedEvent ev)
756            {
757              Object o = ev.getConfigurationObject();
758              if (o instanceof AbstractIndexDescriptor)
759              {
760                lastCreatedIndex = (AbstractIndexDescriptor)o;
761              }
762            }
763          });
764    }
765    else if (!newIndexDialog.isVisible())
766    {
767      String backendID = (String)backends.getSelectedItem();
768      for (BackendDescriptor backend :
769        getInfo().getServerDescriptor().getBackends())
770      {
771        if (backend.getBackendID().equalsIgnoreCase(backendID))
772        {
773          newIndexPanel.update(backend);
774          break;
775        }
776      }
777    }
778    newIndexDialog.setVisible(true);
779  }
780
781  private void newVLVIndexClicked()
782  {
783    if (newVLVIndexPanel == null)
784    {
785      newVLVIndexPanel =
786        new NewVLVIndexPanel((String)backends.getSelectedItem(),
787          Utilities.getParentDialog(this));
788      newVLVIndexPanel.setInfo(getInfo());
789      newVLVIndexDialog = new GenericDialog(null, newVLVIndexPanel);
790      Utilities.centerGoldenMean(newVLVIndexDialog,
791          Utilities.getParentDialog(this));
792      newVLVIndexPanel.addConfigurationElementCreatedListener(
793          new ConfigurationElementCreatedListener()
794          {
795            /** {@inheritDoc} */
796            public void elementCreated(ConfigurationElementCreatedEvent ev)
797            {
798              Object o = ev.getConfigurationObject();
799              if (o instanceof AbstractIndexDescriptor)
800              {
801                lastCreatedIndex = (AbstractIndexDescriptor)o;
802              }
803            }
804          });
805    }
806    else if (!newVLVIndexDialog.isVisible())
807    {
808      String backendID = (String)backends.getSelectedItem();
809      for (BackendDescriptor backend :
810        getInfo().getServerDescriptor().getBackends())
811      {
812        if (backend.getBackendID().equalsIgnoreCase(backendID))
813        {
814          newVLVIndexPanel.update(backend);
815          break;
816        }
817      }
818    }
819    newVLVIndexDialog.setVisible(true);
820  }
821
822  private void deleteClicked()
823  {
824    ArrayList<LocalizableMessage> errors = new ArrayList<>();
825    TreePath[] paths = treePane.getTree().getSelectionPaths();
826    ArrayList<AbstractIndexDescriptor> indexesToDelete = new ArrayList<>();
827    ArrayList<String> indexesNames = new ArrayList<>();
828    if (paths != null)
829    {
830      for (TreePath path : paths)
831      {
832        Object node = path.getLastPathComponent();
833        if (node instanceof IndexTreeNode)
834        {
835          indexesToDelete.add(((IndexTreeNode)node).getIndex());
836        }
837        else if (node instanceof VLVIndexTreeNode)
838        {
839          indexesToDelete.add(((VLVIndexTreeNode)node).getIndex());
840        }
841      }
842    }
843    else
844    {
845      errors.add(ERR_CTRL_PANEL_NO_INDEX_SELECTED.get());
846    }
847    for (AbstractIndexDescriptor index : indexesToDelete)
848    {
849      indexesNames.add(index.getName());
850    }
851    String nameLabel = Utilities.getStringFromCollection(indexesNames, ", ");
852    String backendName = indexesToDelete.get(0).getBackend().getBackendID();
853    if (errors.isEmpty())
854    {
855      ProgressDialog dlg = new ProgressDialog(
856          Utilities.createFrame(),
857          Utilities.getParentDialog(this),
858          INFO_CTRL_PANEL_DELETE_INDEXES_TITLE.get(), getInfo());
859      DeleteIndexTask newTask = new DeleteIndexTask(getInfo(), dlg,
860          indexesToDelete);
861      for (Task task : getInfo().getTasks())
862      {
863        task.canLaunch(newTask, errors);
864      }
865      if (errors.isEmpty())
866      {
867        if (displayConfirmationDialog(
868            INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(),
869            INFO_CTRL_PANEL_CONFIRMATION_INDEXES_DELETE_DETAILS.get(nameLabel,
870                backendName)))
871        {
872          launchOperation(newTask,
873              INFO_CTRL_PANEL_DELETING_INDEXES_SUMMARY.get(),
874              INFO_CTRL_PANEL_DELETING_INDEXES_COMPLETE.get(),
875              INFO_CTRL_PANEL_DELETING_INDEXES_SUCCESSFUL.get(nameLabel, backendName),
876              ERR_CTRL_PANEL_DELETING_INDEXES_ERROR_SUMMARY.get(),
877              ERR_CTRL_PANEL_DELETING_INDEXES_ERROR_DETAILS.get(nameLabel),
878              null,
879              dlg);
880          dlg.setVisible(true);
881        }
882      }
883    }
884    if (!errors.isEmpty())
885    {
886      displayErrorDialog(errors);
887    }
888  }
889
890  private HashMap<Object, ImageIcon> hmCategoryImages = new HashMap<>();
891  private HashMap<Class<?>, ImageIcon> hmImages = new HashMap<>();
892  {
893    Object[] nodes = {standardIndexes, vlvIndexes};
894    String[] paths = {"ds-idx-folder.png", "ds-vlv-idx-folder.png"};
895    for (int i=0; i<nodes.length; i++)
896    {
897      hmCategoryImages.put(nodes[i],
898          Utilities.createImageIcon(IconPool.IMAGE_PATH+"/"+paths[i]));
899    }
900    Class<?>[] classes = {IndexTreeNode.class, VLVIndexTreeNode.class};
901    String[] ocPaths = {"ds-idx.png", "ds-vlv-idx.png"};
902    for (int i=0; i<classes.length; i++)
903    {
904      hmImages.put(classes[i],
905          Utilities.createImageIcon(IconPool.IMAGE_PATH+"/"+ocPaths[i]));
906    }
907  }
908
909  /** Specific class used to render the nodes in the tree.  It uses specific icons for the nodes. */
910  protected class IndexTreeCellRenderer extends TreeCellRenderer
911  {
912    private ImageIcon readOnlyIndexIcon =
913      Utilities.createImageIcon(IconPool.IMAGE_PATH+"/ds-idx-ro.png");
914
915    private static final long serialVersionUID = -6953837045703643228L;
916
917    /** {@inheritDoc} */
918    public Component getTreeCellRendererComponent(JTree tree, Object value,
919        boolean isSelected, boolean isExpanded, boolean isLeaf, int row,
920        boolean hasFocus)
921    {
922      super.getTreeCellRendererComponent(tree, value, isSelected, isExpanded,
923          isLeaf, row, hasFocus);
924      setIcon(getIcon(value));
925      return this;
926    }
927
928    private ImageIcon getIcon(Object value)
929    {
930      ImageIcon icon = null;
931      if (value instanceof IndexTreeNode
932          && ((IndexTreeNode)value).getIndex().isDatabaseIndex())
933      {
934        icon = readOnlyIndexIcon;
935      }
936      if (icon == null)
937      {
938        icon = hmImages.get(value.getClass());
939        if (icon == null)
940        {
941          icon = hmCategoryImages.get(value);
942        }
943      }
944      return icon;
945    }
946  }
947}