merged 'add existing library' and 'add new library' actions in classpath editor
[idea/community.git] / java / idea-ui / src / com / intellij / openapi / roots / ui / configuration / classpath / ClasspathPanelImpl.java
1 /*
2  * Copyright 2004-2005 Alexey Efimov
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.openapi.roots.ui.configuration.classpath;
17
18 import com.intellij.openapi.actionSystem.*;
19 import com.intellij.openapi.application.ApplicationManager;
20 import com.intellij.openapi.application.ex.ApplicationEx;
21 import com.intellij.openapi.diagnostic.Logger;
22 import com.intellij.openapi.module.Module;
23 import com.intellij.openapi.module.StdModuleTypes;
24 import com.intellij.openapi.project.Project;
25 import com.intellij.openapi.project.ProjectBundle;
26 import com.intellij.openapi.projectRoots.Sdk;
27 import com.intellij.openapi.roots.*;
28 import com.intellij.openapi.roots.libraries.Library;
29 import com.intellij.openapi.roots.libraries.LibraryTable;
30 import com.intellij.openapi.roots.ui.configuration.LibraryTableModifiableModelProvider;
31 import com.intellij.openapi.roots.ui.configuration.ModuleConfigurationState;
32 import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
33 import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable;
34 import com.intellij.openapi.roots.ui.configuration.dependencyAnalysis.AnalyzeDependenciesDialog;
35 import com.intellij.openapi.roots.ui.configuration.libraryEditor.ChooseModulesDialog;
36 import com.intellij.openapi.roots.ui.configuration.libraryEditor.EditExistingLibraryDialog;
37 import com.intellij.openapi.roots.ui.configuration.projectRoot.FindUsagesInProjectStructureActionBase;
38 import com.intellij.openapi.roots.ui.configuration.projectRoot.ModuleStructureConfigurable;
39 import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext;
40 import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.LibraryProjectStructureElement;
41 import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ModuleProjectStructureElement;
42 import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement;
43 import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.SdkProjectStructureElement;
44 import com.intellij.openapi.roots.ui.util.CellAppearance;
45 import com.intellij.openapi.roots.ui.util.OrderEntryCellAppearanceUtils;
46 import com.intellij.openapi.ui.Messages;
47 import com.intellij.openapi.ui.popup.JBPopup;
48 import com.intellij.openapi.ui.popup.JBPopupFactory;
49 import com.intellij.openapi.ui.popup.PopupStep;
50 import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
51 import com.intellij.openapi.wm.IdeFocusManager;
52 import com.intellij.ui.*;
53 import com.intellij.ui.awt.RelativePoint;
54 import com.intellij.util.EventDispatcher;
55 import com.intellij.util.ui.Table;
56 import org.jetbrains.annotations.NotNull;
57
58 import javax.swing.*;
59 import javax.swing.border.Border;
60 import javax.swing.event.ListSelectionEvent;
61 import javax.swing.event.ListSelectionListener;
62 import javax.swing.table.TableCellRenderer;
63 import javax.swing.table.TableColumn;
64 import java.awt.*;
65 import java.awt.event.*;
66 import java.util.ArrayList;
67 import java.util.HashSet;
68 import java.util.List;
69 import java.util.Set;
70
71 public class ClasspathPanelImpl extends JPanel implements ClasspathPanel {
72   private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.ui.configuration.classpath.ClasspathPanel");
73
74   private final Table myEntryTable;
75   private final ClasspathTableModel myModel;
76   private final EventDispatcher<OrderPanelListener> myListeners = EventDispatcher.create(OrderPanelListener.class);
77   private List<AddItemPopupAction<?>> myPopupActions = null;
78   private JButton myEditButton;
79   private final ModuleConfigurationState myState;
80
81   public ClasspathPanelImpl(ModuleConfigurationState state) {
82     super(new BorderLayout());
83
84     myState = state;
85     myModel = new ClasspathTableModel(state);
86     myEntryTable = new Table(myModel);
87     myEntryTable.setShowGrid(false);
88     myEntryTable.setDragEnabled(false);
89     myEntryTable.setShowHorizontalLines(false);
90     myEntryTable.setShowVerticalLines(false);
91     myEntryTable.setIntercellSpacing(new Dimension(0, 0));
92
93     myEntryTable.setDefaultRenderer(ClasspathTableItem.class, new TableItemRenderer());
94     myEntryTable.setDefaultRenderer(Boolean.class, new ExportFlagRenderer(myEntryTable.getDefaultRenderer(Boolean.class)));
95
96     JComboBox scopeEditor = new JComboBox(new EnumComboBoxModel<DependencyScope>(DependencyScope.class));
97     myEntryTable.setDefaultEditor(DependencyScope.class, new DefaultCellEditor(scopeEditor));
98     myEntryTable.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
99
100     new SpeedSearchBase<Table>(myEntryTable) {
101       public int getSelectedIndex() {
102         return myEntryTable.getSelectedRow();
103       }
104
105       @Override
106       protected int convertIndexToModel(int viewIndex) {
107         return myEntryTable.convertRowIndexToModel(viewIndex);
108       }
109
110       public Object[] getAllElements() {
111         final int count = myModel.getRowCount();
112         Object[] elements = new Object[count];
113         for (int idx = 0; idx < count; idx++) {
114           elements[idx] = myModel.getItemAt(idx);
115         }
116         return elements;
117       }
118
119       public String getElementText(Object element) {
120         return getCellAppearance((ClasspathTableItem)element, false).getText();
121       }
122
123       public void selectElement(Object element, String selectedText) {
124         final int count = myModel.getRowCount();
125         for (int row = 0; row < count; row++) {
126           if (element.equals(myModel.getItemAt(row))) {
127             final int viewRow = myEntryTable.convertRowIndexToView(row);
128             myEntryTable.getSelectionModel().setSelectionInterval(viewRow, viewRow);
129             TableUtil.scrollSelectionToVisible(myEntryTable);
130             break;
131           }
132         }
133       }
134     };
135
136
137     setFixedColumnWidth(ClasspathTableModel.EXPORT_COLUMN, ClasspathTableModel.EXPORT_COLUMN_NAME);
138     setFixedColumnWidth(ClasspathTableModel.SCOPE_COLUMN, DependencyScope.COMPILE.toString() + "     ");  // leave space for combobox border
139
140     myEntryTable.registerKeyboardAction(
141       new ActionListener() {
142         public void actionPerformed(ActionEvent e) {
143           final int[] selectedRows = myEntryTable.getSelectedRows();
144           boolean currentlyMarked = true;
145           for (final int selectedRow : selectedRows) {
146             final ClasspathTableItem item = myModel.getItemAt(myEntryTable.convertRowIndexToModel(selectedRow));
147             if (selectedRow < 0 || !item.isExportable()) {
148               return;
149             }
150             currentlyMarked &= item.isExported();
151           }
152           for (final int selectedRow : selectedRows) {
153             myModel.getItemAt(myEntryTable.convertRowIndexToModel(selectedRow)).setExported(!currentlyMarked);
154           }
155           myModel.fireTableDataChanged();
156           TableUtil.selectRows(myEntryTable, selectedRows);
157         }
158       },
159       KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0),
160       WHEN_FOCUSED
161     );
162
163     add(ScrollPaneFactory.createScrollPane(myEntryTable), BorderLayout.CENTER);
164     add(createButtonsBlock(), BorderLayout.EAST);
165
166     if (myEntryTable.getRowCount() > 0) {
167       myEntryTable.getSelectionModel().setSelectionInterval(0,0);
168     }
169
170     myEntryTable.addMouseListener(new MouseAdapter() {
171       public void mouseClicked(MouseEvent e) {
172         if (e.getClickCount() == 2){
173           navigate(true);
174         }
175       }
176     });
177
178     DefaultActionGroup actionGroup = new DefaultActionGroup();
179     final AnAction navigateAction = new AnAction(ProjectBundle.message("classpath.panel.navigate.action.text")) {
180       public void actionPerformed(AnActionEvent e) {
181         navigate(false);
182       }
183
184       public void update(AnActionEvent e) {
185         final Presentation presentation = e.getPresentation();
186         presentation.setEnabled(false);
187         if (myEntryTable.getSelectedRowCount() != 1) return;
188         final OrderEntry entry = myModel.getItemAt(myEntryTable.getSelectedRow()).getEntry();
189         if (entry != null && entry.isValid()){
190           if (!(entry instanceof ModuleSourceOrderEntry)){
191             presentation.setEnabled(true);
192           }
193         }
194       }
195     };
196     navigateAction.registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_EDIT_SOURCE).getShortcutSet(), myEntryTable);
197     actionGroup.add(navigateAction);
198     actionGroup.add(new MyFindUsagesAction());
199     PopupHandler.installPopupHandler(myEntryTable, actionGroup, ActionPlaces.UNKNOWN, ActionManager.getInstance());
200   }
201
202   private void setFixedColumnWidth(final int columnIndex, final String textToMeasure) {
203     final FontMetrics fontMetrics = myEntryTable.getFontMetrics(myEntryTable.getFont());
204     final int width = fontMetrics.stringWidth(" " + textToMeasure + " ") + 4;
205     final TableColumn checkboxColumn = myEntryTable.getTableHeader().getColumnModel().getColumn(columnIndex);
206     checkboxColumn.setWidth(width);
207     checkboxColumn.setPreferredWidth(width);
208     checkboxColumn.setMaxWidth(width);
209     checkboxColumn.setMinWidth(width);
210   }
211
212   private void navigate(boolean openLibraryEditor) {
213     final int selectedRow = myEntryTable.getSelectedRow();
214     final OrderEntry entry = myModel.getItemAt(selectedRow).getEntry();
215     final ProjectStructureConfigurable rootConfigurable = ProjectStructureConfigurable.getInstance(myState.getProject());
216     if (entry instanceof ModuleOrderEntry){
217       Module module = ((ModuleOrderEntry)entry).getModule();
218       if (module != null) {
219         rootConfigurable.select(module.getName(), null, true);
220       }
221     }
222     else if (entry instanceof LibraryOrderEntry){
223       if (!openLibraryEditor) {
224         rootConfigurable.select((LibraryOrderEntry)entry, true);
225       }
226       else {
227         myEditButton.doClick();
228       }
229     }
230     else if (entry instanceof JdkOrderEntry) {
231       Sdk jdk = ((JdkOrderEntry)entry).getJdk();
232       if (jdk != null) {
233         rootConfigurable.select(jdk, true);
234       }
235     }
236   }
237
238
239   private JComponent createButtonsBlock() {
240     final boolean isAnalyzeShown = ((ApplicationEx)ApplicationManager.getApplication()).isInternal();
241
242     final JButton addButton = new JButton(ProjectBundle.message("button.add"));
243     final JButton removeButton = new JButton(ProjectBundle.message("button.remove"));
244     myEditButton = new JButton(ProjectBundle.message("button.edit"));
245     final JButton upButton = new JButton(ProjectBundle.message("button.move.up"));
246     final JButton downButton = new JButton(ProjectBundle.message("button.move.down"));
247     final JButton analyzeButton = isAnalyzeShown ? new JButton(ProjectBundle.message("classpath.panel.analyze")) : null;
248
249     final JPanel panel = new JPanel(new GridBagLayout());
250     panel.add(addButton, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(2, 2, 0, 0), 0, 0));
251     panel.add(removeButton, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(2, 2, 0, 0), 0, 0));
252     panel.add(myEditButton, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(2, 2, 0, 0), 0, 0));
253     panel.add(upButton, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(2, 2, 0, 0), 0, 0));
254     panel.add(downButton, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, isAnalyzeShown ? 0.0 : 0.1, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(2, 2, 0, 0), 0, 0));
255     if( isAnalyzeShown) {
256       panel.add(analyzeButton, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(2, 2, 0, 0), 0, 0));
257     }
258
259     myEntryTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
260       public void valueChanged(ListSelectionEvent e) {
261         if (e.getValueIsAdjusting()) {
262           return;
263         }
264         final int[] selectedRows = myEntryTable.getSelectedRows();
265         boolean removeButtonEnabled = true;
266         int minRow = myEntryTable.getRowCount() + 1;
267         int maxRow = -1;
268         for (final int selectedRow : selectedRows) {
269           minRow = Math.min(minRow, selectedRow);
270           maxRow = Math.max(maxRow, selectedRow);
271           final ClasspathTableItem item = myModel.getItemAt(selectedRow);
272           if (!item.isRemovable()) {
273             removeButtonEnabled = false;
274           }
275         }
276         upButton.setEnabled(minRow > 0 && minRow < myEntryTable.getRowCount());
277         downButton.setEnabled(maxRow >= 0 && maxRow < myEntryTable.getRowCount() - 1);
278         removeButton.setEnabled(removeButtonEnabled);
279         ClasspathTableItem selectedItem = selectedRows.length == 1 ? myModel.getItemAt(selectedRows[0]) : null;
280         myEditButton.setEnabled(selectedItem != null && selectedItem.isEditable());
281       }
282     });
283
284     upButton.addActionListener(new ClasspathPanelAction(this) {
285       @Override
286       public void run() {
287         moveSelectedRows(-1);
288       }
289     });
290     downButton.addActionListener(new ClasspathPanelAction(this) {
291       @Override
292       public void run() {
293         moveSelectedRows(+1);
294       }
295     });
296
297     if(isAnalyzeShown) {
298       analyzeButton.addActionListener(new ClasspathPanelAction(this) {
299         @Override
300         public void run() {
301           AnalyzeDependenciesDialog.show(getRootModel().getModule());
302         }
303       });
304     }
305
306     addKeyboardShortcut(myEntryTable, removeButton, KeyEvent.VK_DELETE, 0);
307     addKeyboardShortcut(myEntryTable, addButton, KeyEvent.VK_INSERT, 0);
308     addKeyboardShortcut(myEntryTable, upButton, KeyEvent.VK_UP, KeyEvent.CTRL_DOWN_MASK);
309     addKeyboardShortcut(myEntryTable, downButton, KeyEvent.VK_DOWN, KeyEvent.CTRL_DOWN_MASK);
310
311     addButton.addActionListener(new ActionListener() {
312       @Override
313       public void actionPerformed(ActionEvent e) {
314         initPopupActions();
315         final JBPopup popup = JBPopupFactory.getInstance().createListPopup(new BaseListPopupStep<AddItemPopupAction<?>>(null, myPopupActions) {
316           @Override
317           public Icon getIconFor(AddItemPopupAction<?> aValue) {
318             return aValue.getIcon();
319           }
320
321           public boolean isMnemonicsNavigationEnabled() {
322             return true;
323           }
324           public PopupStep onChosen(final AddItemPopupAction<?> selectedValue, final boolean finalChoice) {
325             return doFinalStep(new Runnable() {
326               public void run() {
327                 selectedValue.execute();
328               }
329             });
330           }
331           @NotNull
332           public String getTextFor(AddItemPopupAction<?> value) {
333             return "&" + value.getIndex() + "  " + value.getTitle();
334           }
335         });
336         popup.showUnderneathOf(addButton);
337       }
338     });
339
340     removeButton.addActionListener(new ClasspathPanelAction(this) {
341       @Override
342       public void run() {
343         final List removedRows = TableUtil.removeSelectedItems(myEntryTable);
344         if (removedRows.isEmpty()) {
345           return;
346         }
347         for (final Object removedRow : removedRows) {
348           final ClasspathTableItem item = (ClasspathTableItem)((Object[])removedRow)[ClasspathTableModel.ITEM_COLUMN];
349           final OrderEntry orderEntry = item.getEntry();
350           if (orderEntry == null) {
351             continue;
352           }
353
354           getRootModel().removeOrderEntry(orderEntry);
355         }
356         final int[] selectedRows = myEntryTable.getSelectedRows();
357         myModel.fireTableDataChanged();
358         TableUtil.selectRows(myEntryTable, selectedRows);
359         final StructureConfigurableContext context = ModuleStructureConfigurable.getInstance(myState.getProject()).getContext();
360         context.getDaemonAnalyzer().queueUpdate(new ModuleProjectStructureElement(context, getRootModel().getModule()));
361       }
362     });
363
364     myEditButton.addActionListener(new ActionListener() {
365       public void actionPerformed(final ActionEvent e) {
366         final int row = myEntryTable.getSelectedRow();
367         final ClasspathTableItem item = myModel.getItemAt(row);
368         final OrderEntry entry = item.getEntry();
369         if (!(entry instanceof LibraryOrderEntry)) return;
370
371         final Library library = ((LibraryOrderEntry)entry).getLibrary();
372         if (library == null) {
373           return;
374         }
375         final LibraryTableModifiableModelProvider provider;
376         final LibraryTable table = library.getTable();
377         if (table == null) {
378           final LibraryTable moduleLibraryTable = getRootModel().getModuleLibraryTable();
379           provider = new LibraryTableModifiableModelProvider() {
380             public LibraryTable.ModifiableModel getModifiableModel() {
381               return moduleLibraryTable.getModifiableModel();
382             }
383
384           };
385         }
386         else {
387           provider = ProjectStructureConfigurable.getInstance(myState.getProject()).getContext().createModifiableModelProvider(table.getTableLevel());
388         }
389         EditExistingLibraryDialog dialog = EditExistingLibraryDialog.createDialog(ClasspathPanelImpl.this, provider, library, myState.getProject());
390         dialog.addFileChooserContext(LangDataKeys.MODULE_CONTEXT, getRootModel().getModule());
391         dialog.show();
392         myEntryTable.repaint();
393         ModuleStructureConfigurable.getInstance(myState.getProject()).getTree().repaint();
394       }
395     });
396     return panel;
397   }
398
399   private static void addKeyboardShortcut(final JComponent target, final JButton button, final int keyEvent, final int modifiers) {
400     target.registerKeyboardAction(
401       new ActionListener() {
402         public void actionPerformed(ActionEvent e) {
403           if (button.isEnabled()) {
404             button.doClick();
405           }
406         }
407       },
408       KeyStroke.getKeyStroke(keyEvent, modifiers),
409       WHEN_FOCUSED
410     );
411   }
412
413   @Override
414   public void runClasspathPanelAction(Runnable action) {
415     try {
416       disableModelUpdate();
417       action.run();
418     }
419     finally {
420       enableModelUpdate();
421       myEntryTable.requestFocus();
422     }
423   }
424
425   @Override
426   public void addItems(List<ClasspathTableItem> toAdd) {
427     for (ClasspathTableItem item : toAdd) {
428       myModel.addItem(item);
429     }
430     myModel.fireTableDataChanged();
431     final ListSelectionModel selectionModel = myEntryTable.getSelectionModel();
432     selectionModel.setSelectionInterval(myModel.getRowCount() - toAdd.size(), myModel.getRowCount() - 1);
433     TableUtil.scrollSelectionToVisible(myEntryTable);
434
435     final StructureConfigurableContext context = ModuleStructureConfigurable.getInstance(myState.getProject()).getContext();
436     context.getDaemonAnalyzer().queueUpdate(new ModuleProjectStructureElement(context, getRootModel().getModule()));
437   }
438
439   @Override
440   public ModifiableRootModel getRootModel() {
441     return myState.getRootModel();
442   }
443
444   @Override
445   public Project getProject() {
446     return myState.getProject();
447   }
448
449   @Override
450   public JComponent getComponent() {
451     return this;
452   }
453
454   public void rootsChanged() {
455     forceInitFromModel();
456   }
457
458   private void initPopupActions() {
459     if (myPopupActions == null) {
460       final StructureConfigurableContext context = ProjectStructureConfigurable.getInstance(myState.getProject()).getContext();
461       int actionIndex = 1;
462       final List<AddItemPopupAction<?>> actions = new ArrayList<AddItemPopupAction<?>>();
463       actions.add(new AddSingleEntryModuleLibraryAction(this, actionIndex++));
464       actions.add(new AddLibraryAction(this, actionIndex++, ProjectBundle.message("classpath.add.library.action"), context));
465       actions.add(new AddItemPopupAction<Module>(this, actionIndex, ProjectBundle.message("classpath.add.module.dependency.action"),
466                                                  StdModuleTypes.JAVA.getNodeIcon(false)) {
467           protected ClasspathTableItem createTableItem(final Module item) {
468             return ClasspathTableItem.createItem(getRootModel().addModuleOrderEntry(item));
469           }
470           protected ClasspathElementChooser<Module> createChooser() {
471             final List<Module> chooseItems = getDependencyModules();
472             if (chooseItems.isEmpty()) {
473               Messages.showMessageDialog(ClasspathPanelImpl.this, ProjectBundle.message("message.no.module.dependency.candidates"), getTitle(), Messages.getInformationIcon());
474               return null;
475             }
476             return new ModuleChooser(chooseItems, ProjectBundle.message("classpath.chooser.title.add.module.dependency"));
477           }
478         }
479       );
480
481       myPopupActions = actions;
482     }
483   }
484
485
486   private void enableModelUpdate() {
487     myInsideChange--;
488   }
489
490   private void disableModelUpdate() {
491     myInsideChange++;
492   }
493
494   public void addListener(OrderPanelListener listener) {
495     myListeners.addListener(listener);
496   }
497
498   public void removeListener(OrderPanelListener listener) {
499     myListeners.removeListener(listener);
500   }
501
502   private void moveSelectedRows(int increment) {
503     if (increment == 0) {
504       return;
505     }
506     if (myEntryTable.isEditing()){
507       myEntryTable.getCellEditor().stopCellEditing();
508     }
509     final ListSelectionModel selectionModel = myEntryTable.getSelectionModel();
510     for(int row = increment < 0? 0 : myModel.getRowCount() - 1; increment < 0? row < myModel.getRowCount() : row >= 0; row +=
511       increment < 0? +1 : -1){
512       if (selectionModel.isSelectedIndex(row)) {
513         final int newRow = moveRow(row, increment);
514         selectionModel.removeSelectionInterval(row, row);
515         selectionModel.addSelectionInterval(newRow, newRow);
516       }
517     }
518     myModel.fireTableRowsUpdated(0, myModel.getRowCount() - 1);
519     Rectangle cellRect = myEntryTable.getCellRect(selectionModel.getMinSelectionIndex(), 0, true);
520     if (cellRect != null) {
521       myEntryTable.scrollRectToVisible(cellRect);
522     }
523     myEntryTable.repaint();
524     myListeners.getMulticaster().entryMoved();
525   }
526
527   public void selectOrderEntry(@NotNull OrderEntry entry) {
528     for (int row = 0; row < myModel.getRowCount(); row++) {
529       if (entry.getPresentableName().equals(myModel.getItemAt(row).getEntry().getPresentableName())) {
530         myEntryTable.getSelectionModel().setSelectionInterval(row, row);
531         TableUtil.scrollSelectionToVisible(myEntryTable);
532       }
533     }
534     IdeFocusManager.getInstance(myState.getProject()).requestFocus(myEntryTable, true);
535   }
536
537   private int moveRow(final int row, final int increment) {
538     int newIndex = Math.abs(row + increment) % myModel.getRowCount();
539     final ClasspathTableItem item = myModel.removeDataRow(row);
540     myModel.addItemAt(item, newIndex);
541     return newIndex;
542   }
543
544   public void stopEditing() {
545     TableUtil.stopEditing(myEntryTable);
546   }
547
548   public List<OrderEntry> getEntries() {
549     final int count = myModel.getRowCount();
550     final List<OrderEntry> entries = new ArrayList<OrderEntry>(count);
551     for (int row = 0; row < count; row++) {
552       final OrderEntry entry = myModel.getItemAt(row).getEntry();
553       if (entry != null) {
554         entries.add(entry);
555       }
556     }
557     return entries;
558   }
559
560   private int myInsideChange = 0;
561   public void initFromModel() {
562     if (myInsideChange == 0) {
563       forceInitFromModel();
564     }
565   }
566
567   public void forceInitFromModel() {
568     final int[] selection = myEntryTable.getSelectedRows();
569     myModel.clear();
570     myModel.init();
571     myModel.fireTableDataChanged();
572     TableUtil.selectRows(myEntryTable, selection);
573   }
574
575   private List<Module> getDependencyModules() {
576     final int rowCount = myModel.getRowCount();
577     final Set<String> filtered = new HashSet<String>(rowCount);
578     for (int row = 0; row < rowCount; row++) {
579       final OrderEntry entry = myModel.getItemAt(row).getEntry();
580       if (entry instanceof ModuleOrderEntry) {
581         filtered.add(((ModuleOrderEntry)entry).getModuleName());
582       }
583     }
584     final ModulesProvider modulesProvider = myState.getModulesProvider();
585     final Module self = modulesProvider.getModule(getRootModel().getModule().getName());
586     filtered.add(self.getName());
587
588     final Module[] modules = modulesProvider.getModules();
589     final List<Module> elements = new ArrayList<Module>(modules.length);
590     for (final Module module : modules) {
591       if (!filtered.contains(module.getName())) {
592         elements.add(module);
593       }
594     }
595     return elements;
596   }
597
598
599   private static CellAppearance getCellAppearance(final ClasspathTableItem item, final boolean selected) {
600     if (item instanceof InvalidJdkItem) {
601       return OrderEntryCellAppearanceUtils.forJdk(null, false, selected);
602     }
603     else {
604       return OrderEntryCellAppearanceUtils.forOrderEntry(item.getEntry(), selected);
605     }
606   }
607
608   private static class TableItemRenderer extends ColoredTableCellRenderer {
609     private final Border NO_FOCUS_BORDER = BorderFactory.createEmptyBorder(1, 1, 1, 1);
610
611     protected void customizeCellRenderer(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
612       setPaintFocusBorder(false);
613       setFocusBorderAroundIcon(true);
614       setBorder(NO_FOCUS_BORDER);
615       if (value instanceof ClasspathTableItem) {
616         getCellAppearance((ClasspathTableItem)value, selected).customize(this);
617       }
618     }
619   }
620
621   private static class ExportFlagRenderer implements TableCellRenderer {
622     private final TableCellRenderer myDelegate;
623     private final JPanel myBlankPanel;
624
625     public ExportFlagRenderer(TableCellRenderer delegate) {
626       myDelegate = delegate;
627       myBlankPanel = new JPanel();
628     }
629
630     public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
631       if (!table.isCellEditable(row, column)) {
632         myBlankPanel.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
633         return myBlankPanel;
634       }
635       return myDelegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
636     }
637   }
638
639   private class ModuleChooser extends ChooseModulesDialog implements ClasspathElementChooser<Module> {
640     public ModuleChooser(final List<Module> items, final String title) {
641       super(ClasspathPanelImpl.this, items, title);
642     }
643
644     public void doChoose() {
645       show();
646     }
647
648     public void dispose() {
649       super.dispose();
650     }
651   }
652
653   private class MyFindUsagesAction extends FindUsagesInProjectStructureActionBase {
654     private MyFindUsagesAction() {
655       super(myEntryTable, myState.getProject());
656     }
657
658     protected boolean isEnabled() {
659       return getSelectedElement() != null;
660     }
661
662     protected ProjectStructureElement getSelectedElement() {
663       int row = myEntryTable.getSelectedRow();
664       if (0 <= row && row < myModel.getRowCount()) {
665         ClasspathTableItem item = myModel.getItemAt(row);
666         final OrderEntry entry = item.getEntry();
667         if (entry instanceof LibraryOrderEntry) {
668           final Library library = ((LibraryOrderEntry)entry).getLibrary();
669           if (library != null) {
670             return new LibraryProjectStructureElement(getContext(), library);
671           }
672         }
673         else if (entry instanceof ModuleOrderEntry) {
674           final Module module = ((ModuleOrderEntry)entry).getModule();
675           if (module != null) {
676             return new ModuleProjectStructureElement(getContext(), module);
677           }
678         }
679         else if (entry instanceof JdkOrderEntry) {
680           final Sdk jdk = ((JdkOrderEntry)entry).getJdk();
681           if (jdk != null) {
682             return new SdkProjectStructureElement(getContext(), jdk);
683           }
684         }
685       }
686       return null;
687     }
688
689     protected RelativePoint getPointToShowResults() {
690       Rectangle rect = myEntryTable.getCellRect(myEntryTable.getSelectedRow(), 1, false);
691       Point location = rect.getLocation();
692       location.y += rect.height;
693       return new RelativePoint(myEntryTable, location);
694     }
695   }
696
697 }