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 2011-2016 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.Cursor;
024import java.awt.Dimension;
025import java.awt.Toolkit;
026import java.awt.datatransfer.Clipboard;
027import java.awt.datatransfer.ClipboardOwner;
028import java.awt.datatransfer.StringSelection;
029import java.awt.datatransfer.Transferable;
030import java.awt.dnd.DnDConstants;
031import java.awt.dnd.DragGestureEvent;
032import java.awt.dnd.DragGestureListener;
033import java.awt.dnd.DragSource;
034import java.awt.dnd.DragSourceContext;
035import java.awt.dnd.DragSourceDragEvent;
036import java.awt.dnd.DragSourceDropEvent;
037import java.awt.dnd.DragSourceEvent;
038import java.awt.dnd.DragSourceListener;
039import java.awt.event.ActionEvent;
040import java.awt.event.ActionListener;
041import java.awt.event.KeyEvent;
042import java.util.ArrayList;
043import java.util.LinkedHashSet;
044
045import javax.naming.InterruptedNamingException;
046import javax.naming.NamingException;
047import javax.naming.ldap.InitialLdapContext;
048import javax.swing.ButtonGroup;
049import javax.swing.JCheckBoxMenuItem;
050import javax.swing.JComponent;
051import javax.swing.JMenu;
052import javax.swing.JMenuBar;
053import javax.swing.JMenuItem;
054import javax.swing.JPopupMenu;
055import javax.swing.JRadioButtonMenuItem;
056import javax.swing.JScrollPane;
057import javax.swing.JSeparator;
058import javax.swing.JSplitPane;
059import javax.swing.JTree;
060import javax.swing.SwingUtilities;
061import javax.swing.event.TreeSelectionEvent;
062import javax.swing.event.TreeSelectionListener;
063import javax.swing.tree.TreePath;
064
065import org.forgerock.i18n.LocalizableMessage;
066import org.forgerock.opendj.ldap.DN;
067import org.forgerock.opendj.ldap.schema.AttributeType;
068import org.forgerock.opendj.ldap.schema.ObjectClass;
069import org.opends.guitools.controlpanel.browser.NodeRefresher;
070import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
071import org.opends.guitools.controlpanel.datamodel.CustomSearchResult;
072import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
073import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
074import org.opends.guitools.controlpanel.event.EntryReadErrorEvent;
075import org.opends.guitools.controlpanel.task.DeleteEntryTask;
076import org.opends.guitools.controlpanel.task.Task;
077import org.opends.guitools.controlpanel.ui.components.CustomTree;
078import org.opends.guitools.controlpanel.ui.nodes.BasicNode;
079import org.opends.guitools.controlpanel.ui.nodes.BrowserNodeInfo;
080import org.opends.guitools.controlpanel.ui.nodes.DndBrowserNodes;
081import org.opends.guitools.controlpanel.util.LDAPEntryReader;
082import org.opends.guitools.controlpanel.util.Utilities;
083import org.opends.server.types.Schema;
084import org.opends.server.util.ServerConstants;
085
086/**
087 * The pane that is displayed when the user clicks on 'Browse Entries...'.
088 * It contains its own menu bar with all the actions to edit the entries.
089 */
090public class BrowseEntriesPanel extends AbstractBrowseEntriesPanel
091{
092  private static final long serialVersionUID = 1308129251140541645L;
093
094  private BrowseMenuBar menuBar;
095
096  private JPopupMenu popup;
097  private JMenuItem popupDeleteMenuItem;
098  private JMenuItem popupCopyDNMenuItem;
099  private JMenuItem popupAddToGroupMenuItem;
100  private JMenuItem popupNewEntryFromLDIFMenuItem;
101  private JMenuItem popupNewUserMenuItem;
102  private JMenuItem popupNewGroupMenuItem;
103  private JMenuItem popupNewOUMenuItem;
104  private JMenuItem popupNewOrganizationMenuItem;
105  private JMenuItem popupNewDomainMenuItem;
106  private JMenuItem popupResetUserPasswordMenuItem;
107  private JMenuItem popupDuplicateEntryMenuItem;
108
109  private LDAPEntryPanel entryPane;
110
111  private GenericDialog resetUserPasswordDlg;
112  private ResetUserPasswordPanel resetUserPasswordPanel;
113
114  private GenericDialog addToGroupDlg;
115  private AddToGroupPanel addToGroupPanel;
116
117  private GenericDialog deleteBaseDNDlg;
118  private GenericDialog deleteBackendDlg;
119
120  private GenericDialog newUserDlg;
121  private NewUserPanel newUserPanel;
122
123  private GenericDialog newGroupDlg;
124  private NewGroupPanel newGroupPanel;
125
126  private GenericDialog newOUDlg;
127  private NewOrganizationalUnitPanel newOUPanel;
128
129  private GenericDialog newOrganizationDlg;
130  private NewOrganizationPanel newOrganizationPanel;
131
132  private GenericDialog newDomainDlg;
133  private NewDomainPanel newDomainPanel;
134
135  private GenericDialog newEntryFromLDIFDlg;
136  private NewEntryFromLDIFPanel newEntryFromLDIFPanel;
137
138  private GenericDialog duplicateEntryDlg;
139  private DuplicateEntryPanel duplicateEntryPanel;
140
141  private boolean ignoreTreeSelectionEvents;
142
143  private LDAPEntryReader entryReader;
144
145  private Thread entryReaderThread;
146
147  private boolean forceRefreshWhenOpening;
148
149  @Override
150  public JMenuBar getMenuBar()
151  {
152    if (menuBar == null)
153    {
154      menuBar = new BrowseMenuBar(getInfo());
155      menuBar.deleteMenuItem.setEnabled(false);
156    }
157    return menuBar;
158  }
159
160  @Override
161  public LocalizableMessage getTitle()
162  {
163    return INFO_CTRL_PANEL_MANAGE_ENTRIES_TITLE.get();
164  }
165
166  @Override
167  public GenericDialog.ButtonType getBrowseButtonType()
168  {
169    return GenericDialog.ButtonType.CLOSE;
170  }
171
172  @Override
173  protected void createBrowserController(ControlPanelInfo info)
174  {
175    super.createBrowserController(info);
176    entryPane.setController(controller);
177  }
178
179  @Override
180  public void okClicked()
181  {
182  }
183
184  @Override
185  public void toBeDisplayed(boolean visible)
186  {
187    super.toBeDisplayed(visible);
188    boolean isAuthenticated = false;
189    if (getInfo() != null && getInfo().getServerDescriptor() != null)
190    {
191      isAuthenticated = getInfo().getServerDescriptor().isAuthenticated();
192    }
193    if (visible && !isDisposeOnClose() && forceRefreshWhenOpening &&
194        isAuthenticated)
195    {
196      refreshClicked();
197    }
198    if (!visible)
199    {
200      forceRefreshWhenOpening = isAuthenticated;
201    }
202  }
203
204  @Override
205  protected Component createMainPanel()
206  {
207    JSplitPane pane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
208    pane.setOpaque(true); //content panes must be opaque
209
210    JComponent p = createTreePane();
211
212    JTree tree = treePane.getTree();
213    addDragAndDropListener(tree);
214    addTreeSelectionListener(tree);
215
216    JScrollPane treeScroll = Utilities.createScrollPane(p);
217    treeScroll.setPreferredSize(
218        new Dimension(treeScroll.getPreferredSize().width + 30,
219            4 * treeScroll.getPreferredSize().height));
220    pane.setDividerLocation(treeScroll.getPreferredSize().width);
221
222    entryPane = new LDAPEntryPanel();
223
224
225//  Create a split pane with the two scroll panes in it.
226    pane.setLeftComponent(treeScroll);
227    pane.setRightComponent(entryPane);
228    pane.setResizeWeight(0.0);
229    entryPane.setPreferredSize(
230        new Dimension((treeScroll.getPreferredSize().width * 5) / 2,
231            treeScroll.getPreferredSize().height));
232
233    entryPane.setBorder(getRightPanelBorder());
234
235    addPopupMenu();
236
237    return pane;
238  }
239
240  /**
241   * Adds the tree selection listener.
242   * @param tree the tree to which the listeners are added.
243   */
244  private void addTreeSelectionListener(JTree tree)
245  {
246    TreeSelectionListener treeSelectionListener = new TreeSelectionListener()
247    {
248      @Override
249      public void valueChanged(TreeSelectionEvent ev)
250      {
251        if (ignoreTreeSelectionEvents)
252        {
253          return;
254        }
255        TreePath path = null;
256        TreePath[] paths = treePane.getTree().getSelectionPaths();
257        if (entryPane.mustCheckUnsavedChanges())
258        {
259          ignoreTreeSelectionEvents = true;
260          treePane.getTree().setSelectionPath(entryPane.getTreePath());
261          switch (entryPane.checkUnsavedChanges())
262          {
263          case DO_NOT_SAVE:
264            break;
265          case SAVE:
266            break;
267          case CANCEL:
268            ignoreTreeSelectionEvents = false;
269            return;
270          }
271          if (paths != null)
272          {
273            treePane.getTree().setSelectionPaths(paths);
274          }
275          else
276          {
277            treePane.getTree().clearSelection();
278          }
279          ignoreTreeSelectionEvents = false;
280        }
281        if (paths != null && paths.length == 1)
282        {
283          path = paths[0];
284        }
285
286//      Update menu items
287        boolean enableDelete = enableDelete(paths);
288        popupDeleteMenuItem.setEnabled(enableDelete);
289        menuBar.deleteMenuItem.setEnabled(enableDelete);
290
291        boolean enableCopyDN = path != null;
292        popupCopyDNMenuItem.setEnabled(enableCopyDN);
293        menuBar.copyDNMenuItem.setEnabled(enableCopyDN);
294
295        boolean enableDuplicateEntry = enableCopyDN;
296        popupDuplicateEntryMenuItem.setEnabled(enableDuplicateEntry);
297        menuBar.duplicateEntryMenuItem.setEnabled(enableDuplicateEntry);
298
299        boolean enableAddToGroup = enableDelete;
300        popupAddToGroupMenuItem.setEnabled(enableAddToGroup);
301        menuBar.addToGroupMenuItem.setEnabled(enableAddToGroup);
302
303        boolean enableResetPassword = path != null;
304        if (enableResetPassword)
305        {
306          BasicNode node = (BasicNode)path.getLastPathComponent();
307          enableResetPassword = hasUserPassword(node.getObjectClassValues());
308        }
309        popupResetUserPasswordMenuItem.setEnabled(enableResetPassword);
310        menuBar.resetPasswordMenuItem.setEnabled(enableResetPassword);
311
312//      Assume that if we cannot delete, we cannot create a new path
313        boolean enableNewEntry = path != null && enableDelete;
314        popupNewUserMenuItem.setEnabled(enableNewEntry);
315        menuBar.newUserMenuItem.setEnabled(enableNewEntry);
316
317        popupNewGroupMenuItem.setEnabled(enableNewEntry);
318        menuBar.newGroupMenuItem.setEnabled(enableNewEntry);
319
320        popupNewOUMenuItem.setEnabled(enableNewEntry);
321        menuBar.newOUMenuItem.setEnabled(enableNewEntry);
322
323        popupNewOrganizationMenuItem.setEnabled(enableNewEntry);
324        menuBar.newOrganizationMenuItem.setEnabled(enableNewEntry);
325
326        popupNewDomainMenuItem.setEnabled(enableNewEntry);
327        menuBar.newDomainMenuItem.setEnabled(enableNewEntry);
328
329        updateRightPane(paths);
330      }
331
332      private boolean enableDelete(TreePath[] paths)
333      {
334        if (paths != null && paths.length > 0)
335        {
336          for (TreePath p : paths)
337          {
338            BasicNode n = (BasicNode)p.getLastPathComponent();
339            if (!entryPane.canDelete(n.getDN()))
340            {
341              return false;
342            }
343          }
344          return true;
345        }
346        return false;
347      }
348    };
349    tree.getSelectionModel().addTreeSelectionListener(treeSelectionListener);
350  }
351
352  /**
353   * Adds a drag and drop listener to a tree.
354   * @param tree the tree to which the listener is added.
355   */
356  private void addDragAndDropListener(JTree tree)
357  {
358    final DragSource dragSource = DragSource.getDefaultDragSource();
359    final DragSourceListener dragSourceListener = new DragSourceListener()
360    {
361      @Override
362      public void dragDropEnd(DragSourceDropEvent dsde)
363      {
364      }
365
366      @Override
367      public void dragEnter(DragSourceDragEvent dsde)
368      {
369        DragSourceContext context = dsde.getDragSourceContext();
370        int dropAction = dsde.getDropAction();
371        if ((dropAction & DnDConstants.ACTION_COPY) != 0)
372        {
373          context.setCursor(DragSource.DefaultCopyDrop);
374        }
375        else if ((dropAction & DnDConstants.ACTION_MOVE) != 0)
376        {
377          context.setCursor(DragSource.DefaultMoveDrop);
378        }
379        else
380        {
381          context.setCursor(DragSource.DefaultCopyNoDrop);
382        }
383      }
384
385      @Override
386      public void dragOver(DragSourceDragEvent dsde)
387      {
388      }
389
390      @Override
391      public void dropActionChanged(DragSourceDragEvent dsde)
392      {
393      }
394
395      @Override
396      public void dragExit(DragSourceEvent dsde)
397      {
398      }
399    };
400    final DragGestureListener dragGestureListener = new DragGestureListener()
401    {
402      @Override
403      public void dragGestureRecognized(DragGestureEvent e)
404      {
405        //Get the selected node
406        JTree tree = treePane.getTree();
407        TreePath[] paths = tree.getSelectionPaths();
408        if (paths != null)
409        {
410          BrowserNodeInfo[] nodes = new BrowserNodeInfo[paths.length];
411          DndBrowserNodes dndNodes = new DndBrowserNodes();
412          for (int i=0; i<paths.length; i++)
413          {
414            BrowserNodeInfo node = controller.getNodeInfoFromPath(paths[i]);
415            nodes[i] = node;
416          }
417          dndNodes.setParent(tree);
418          dndNodes.setNodes(nodes);
419          //Select the appropriate cursor;
420          Cursor cursor = DragSource.DefaultCopyNoDrop;
421          // begin the drag
422          dragSource.startDrag(e, cursor, dndNodes, dragSourceListener);
423        }
424      }
425    };
426    dragSource.createDefaultDragGestureRecognizer(tree,  //DragSource
427        DnDConstants.ACTION_COPY_OR_MOVE, //specifies valid actions
428        dragGestureListener
429    );
430  }
431
432  @Override
433  public void setInfo(ControlPanelInfo info)
434  {
435    super.setInfo(info);
436    entryPane.setInfo(info);
437  }
438
439  @Override
440  public void configurationChanged(ConfigurationChangeEvent ev)
441  {
442    final ServerDescriptor desc = ev.getNewDescriptor();
443
444    updateMenus(desc);
445
446    super.configurationChanged(ev);
447  }
448
449  /**
450   * Returns <CODE>true</CODE> if the provided object classes allow (or require
451   * the userPassword attribute).
452   * @param ocs the object classes.
453   * @return <CODE>true</CODE> if the provided object classes allow (or require
454   * the userPassword attribute) and <CODE>false</CODE> otherwise.
455   */
456  private boolean hasUserPassword(String[] ocs)
457  {
458    Schema schema = getInfo().getServerDescriptor().getSchema();
459    if (ocs != null && schema != null)
460    {
461      AttributeType attr = schema.getAttributeType(ServerConstants.ATTR_USER_PASSWORD);
462      for (String oc : ocs)
463      {
464        ObjectClass objectClass = schema.getObjectClass(oc);
465        if (!attr.isPlaceHolder()
466            && !objectClass.isPlaceHolder()
467            && objectClass.isRequiredOrOptional(attr))
468        {
469          return true;
470        }
471      }
472    }
473    return false;
474  }
475
476  /**
477   * Updates the menus with the provided server descriptor.
478   * @param desc the server descriptor.
479   */
480  private void updateMenus(ServerDescriptor desc)
481  {
482    menuBar.newEntryFromLDIFMenuItem.setEnabled(desc.isAuthenticated());
483    menuBar.deleteBackendMenuItem.setEnabled(desc.isAuthenticated());
484    menuBar.deleteBaseDNMenuItem.setEnabled(desc.isAuthenticated());
485  }
486
487  /**
488   * Updates the contents of the right pane with the selected tree paths.
489   * @param paths the selected tree paths.
490   */
491  private void updateRightPane(TreePath[] paths)
492  {
493    TreePath path = null;
494    if (paths != null && paths.length == 1)
495    {
496      path = paths[0];
497    }
498    BasicNode node = null;
499    if (path != null)
500    {
501      node = (BasicNode)path.getLastPathComponent();
502    }
503    if (node != null)
504    {
505      String dn;
506      if (controller.getFollowReferrals() &&
507          node.getReferral() != null &&
508          node.getRemoteUrl() == null &&
509          node.getError() != null &&
510          node.getError().getState() == NodeRefresher.State.SOLVING_REFERRAL)
511      {
512        // We are in the case where we are following referrals but the referral
513        // could not be resolved.  Display an error.
514        entryPane.referralSolveError(node.getDN(), node.getReferral(),
515            node.getError());
516        dn = null;
517      }
518      else if (controller.getFollowReferrals() && node.getRemoteUrl() != null)
519      {
520        dn = node.getRemoteUrl().getRawBaseDN();
521      }
522      else
523      {
524        dn = node.getDN();
525      }
526
527      if (dn != null)
528      {
529        try
530        {
531          InitialLdapContext ctx =
532            controller.findConnectionForDisplayedEntry(node);
533          LDAPEntryReader reader = new LDAPEntryReader(dn, ctx);
534          reader.addEntryReadListener(entryPane);
535          // Required to update the browser controller properly if the entry is
536          // deleted.
537          entryPane.setTreePath(path);
538          stopCurrentReader();
539          startReader(reader);
540        }
541        catch (Throwable t)
542        {
543          if (!isInterruptedException(t))
544          {
545            EntryReadErrorEvent ev = new EntryReadErrorEvent(this, dn, t);
546            entryPane.entryReadError(ev);
547          }
548        }
549      }
550    }
551    else
552    {
553      stopCurrentReader();
554      if (paths != null && paths.length > 1)
555      {
556        entryPane.multipleEntriesSelected();
557      }
558      else
559      {
560        entryPane.noEntrySelected();
561      }
562    }
563  }
564
565  private void stopCurrentReader()
566  {
567    if (entryReader != null)
568    {
569      entryReader.setNotifyListeners(false);
570    }
571  }
572
573  /**
574   * Starts the provider reader.
575   * @param reader the LDAPEntryReader.
576   */
577  private void startReader(LDAPEntryReader reader)
578  {
579    entryReader = reader;
580    if (entryReaderThread == null || !entryReaderThread.isAlive())
581    {
582      entryReaderThread = new Thread(new Runnable()
583      {
584        LDAPEntryReader reader;
585        CustomSearchResult sr;
586        Throwable t;
587        @Override
588        public void run()
589        {
590          while (true)
591          {
592            try
593            {
594              synchronized (entryReaderThread)
595              {
596                while ((reader = entryReader) == null)
597                {
598                  entryReaderThread.wait();
599                }
600              }
601              sr = null;
602              t = null;
603              try
604              {
605                sr = reader.processBackgroundTask();
606              }
607              catch (Throwable th)
608              {
609                t = th;
610              }
611              SwingUtilities.invokeAndWait(new Runnable()
612              {
613                @Override
614                public void run()
615                {
616                  reader.backgroundTaskCompleted(sr, t);
617                  if (reader == entryReader)
618                  {
619                    entryReader = null;
620                  }
621                }
622              });
623            }
624            catch (Throwable t)
625            {
626              entryReader = null;
627            }
628          }
629        }
630      });
631      entryReaderThread.start();
632    }
633    synchronized (entryReaderThread)
634    {
635      entryReaderThread.notify();
636    }
637  }
638
639  /** Adds a pop up menu to the tree. */
640  private void addPopupMenu()
641  {
642    popup = new JPopupMenu();
643
644    popupNewUserMenuItem = Utilities.createMenuItem(
645        INFO_CTRL_PANEL_NEW_USER_MENU.get());
646    popupNewUserMenuItem.addActionListener(new ActionListener()
647    {
648      @Override
649      public void actionPerformed(ActionEvent ev)
650      {
651        newUser();
652      }
653    });
654    popupNewUserMenuItem.setEnabled(false);
655    popup.add(popupNewUserMenuItem);
656
657    popupNewGroupMenuItem = Utilities.createMenuItem(
658        INFO_CTRL_PANEL_NEW_GROUP_MENU.get());
659    popupNewGroupMenuItem.addActionListener(new ActionListener()
660    {
661      @Override
662      public void actionPerformed(ActionEvent ev)
663      {
664        newGroup();
665      }
666    });
667    popupNewGroupMenuItem.setEnabled(false);
668    popup.add(popupNewGroupMenuItem);
669
670    popupNewOUMenuItem = Utilities.createMenuItem(
671        INFO_CTRL_PANEL_NEW_ORGANIZATIONAL_UNIT_MENU.get());
672    popupNewOUMenuItem.addActionListener(new ActionListener()
673    {
674      @Override
675      public void actionPerformed(ActionEvent ev)
676      {
677        newOrganizationalUnit();
678      }
679    });
680    popupNewOUMenuItem.setEnabled(false);
681    popup.add(popupNewOUMenuItem);
682
683    popupNewOrganizationMenuItem = Utilities.createMenuItem(
684        INFO_CTRL_PANEL_NEW_ORGANIZATION_MENU.get());
685    popupNewOrganizationMenuItem.addActionListener(new ActionListener()
686    {
687      @Override
688      public void actionPerformed(ActionEvent ev)
689      {
690        newOrganization();
691      }
692    });
693    popupNewOrganizationMenuItem.setEnabled(false);
694    popup.add(popupNewOrganizationMenuItem);
695
696    popupNewDomainMenuItem = Utilities.createMenuItem(
697        INFO_CTRL_PANEL_NEW_DOMAIN_MENU.get());
698    popupNewDomainMenuItem.addActionListener(new ActionListener()
699    {
700      @Override
701      public void actionPerformed(ActionEvent ev)
702      {
703        newDomain();
704      }
705    });
706    popupNewDomainMenuItem.setEnabled(false);
707    popup.add(popupNewDomainMenuItem);
708
709    popupNewEntryFromLDIFMenuItem = Utilities.createMenuItem(
710        INFO_CTRL_PANEL_NEW_FROM_LDIF_MENU.get());
711    popupNewEntryFromLDIFMenuItem.addActionListener(new ActionListener()
712    {
713      @Override
714      public void actionPerformed(ActionEvent ev)
715      {
716        newEntryFromLDIF();
717      }
718    });
719    popup.add(popupNewEntryFromLDIFMenuItem);
720
721    popup.add(new JSeparator());
722    popupResetUserPasswordMenuItem = Utilities.createMenuItem(
723        INFO_CTRL_PANEL_RESET_USER_PASSWORD_MENU.get());
724    popupResetUserPasswordMenuItem.addActionListener(new ActionListener()
725    {
726      @Override
727      public void actionPerformed(ActionEvent ev)
728      {
729        resetUserPassword();
730      }
731    });
732
733    popup.add(popupResetUserPasswordMenuItem);
734    popupResetUserPasswordMenuItem.setEnabled(false);
735
736    popupAddToGroupMenuItem = Utilities.createMenuItem(
737        INFO_CTRL_PANEL_ADD_TO_GROUP_MENU.get());
738    popupAddToGroupMenuItem.addActionListener(new ActionListener()
739    {
740      @Override
741      public void actionPerformed(ActionEvent ev)
742      {
743        addToGroup();
744      }
745    });
746    popup.add(popupAddToGroupMenuItem);
747    popupAddToGroupMenuItem.setEnabled(false);
748
749    popup.add(new JSeparator());
750
751    popupDuplicateEntryMenuItem = Utilities.createMenuItem(
752        INFO_CTRL_PANEL_DUPLICATE_ENTRY_MENU.get());
753    popupDuplicateEntryMenuItem.addActionListener(new ActionListener()
754    {
755      @Override
756      public void actionPerformed(ActionEvent ev)
757      {
758        duplicateEntry();
759      }
760    });
761    popup.add(popupDuplicateEntryMenuItem);
762
763    popupCopyDNMenuItem = Utilities.createMenuItem(
764        INFO_CTRL_PANEL_COPY_DN_MENU.get());
765    popupCopyDNMenuItem.addActionListener(new ActionListener()
766    {
767      @Override
768      public void actionPerformed(ActionEvent ev)
769      {
770        copyDN();
771      }
772    });
773    popup.add(popupCopyDNMenuItem);
774    popupCopyDNMenuItem.setEnabled(false);
775
776    popup.add(new JSeparator());
777
778    popupDeleteMenuItem = Utilities.createMenuItem(
779        INFO_CTRL_PANEL_DELETE_ENTRY_MENU.get());
780    popupDeleteMenuItem.addActionListener(new ActionListener()
781    {
782      @Override
783      public void actionPerformed(ActionEvent ev)
784      {
785        deleteClicked();
786      }
787    });
788    popup.add(popupDeleteMenuItem);
789    popupDeleteMenuItem.setEnabled(false);
790
791    popup.setOpaque(true);
792
793    ((CustomTree)treePane.getTree()).setPopupMenu(popup);
794  }
795
796  private void resetUserPassword()
797  {
798    if (resetUserPasswordDlg == null)
799    {
800      resetUserPasswordPanel = new ResetUserPasswordPanel();
801      resetUserPasswordPanel.setInfo(getInfo());
802      resetUserPasswordDlg = new GenericDialog(Utilities.getFrame(this),
803          resetUserPasswordPanel);
804      Utilities.centerGoldenMean(resetUserPasswordDlg,
805          Utilities.getParentDialog(this));
806    }
807    TreePath[] paths = treePane.getTree().getSelectionPaths();
808    if (paths != null && paths.length == 1)
809    {
810      TreePath path = paths[0];
811      BasicNode node = (BasicNode)path.getLastPathComponent();
812      resetUserPasswordPanel.setValue(node, controller);
813      resetUserPasswordDlg.setVisible(true);
814    }
815  }
816
817  private void deleteBaseDN()
818  {
819    if (deleteBaseDNDlg == null)
820    {
821      DeleteBaseDNPanel panel = new DeleteBaseDNPanel();
822      panel.setInfo(getInfo());
823      deleteBaseDNDlg = new GenericDialog(Utilities.getFrame(this), panel);
824      Utilities.centerGoldenMean(deleteBaseDNDlg,
825          Utilities.getParentDialog(this));
826    }
827    deleteBaseDNDlg.setVisible(true);
828  }
829
830  private void deleteBackend()
831  {
832    if (deleteBackendDlg == null)
833    {
834      DeleteBackendPanel panel = new DeleteBackendPanel();
835      panel.setInfo(getInfo());
836      deleteBackendDlg = new GenericDialog(Utilities.getFrame(this), panel);
837      Utilities.centerGoldenMean(deleteBackendDlg,
838          Utilities.getParentDialog(this));
839    }
840    deleteBackendDlg.setVisible(true);
841  }
842
843  private void newUser()
844  {
845    if (newUserDlg == null)
846    {
847      newUserPanel = new NewUserPanel();
848      newUserPanel.setInfo(getInfo());
849      newUserDlg = new GenericDialog(Utilities.getFrame(this), newUserPanel);
850      Utilities.centerGoldenMean(newUserDlg,
851          Utilities.getParentDialog(this));
852    }
853    TreePath[] paths = treePane.getTree().getSelectionPaths();
854    BasicNode parentNode = null;
855    if (paths != null && paths.length == 1)
856    {
857      TreePath path = paths[0];
858      parentNode = (BasicNode)path.getLastPathComponent();
859    }
860    newUserPanel.setParent(parentNode, controller);
861    newUserDlg.setVisible(true);
862  }
863
864  private void newGroup()
865  {
866    if (newGroupDlg == null)
867    {
868      newGroupPanel = new NewGroupPanel();
869      newGroupPanel.setInfo(getInfo());
870      /* First argument: Component to associate the target with Second argument: DropTargetListener */
871      newGroupDlg = new GenericDialog(Utilities.getFrame(this), newGroupPanel);
872      Utilities.centerGoldenMean(newGroupDlg,
873          Utilities.getParentDialog(this));
874    }
875    TreePath[] paths = treePane.getTree().getSelectionPaths();
876    BasicNode parentNode = null;
877    if (paths != null && paths.length == 1)
878    {
879      TreePath path = paths[0];
880      parentNode = (BasicNode)path.getLastPathComponent();
881    }
882    newGroupPanel.setParent(parentNode, controller);
883    newGroupDlg.setVisible(true);
884  }
885
886  private void newOrganizationalUnit()
887  {
888    if (newOUDlg == null)
889    {
890      newOUPanel = new NewOrganizationalUnitPanel();
891      newOUPanel.setInfo(getInfo());
892      newOUDlg = new GenericDialog(Utilities.getFrame(this), newOUPanel);
893      Utilities.centerGoldenMean(newOUDlg,
894          Utilities.getParentDialog(this));
895    }
896    TreePath[] paths = treePane.getTree().getSelectionPaths();
897    BasicNode parentNode = null;
898    if (paths != null && paths.length == 1)
899    {
900      TreePath path = paths[0];
901      parentNode = (BasicNode)path.getLastPathComponent();
902    }
903    newOUPanel.setParent(parentNode, controller);
904    newOUDlg.setVisible(true);
905  }
906
907  private void newOrganization()
908  {
909    if (newOrganizationDlg == null)
910    {
911      newOrganizationPanel = new NewOrganizationPanel();
912      newOrganizationPanel.setInfo(getInfo());
913      newOrganizationDlg = new GenericDialog(Utilities.getFrame(this),
914          newOrganizationPanel);
915      Utilities.centerGoldenMean(newOrganizationDlg,
916          Utilities.getParentDialog(this));
917    }
918    TreePath[] paths = treePane.getTree().getSelectionPaths();
919    BasicNode parentNode = null;
920    if (paths != null && paths.length == 1)
921    {
922      TreePath path = paths[0];
923      parentNode = (BasicNode)path.getLastPathComponent();
924    }
925    newOrganizationPanel.setParent(parentNode, controller);
926    newOrganizationDlg.setVisible(true);
927  }
928
929  private void newDomain()
930  {
931    if (newDomainDlg == null)
932    {
933      newDomainPanel = new NewDomainPanel();
934      newDomainPanel.setInfo(getInfo());
935      newDomainDlg =
936        new GenericDialog(Utilities.getFrame(this), newDomainPanel);
937      Utilities.centerGoldenMean(newDomainDlg,
938          Utilities.getParentDialog(this));
939    }
940    TreePath[] paths = treePane.getTree().getSelectionPaths();
941    BasicNode parentNode = null;
942    if (paths != null && paths.length == 1)
943    {
944      TreePath path = paths[0];
945      parentNode = (BasicNode)path.getLastPathComponent();
946    }
947    newDomainPanel.setParent(parentNode, controller);
948    newDomainDlg.setVisible(true);
949  }
950
951  private void newEntryFromLDIF()
952  {
953    if (newEntryFromLDIFDlg == null)
954    {
955      newEntryFromLDIFPanel = new NewEntryFromLDIFPanel();
956      newEntryFromLDIFPanel.setInfo(getInfo());
957      newEntryFromLDIFDlg = new GenericDialog(Utilities.getFrame(this),
958          newEntryFromLDIFPanel);
959      Utilities.centerGoldenMean(newEntryFromLDIFDlg,
960          Utilities.getParentDialog(this));
961    }
962    TreePath[] paths = treePane.getTree().getSelectionPaths();
963    BasicNode parentNode = null;
964    if (paths != null && paths.length == 1)
965    {
966      TreePath path = paths[0];
967      parentNode = (BasicNode)path.getLastPathComponent();
968    }
969    newEntryFromLDIFPanel.setParent(parentNode, controller);
970    newEntryFromLDIFDlg.setVisible(true);
971  }
972
973  private void duplicateEntry()
974  {
975    duplicateEntryDlg = null;
976    if (duplicateEntryDlg == null)
977    {
978      if (duplicateEntryPanel == null)
979      {
980        duplicateEntryPanel = new DuplicateEntryPanel();
981        duplicateEntryPanel.setInfo(getInfo());
982      }
983      duplicateEntryDlg = new GenericDialog(Utilities.getFrame(this),
984          duplicateEntryPanel);
985      Utilities.centerGoldenMean(duplicateEntryDlg,
986          Utilities.getParentDialog(this));
987    }
988    TreePath[] paths = treePane.getTree().getSelectionPaths();
989    BasicNode node = null;
990    if (paths != null && paths.length == 1)
991    {
992      TreePath path = paths[0];
993      node = (BasicNode)path.getLastPathComponent();
994    }
995    duplicateEntryPanel.setEntryToDuplicate(node, controller);
996    duplicateEntryDlg.setVisible(true);
997  }
998
999  private void deleteClicked()
1000  {
1001    ArrayList<LocalizableMessage> errors = new ArrayList<>();
1002    TreePath[] paths = treePane.getTree().getSelectionPaths();
1003
1004    if (paths != null && paths.length > 0)
1005    {
1006      ProgressDialog dlg = new ProgressDialog(
1007          Utilities.createFrame(),
1008          Utilities.getParentDialog(this),
1009          INFO_CTRL_PANEL_DELETE_SELECTED_ENTRIES_TITLE.get(), getInfo());
1010      DeleteEntryTask newTask = new DeleteEntryTask(getInfo(), dlg, paths,
1011          controller);
1012      for (Task task : getInfo().getTasks())
1013      {
1014        task.canLaunch(newTask, errors);
1015      }
1016      if (errors.isEmpty())
1017      {
1018        if (displayConfirmationDialog(
1019            INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(),
1020            INFO_CTRL_PANEL_DELETE_ENTRIES_CONFIRMATION_DETAILS.get()))
1021        {
1022          launchOperation(newTask,
1023              INFO_CTRL_PANEL_DELETING_ENTRIES_SUMMARY.get(),
1024              INFO_CTRL_PANEL_DELETING_ENTRIES_COMPLETE.get(),
1025              INFO_CTRL_PANEL_DELETING_ENTRIES_SUCCESSFUL.get(),
1026              ERR_CTRL_PANEL_DELETING_ENTRIES_ERROR_SUMMARY.get(),
1027              ERR_CTRL_PANEL_DELETING_ENTRIES_ERROR_DETAILS.get(),
1028              null,
1029              dlg);
1030          dlg.setVisible(true);
1031        }
1032      }
1033    }
1034  }
1035
1036  private void copyDN()
1037  {
1038    ClipboardOwner owner = new ClipboardOwner()
1039    {
1040      @Override
1041      public void lostOwnership( Clipboard aClipboard,
1042          Transferable aContents) {
1043        //do nothing
1044      }
1045    };
1046    Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
1047    TreePath[] paths = treePane.getTree().getSelectionPaths();
1048    if (paths != null)
1049    {
1050      StringBuilder sb = new StringBuilder();
1051      for (TreePath path : paths)
1052      {
1053        BasicNode node = (BasicNode)path.getLastPathComponent();
1054        if (sb.length() > 0)
1055        {
1056          sb.append("\n");
1057        }
1058        sb.append(node.getDN());
1059      }
1060      StringSelection stringSelection = new StringSelection(sb.toString());
1061      clipboard.setContents(stringSelection, owner);
1062    }
1063  }
1064
1065  private void addToGroup()
1066  {
1067    TreePath[] paths = treePane.getTree().getSelectionPaths();
1068    if (paths != null)
1069    {
1070      LinkedHashSet<DN> dns = new LinkedHashSet<>();
1071      for (TreePath path : paths)
1072      {
1073        BasicNode node = (BasicNode)path.getLastPathComponent();
1074        dns.add(DN.valueOf(node.getDN()));
1075      }
1076      if (addToGroupDlg == null)
1077      {
1078        addToGroupPanel = new AddToGroupPanel();
1079        addToGroupPanel.setInfo(getInfo());
1080        addToGroupDlg = new GenericDialog(Utilities.getFrame(this),
1081            addToGroupPanel);
1082        Utilities.centerGoldenMean(addToGroupDlg,
1083            Utilities.getParentDialog(this));
1084      }
1085      addToGroupPanel.setEntriesToAdd(dns);
1086      addToGroupDlg.setVisible(true);
1087    }
1088  }
1089
1090  private void newWindow()
1091  {
1092    BrowseEntriesPanel panel = new BrowseEntriesPanel();
1093    panel.setDisposeOnClose(true);
1094    panel.setInfo(getInfo());
1095    GenericFrame frame = new GenericFrame(panel);
1096
1097    Utilities.centerGoldenMean(frame, Utilities.getFrame(this));
1098
1099    frame.setVisible(true);
1100  }
1101
1102  /** The specific menu bar of this panel. */
1103  private class BrowseMenuBar extends GenericMenuBar
1104  {
1105    private static final long serialVersionUID = 505187832236882370L;
1106    private JMenuItem deleteMenuItem;
1107    private JMenuItem copyDNMenuItem;
1108    private JMenuItem addToGroupMenuItem;
1109    private JMenuItem resetPasswordMenuItem;
1110    private JMenuItem newUserMenuItem;
1111    private JMenuItem newGroupMenuItem;
1112    private JMenuItem newOUMenuItem;
1113    private JMenuItem newOrganizationMenuItem;
1114    private JMenuItem newDomainMenuItem;
1115    private JMenuItem newEntryFromLDIFMenuItem;
1116    private JMenuItem duplicateEntryMenuItem;
1117    private JMenuItem deleteBaseDNMenuItem;
1118    private JMenuItem deleteBackendMenuItem;
1119
1120    /**
1121     * Constructor.
1122     * @param info the control panel info.
1123     */
1124    private BrowseMenuBar(ControlPanelInfo info)
1125    {
1126      super(info);
1127      add(createFileMenuBar());
1128      add(createEntriesMenuBar());
1129      add(createViewMenuBar());
1130      add(createHelpMenuBar());
1131    }
1132
1133    /**
1134     * Creates the file menu bar.
1135     * @return the file menu bar.
1136     */
1137    private JMenu createFileMenuBar()
1138    {
1139      JMenu menu = Utilities.createMenu(INFO_CTRL_PANEL_FILE_MENU.get(),
1140          INFO_CTRL_PANEL_FILE_MENU_DESCRIPTION.get());
1141      menu.setMnemonic(KeyEvent.VK_F);
1142      JMenuItem newWindow = Utilities.createMenuItem(
1143          INFO_CTRL_PANEL_NEW_BROWSER_WINDOW_MENU.get());
1144      newWindow.addActionListener(new ActionListener()
1145      {
1146        @Override
1147        public void actionPerformed(ActionEvent ev)
1148        {
1149          newWindow();
1150        }
1151      });
1152      menu.add(newWindow);
1153      menu.add(new JSeparator());
1154      JMenuItem close = Utilities.createMenuItem(
1155          INFO_CTRL_PANEL_CLOSE_MENU.get());
1156      close.addActionListener(new ActionListener()
1157      {
1158        @Override
1159        public void actionPerformed(ActionEvent ev)
1160        {
1161          closeClicked();
1162        }
1163      });
1164      menu.add(close);
1165      return menu;
1166    }
1167
1168    /**
1169     * Creates the view menu bar.
1170     * @return the view menu bar.
1171     */
1172    private JMenu createViewMenuBar()
1173    {
1174      JMenu menu = Utilities.createMenu(
1175          INFO_CTRL_PANEL_VIEW_MENU.get(),
1176          INFO_CTRL_PANEL_VIEW_MENU_DESCRIPTION.get());
1177      menu.setMnemonic(KeyEvent.VK_V);
1178      LocalizableMessage[] labels = {
1179          INFO_CTRL_PANEL_SIMPLIFIED_VIEW_MENU.get(),
1180          INFO_CTRL_PANEL_ATTRIBUTE_VIEW_MENU.get(),
1181          INFO_CTRL_PANEL_LDIF_VIEW_MENU.get()
1182      };
1183      final LDAPEntryPanel.View[] views = {
1184          LDAPEntryPanel.View.SIMPLIFIED_VIEW,
1185          LDAPEntryPanel.View.ATTRIBUTE_VIEW,
1186          LDAPEntryPanel.View.LDIF_VIEW
1187      };
1188      final JRadioButtonMenuItem[] menus =
1189        new JRadioButtonMenuItem[labels.length];
1190      ButtonGroup group = new ButtonGroup();
1191      for (int i=0; i<labels.length; i++)
1192      {
1193        menus[i] = new JRadioButtonMenuItem(labels[i].toString());
1194        menu.add(menus[i]);
1195        group.add(menus[i]);
1196      }
1197      ActionListener radioListener = new ActionListener()
1198      {
1199        private boolean ignoreEvents;
1200        private JRadioButtonMenuItem lastSelected = menus[0];
1201        @Override
1202        public void actionPerformed(ActionEvent ev)
1203        {
1204          if (ignoreEvents)
1205          {
1206            return;
1207          }
1208          for (int i=0; i<menus.length; i++)
1209          {
1210            if (menus[i].isSelected())
1211            {
1212              ignoreEvents = true;
1213              lastSelected.setSelected(true);
1214              if (entryPane.mustCheckUnsavedChanges())
1215              {
1216                switch (entryPane.checkUnsavedChanges())
1217                {
1218                case DO_NOT_SAVE:
1219                  break;
1220                case SAVE:
1221                  break;
1222                case CANCEL:
1223                  ignoreEvents = false;
1224                  return;
1225                }
1226              }
1227              lastSelected = menus[i];
1228              menus[i].setSelected(true);
1229              entryPane.setView(views[i]);
1230              ignoreEvents = false;
1231              break;
1232            }
1233          }
1234        }
1235      };
1236      for (int i=0; i<labels.length; i++)
1237      {
1238        menus[i].addActionListener(radioListener);
1239      }
1240      menus[0].setSelected(true);
1241
1242      // Add the referral and sort data menus
1243      menu.add(new JSeparator());
1244      final JCheckBoxMenuItem sortUserData =
1245        new JCheckBoxMenuItem(INFO_CTRL_PANEL_SORT_USER_DATA.get().toString());
1246      final JCheckBoxMenuItem followReferrals = new JCheckBoxMenuItem(
1247        INFO_CTRL_PANEL_FOLLOW_REFERRALS.get().toString());
1248      menu.add(sortUserData);
1249      menu.add(followReferrals);
1250      sortUserData.setSelected(entryPane.getController().isSorted());
1251      followReferrals.setSelected(
1252          entryPane.getController().getFollowReferrals());
1253      sortUserData.addActionListener(new ActionListener()
1254      {
1255        @Override
1256        public void actionPerformed(ActionEvent ev)
1257        {
1258          try
1259          {
1260            entryPane.getController().setSorted(sortUserData.isSelected());
1261          }
1262          catch (NamingException ne)
1263          {
1264            // Bug
1265            System.err.println("Unexpected error updating sorting.");
1266            ne.printStackTrace();
1267          }
1268        }
1269      });
1270      followReferrals.addActionListener(new ActionListener()
1271      {
1272        @Override
1273        public void actionPerformed(ActionEvent ev)
1274        {
1275          try
1276          {
1277            entryPane.getController().setFollowReferrals(
1278                followReferrals.isSelected());
1279          }
1280          catch (NamingException ne)
1281          {
1282            // Bug
1283            System.err.println("Unexpected error updating referral state.");
1284            ne.printStackTrace();
1285          }
1286        }
1287      });
1288      // Add the refresh menu
1289      menu.add(new JSeparator());
1290      final JMenuItem refresh =
1291        new JMenuItem(INFO_CTRL_PANEL_REFRESH_DATA.get().toString());
1292      menu.add(refresh);
1293      refresh.addActionListener(new ActionListener()
1294      {
1295        @Override
1296        public void actionPerformed(ActionEvent ev)
1297        {
1298          refreshClicked();
1299        }
1300      });
1301      return menu;
1302    }
1303
1304    /**
1305     * Creates the entries menu bar.
1306     * @return the entries menu bar.
1307     */
1308    private JMenu createEntriesMenuBar()
1309    {
1310      JMenu menu = Utilities.createMenu(
1311          INFO_CTRL_PANEL_ENTRIES_MENU.get(),
1312          INFO_CTRL_PANEL_ENTRIES_MENU_DESCRIPTION.get());
1313      menu.setMnemonic(KeyEvent.VK_E);
1314
1315      newUserMenuItem = Utilities.createMenuItem(
1316          INFO_CTRL_PANEL_NEW_USER_MENU.get());
1317      newUserMenuItem.addActionListener(new ActionListener()
1318      {
1319        @Override
1320        public void actionPerformed(ActionEvent ev)
1321        {
1322          newUser();
1323        }
1324      });
1325      newUserMenuItem.setEnabled(false);
1326      menu.add(newUserMenuItem);
1327
1328      newGroupMenuItem = Utilities.createMenuItem(
1329          INFO_CTRL_PANEL_NEW_GROUP_MENU.get());
1330      newGroupMenuItem.addActionListener(new ActionListener()
1331      {
1332        @Override
1333        public void actionPerformed(ActionEvent ev)
1334        {
1335          newGroup();
1336        }
1337      });
1338      newGroupMenuItem.setEnabled(false);
1339      menu.add(newGroupMenuItem);
1340
1341      newOUMenuItem = Utilities.createMenuItem(
1342          INFO_CTRL_PANEL_NEW_ORGANIZATIONAL_UNIT_MENU.get());
1343      newOUMenuItem.addActionListener(new ActionListener()
1344      {
1345        @Override
1346        public void actionPerformed(ActionEvent ev)
1347        {
1348          newOrganizationalUnit();
1349        }
1350      });
1351      newOUMenuItem.setEnabled(false);
1352      menu.add(newOUMenuItem);
1353
1354      newOrganizationMenuItem = Utilities.createMenuItem(
1355          INFO_CTRL_PANEL_NEW_ORGANIZATION_MENU.get());
1356      newOrganizationMenuItem.addActionListener(new ActionListener()
1357      {
1358        @Override
1359        public void actionPerformed(ActionEvent ev)
1360        {
1361          newOrganization();
1362        }
1363      });
1364      newOrganizationMenuItem.setEnabled(false);
1365      menu.add(newOrganizationMenuItem);
1366
1367      newDomainMenuItem = Utilities.createMenuItem(
1368          INFO_CTRL_PANEL_NEW_DOMAIN_MENU.get());
1369      newDomainMenuItem.addActionListener(new ActionListener()
1370      {
1371        @Override
1372        public void actionPerformed(ActionEvent ev)
1373        {
1374          newDomain();
1375        }
1376      });
1377      newDomainMenuItem.setEnabled(false);
1378      menu.add(newDomainMenuItem);
1379
1380      newEntryFromLDIFMenuItem = Utilities.createMenuItem(
1381          INFO_CTRL_PANEL_NEW_FROM_LDIF_MENU.get());
1382      newEntryFromLDIFMenuItem.addActionListener(new ActionListener()
1383      {
1384        @Override
1385        public void actionPerformed(ActionEvent ev)
1386        {
1387          newEntryFromLDIF();
1388        }
1389      });
1390      menu.add(newEntryFromLDIFMenuItem);
1391      menu.add(new JSeparator());
1392      resetPasswordMenuItem = Utilities.createMenuItem(
1393          INFO_CTRL_PANEL_RESET_USER_PASSWORD_MENU.get());
1394      resetPasswordMenuItem.addActionListener(new ActionListener()
1395      {
1396        @Override
1397        public void actionPerformed(ActionEvent ev)
1398        {
1399          resetUserPassword();
1400        }
1401      });
1402      resetPasswordMenuItem.setEnabled(false);
1403      menu.add(resetPasswordMenuItem);
1404
1405      addToGroupMenuItem = Utilities.createMenuItem(
1406          INFO_CTRL_PANEL_ADD_TO_GROUP_MENU.get());
1407      addToGroupMenuItem.addActionListener(new ActionListener()
1408      {
1409        @Override
1410        public void actionPerformed(ActionEvent ev)
1411        {
1412          addToGroup();
1413        }
1414      });
1415      addToGroupMenuItem.setEnabled(false);
1416      menu.add(addToGroupMenuItem);
1417
1418      menu.add(new JSeparator());
1419
1420      duplicateEntryMenuItem = Utilities.createMenuItem(
1421          INFO_CTRL_PANEL_DUPLICATE_ENTRY_MENU.get());
1422      duplicateEntryMenuItem.addActionListener(new ActionListener()
1423      {
1424        @Override
1425        public void actionPerformed(ActionEvent ev)
1426        {
1427          duplicateEntry();
1428        }
1429      });
1430      duplicateEntryMenuItem.setEnabled(false);
1431      menu.add(duplicateEntryMenuItem);
1432
1433      copyDNMenuItem = Utilities.createMenuItem(
1434          INFO_CTRL_PANEL_COPY_DN_MENU.get());
1435      copyDNMenuItem.addActionListener(new ActionListener()
1436      {
1437        @Override
1438        public void actionPerformed(ActionEvent ev)
1439        {
1440          copyDN();
1441        }
1442      });
1443      copyDNMenuItem.setEnabled(false);
1444      menu.add(copyDNMenuItem);
1445      menu.add(new JSeparator());
1446      deleteMenuItem = Utilities.createMenuItem(
1447          INFO_CTRL_PANEL_DELETE_ENTRY_MENU.get());
1448      deleteMenuItem.addActionListener(new ActionListener()
1449      {
1450        @Override
1451        public void actionPerformed(ActionEvent ev)
1452        {
1453          deleteClicked();
1454        }
1455      });
1456      deleteMenuItem.setEnabled(false);
1457      menu.add(deleteMenuItem);
1458      menu.add(new JSeparator());
1459      deleteBaseDNMenuItem = Utilities.createMenuItem(
1460          INFO_CTRL_PANEL_DELETE_BASE_DN_MENU.get());
1461      deleteBaseDNMenuItem.addActionListener(new ActionListener()
1462      {
1463        @Override
1464        public void actionPerformed(ActionEvent ev)
1465        {
1466          deleteBaseDN();
1467        }
1468      });
1469      deleteBaseDNMenuItem.setEnabled(false);
1470      menu.add(deleteBaseDNMenuItem);
1471
1472      deleteBackendMenuItem = Utilities.createMenuItem(
1473          INFO_CTRL_PANEL_DELETE_BACKEND_MENU.get());
1474      deleteBackendMenuItem.addActionListener(new ActionListener()
1475      {
1476        @Override
1477        public void actionPerformed(ActionEvent ev)
1478        {
1479          deleteBackend();
1480        }
1481      });
1482      deleteBackendMenuItem.setEnabled(false);
1483      menu.add(deleteBackendMenuItem);
1484      return menu;
1485    }
1486  }
1487
1488  private boolean isInterruptedException(Throwable t)
1489  {
1490    boolean isInterruptedException = false;
1491    isInterruptedException = t instanceof java.io.InterruptedIOException ||
1492    t instanceof InterruptedNamingException;
1493    while (t != null && !isInterruptedException)
1494    {
1495      t = t.getCause();
1496      isInterruptedException = t instanceof java.io.InterruptedIOException ||
1497      t instanceof InterruptedNamingException;
1498    }
1499    return isInterruptedException;
1500  }
1501
1502  private void refreshClicked()
1503  {
1504    // Refresh the contents of the selected entry.
1505    TreePath[] paths = treePane.getTree().getSelectionPaths();
1506    if (paths != null && paths.length == 1)
1507    {
1508      if (entryPane.mustCheckUnsavedChanges())
1509      {
1510        switch (entryPane.checkUnsavedChanges())
1511        {
1512        case DO_NOT_SAVE:
1513          break;
1514        case SAVE:
1515          break;
1516        case CANCEL:
1517          // Do nothing.
1518          return;
1519        }
1520      }
1521      updateRightPane(paths);
1522    }
1523    entryPane.getController().startRefresh(null);
1524  }
1525}