blob: aad3ad1d638500453886682de47f71b9c0bdcec3 [file] [log] [blame]
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.vcs.configurable;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.impl.DefaultVcsRootPolicy;
import com.intellij.openapi.vcs.impl.VcsDescriptor;
import com.intellij.openapi.vcs.roots.VcsRootErrorsFinder;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.*;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.labels.LinkLabel;
import com.intellij.ui.components.labels.LinkListener;
import com.intellij.ui.table.TableView;
import com.intellij.util.UriUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.*;
import com.intellij.xml.util.XmlStringUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.CompoundBorder;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.util.*;
import java.util.List;
import static com.intellij.openapi.vcs.VcsConfiguration.getInstance;
import static com.intellij.openapi.vcs.VcsConfiguration.ourMaximumFileForBaseRevisionSize;
import static com.intellij.util.ui.UIUtil.DEFAULT_HGAP;
import static com.intellij.util.ui.UIUtil.DEFAULT_VGAP;
/**
* @author yole
*/
public class VcsDirectoryConfigurationPanel extends JPanel implements Configurable {
private final Project myProject;
private final String myProjectMessage;
private final ProjectLevelVcsManager myVcsManager;
private final TableView<VcsDirectoryMapping> myDirectoryMappingTable;
private final ComboboxWithBrowseButton myVcsComboBox = new ComboboxWithBrowseButton();
private final List<ModuleVcsListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
private final MyDirectoryRenderer myDirectoryRenderer;
private final ColumnInfo<VcsDirectoryMapping, VcsDirectoryMapping> DIRECTORY;
private final JCheckBox myBaseRevisionTexts;
private ListTableModel<VcsDirectoryMapping> myModel;
private final Map<String, VcsDescriptor> myAllVcss;
private VcsContentAnnotationConfigurable myRecentlyChangedConfigurable;
private final boolean myIsDisabled;
private final VcsConfiguration myVcsConfiguration;
private final @NotNull Map<String, VcsRootChecker> myCheckers;
private JCheckBox myShowVcsRootErrorNotification;
private JCheckBox myShowChangedRecursively;
private final VcsLimitHistoryConfigurable myLimitHistory;
private final VcsUpdateInfoScopeFilterConfigurable myScopeFilterConfig;
private VcsCommitMessageMarginConfigurable myCommitMessageMarginConfigurable;
private class MyDirectoryRenderer extends ColoredTableCellRenderer {
private final Project myProject;
public MyDirectoryRenderer(Project project) {
myProject = project;
}
@Override
protected void customizeCellRenderer(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
if (value instanceof VcsDirectoryMapping) {
VcsDirectoryMapping mapping = (VcsDirectoryMapping)value;
if (mappingIsError(mapping)) {
setForeground(Color.RED);
}
if (mapping.isDefaultMapping()) {
append(VcsDirectoryMapping.PROJECT_CONSTANT);
return;
}
String directory = mapping.getDirectory();
VirtualFile baseDir = myProject.getBaseDir();
if (baseDir != null) {
final File directoryFile = new File(StringUtil.trimEnd(UriUtil.trimTrailingSlashes(directory), "\\") + "/");
File ioBase = new File(baseDir.getPath());
if (directoryFile.isAbsolute() && !FileUtil.isAncestor(ioBase, directoryFile, false)) {
append(new File(directory).getPath());
return;
}
String relativePath = FileUtil.getRelativePath(ioBase, directoryFile);
if (".".equals(relativePath) || relativePath == null) {
append(ioBase.getPath());
}
else {
append(relativePath);
append(" (" + ioBase + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES);
}
}
}
}
private boolean mappingIsError(VcsDirectoryMapping mapping) {
String vcs = mapping.getVcs();
VcsRootChecker checker = myCheckers.get(vcs);
return checker != null &&
(mapping.isDefaultMapping() ? !checker.isRoot(myProject.getBasePath()) : !checker.isRoot(mapping.getDirectory()));
}
}
private final ColumnInfo<VcsDirectoryMapping, String> VCS_SETTING =
new ColumnInfo<VcsDirectoryMapping, String>(VcsBundle.message("column.name.configure.vcses.vcs")) {
@Override
public String valueOf(final VcsDirectoryMapping object) {
return object.getVcs();
}
@Override
public boolean isCellEditable(final VcsDirectoryMapping o) {
return true;
}
@Override
public void setValue(final VcsDirectoryMapping o, final String aValue) {
Collection<AbstractVcs> activeVcses = getActiveVcses();
o.setVcs(aValue);
checkNotifyListeners(activeVcses);
}
@Override
public TableCellRenderer getRenderer(final VcsDirectoryMapping p0) {
return new ColoredTableCellRenderer() {
@Override
protected void customizeCellRenderer(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
final String vcsName = p0.getVcs();
String text;
if (vcsName.length() == 0) {
text = VcsBundle.message("none.vcs.presentation");
}
else {
final VcsDescriptor vcs = myAllVcss.get(vcsName);
if (vcs != null) {
text = vcs.getDisplayName();
}
else {
text = VcsBundle.message("unknown.vcs.presentation", vcsName);
}
}
append(text, new SimpleTextAttributes(SimpleTextAttributes.STYLE_PLAIN, table.getForeground()));
}
};
}
@Override
public TableCellEditor getEditor(final VcsDirectoryMapping o) {
return new AbstractTableCellEditor() {
@Override
public Object getCellEditorValue() {
final VcsDescriptor selectedVcs = (VcsDescriptor)myVcsComboBox.getComboBox().getSelectedItem();
return ((selectedVcs == null) || selectedVcs.isNone()) ? "" : selectedVcs.getName();
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
String vcsName = (String)value;
myVcsComboBox.getComboBox().setSelectedItem(myAllVcss.get(vcsName));
return myVcsComboBox;
}
};
}
@Nullable
@Override
public String getMaxStringValue() {
String maxString = null;
for (String name : myAllVcss.keySet()) {
if (maxString == null || maxString.length() < name.length()) {
maxString = name;
}
}
return maxString;
}
@Override
public int getAdditionalWidth() {
return DEFAULT_HGAP;
}
};
public VcsDirectoryConfigurationPanel(final Project project) {
myProject = project;
myVcsConfiguration = getInstance(myProject);
myProjectMessage = XmlStringUtil.wrapInHtml(StringUtil.escapeXml(VcsDirectoryMapping.PROJECT_CONSTANT) + " - " +
DefaultVcsRootPolicy.getInstance(myProject).getProjectConfigurationMessage(myProject)
.replace('\n', ' '));
myIsDisabled = myProject.isDefault();
myVcsManager = ProjectLevelVcsManager.getInstance(project);
final VcsDescriptor[] vcsDescriptors = myVcsManager.getAllVcss();
myAllVcss = new HashMap<String, VcsDescriptor>();
for (VcsDescriptor vcsDescriptor : vcsDescriptors) {
myAllVcss.put(vcsDescriptor.getName(), vcsDescriptor);
}
myDirectoryMappingTable = new TableView<VcsDirectoryMapping>();
myBaseRevisionTexts = new JCheckBox("Store on shelf base revision texts for files under DVCS");
myLimitHistory = new VcsLimitHistoryConfigurable(myProject);
myScopeFilterConfig = new VcsUpdateInfoScopeFilterConfigurable(myProject, myVcsConfiguration);
myCheckers = new HashMap<String, VcsRootChecker>();
updateRootCheckers();
setLayout(new BorderLayout());
add(createMainComponent());
myDirectoryRenderer = new MyDirectoryRenderer(myProject);
DIRECTORY = new ColumnInfo<VcsDirectoryMapping, VcsDirectoryMapping>(VcsBundle.message("column.info.configure.vcses.directory")) {
@Override
public VcsDirectoryMapping valueOf(final VcsDirectoryMapping mapping) {
return mapping;
}
@Override
public TableCellRenderer getRenderer(VcsDirectoryMapping vcsDirectoryMapping) {
return myDirectoryRenderer;
}
};
initializeModel();
final JComboBox comboBox = myVcsComboBox.getComboBox();
comboBox.setModel(buildVcsWrappersModel(myProject));
comboBox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(final ItemEvent e) {
if (myDirectoryMappingTable.isEditing()) {
myDirectoryMappingTable.stopEditing();
}
}
});
myVcsComboBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
final VcsDescriptor vcsWrapper = ((VcsDescriptor)comboBox.getSelectedItem());
new VcsConfigurationsDialog(project, comboBox, vcsWrapper).show();
}
});
myDirectoryMappingTable.setRowHeight(myVcsComboBox.getPreferredSize().height);
if (myIsDisabled) {
myDirectoryMappingTable.setEnabled(false);
}
}
private void updateRootCheckers() {
myCheckers.clear();
VcsRootChecker[] checkers = Extensions.getExtensions(VcsRootChecker.EXTENSION_POINT_NAME);
for (VcsRootChecker checker : checkers) {
VcsKey key = checker.getSupportedVcs();
AbstractVcs vcs = myVcsManager.findVcsByName(key.getName());
if (vcs == null) {
continue;
}
myCheckers.put(key.getName(), checker);
}
}
private void initializeModel() {
List<VcsDirectoryMapping> mappings = new ArrayList<VcsDirectoryMapping>();
for (VcsDirectoryMapping mapping : ProjectLevelVcsManager.getInstance(myProject).getDirectoryMappings()) {
mappings.add(new VcsDirectoryMapping(mapping.getDirectory(), mapping.getVcs(), mapping.getRootSettings()));
}
myModel = new ListTableModel<VcsDirectoryMapping>(new ColumnInfo[]{DIRECTORY, VCS_SETTING}, mappings, 0);
myDirectoryMappingTable.setModelAndUpdateColumns(myModel);
myRecentlyChangedConfigurable.reset();
myLimitHistory.reset();
myScopeFilterConfig.reset();
myBaseRevisionTexts.setSelected(myVcsConfiguration.INCLUDE_TEXT_INTO_SHELF);
myShowChangedRecursively.setSelected(myVcsConfiguration.SHOW_DIRTY_RECURSIVELY);
myCommitMessageMarginConfigurable.reset();
}
public static DefaultComboBoxModel buildVcsWrappersModel(final Project project) {
final VcsDescriptor[] vcsDescriptors = ProjectLevelVcsManager.getInstance(project).getAllVcss();
final VcsDescriptor[] result = new VcsDescriptor[vcsDescriptors.length + 1];
result[0] = VcsDescriptor.createFictive();
System.arraycopy(vcsDescriptors, 0, result, 1, vcsDescriptors.length);
return new DefaultComboBoxModel(result);
}
private void addMapping() {
VcsMappingConfigurationDialog dlg = new VcsMappingConfigurationDialog(myProject, VcsBundle.message("directory.mapping.add.title"));
// due to wonderful UI designer bug
dlg.initProjectMessage();
dlg.show();
if (dlg.isOK()) {
VcsDirectoryMapping mapping = new VcsDirectoryMapping();
dlg.saveToMapping(mapping);
addMapping(mapping);
}
}
private void addMapping(VcsDirectoryMapping mapping) {
List<VcsDirectoryMapping> items = new ArrayList<VcsDirectoryMapping>(myModel.getItems());
items.add(mapping);
myModel.setItems(items);
checkNotifyListeners(getActiveVcses());
}
private void editMapping() {
Collection<AbstractVcs> activeVcses = getActiveVcses();
VcsMappingConfigurationDialog dlg = new VcsMappingConfigurationDialog(myProject, VcsBundle.message("directory.mapping.remove.title"));
final VcsDirectoryMapping mapping = myDirectoryMappingTable.getSelectedObject();
dlg.setMapping(mapping);
dlg.show();
if (dlg.isOK()) {
dlg.saveToMapping(mapping);
myModel.fireTableDataChanged();
checkNotifyListeners(activeVcses);
}
}
private void removeMapping() {
Collection<AbstractVcs> activeVcses = getActiveVcses();
ArrayList<VcsDirectoryMapping> mappings = new ArrayList<VcsDirectoryMapping>(myModel.getItems());
int index = myDirectoryMappingTable.getSelectionModel().getMinSelectionIndex();
Collection<VcsDirectoryMapping> selection = myDirectoryMappingTable.getSelection();
mappings.removeAll(selection);
myModel.setItems(mappings);
if (mappings.size() > 0) {
if (index >= mappings.size()) {
index = mappings.size() - 1;
}
myDirectoryMappingTable.getSelectionModel().setSelectionInterval(index, index);
}
checkNotifyListeners(activeVcses);
}
protected JComponent createMainComponent() {
JPanel panel = new JPanel(new GridBagLayout());
GridBag gb = new GridBag()
.setDefaultInsets(new Insets(0, 0, DEFAULT_VGAP, DEFAULT_HGAP))
.setDefaultWeightX(1)
.setDefaultFill(GridBagConstraints.HORIZONTAL);
panel.add(createMappingsTable(), gb.nextLine().next().fillCell().weighty(1.0));
panel.add(createProjectMappingDescription(), gb.nextLine().next());
panel.add(createErrorList(), gb.nextLine().next());
panel.add(myLimitHistory.createComponent(), gb.nextLine().next());
panel.add(createShowRecursivelyDirtyOption(), gb.nextLine().next());
panel.add(createStoreBaseRevisionOption(), gb.nextLine().next());
panel.add(createShowChangedOption(), gb.nextLine().next());
panel.add(createShowVcsRootErrorNotificationOption(), gb.nextLine().next());
panel.add(myScopeFilterConfig.createComponent(), gb.nextLine().next());
panel.add(createUseCommitMessageRightMargin(), gb.nextLine().next().fillCellHorizontally());
return panel;
}
private JComponent createMappingsTable() {
JPanel panelForTable = ToolbarDecorator.createDecorator(myDirectoryMappingTable, null)
.setAddAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
addMapping();
updateRootCheckers();
}
}).setEditAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
editMapping();
updateRootCheckers();
}
}).setRemoveAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
removeMapping();
updateRootCheckers();
}
}).setAddActionUpdater(new AnActionButtonUpdater() {
@Override
public boolean isEnabled(AnActionEvent e) {
return !myIsDisabled;
}
}).setEditActionUpdater(new AnActionButtonUpdater() {
@Override
public boolean isEnabled(AnActionEvent e) {
final boolean hasSelection = myDirectoryMappingTable.getSelectedObject() != null;
return (!myIsDisabled) && hasSelection;
}
}).setRemoveActionUpdater(new AnActionButtonUpdater() {
@Override
public boolean isEnabled(AnActionEvent e) {
final boolean hasSelection = myDirectoryMappingTable.getSelectedObject() != null;
return (!myIsDisabled) && hasSelection;
}
}).disableUpDownActions().createPanel();
panelForTable.setPreferredSize(new Dimension(-1, 200));
return panelForTable;
}
private JComponent createErrorList() {
final int DEFAULT_HEIGHT = 200;
final JComponent errorPanel = Box.createVerticalBox();
final JBScrollPane pane = new JBScrollPane(errorPanel);
Collection<VcsRootError> myErrors = VcsRootErrorsFinder.getInstance(myProject).find();
for (final VcsRootError root : myErrors) {
if (!VcsRootError.Type.UNREGISTERED_ROOT.equals(root.getType())) {
continue;
}
final VcsKey vcsKey = root.getVcsKey();
final VcsDescriptor vcsDescriptor = myAllVcss.get(vcsKey.getName());
String displayVcsName = vcsDescriptor.getDisplayName();
String title = "Unregistered " + displayVcsName + " root: " + FileUtil.toSystemDependentName(root.getMapping());
final VcsRootErrorLabel vcsRootErrorLabel = new VcsRootErrorLabel(title);
vcsRootErrorLabel.setAddRootLinkHandler(new Runnable() {
@Override
public void run() {
addMapping(new VcsDirectoryMapping(root.getMapping(), vcsKey.getName()));
errorPanel.remove(vcsRootErrorLabel);
if (errorPanel.getComponentCount() == 0) {
pane.setVisible(false);
}
pane.setMinimumSize(new Dimension(-1, calcMinHeight(errorPanel, DEFAULT_HEIGHT)));
validate();
}
});
errorPanel.add(vcsRootErrorLabel);
}
if (errorPanel.getComponentCount() == 0) {
pane.setVisible(false);
}
pane.setMinimumSize(new Dimension(-1, calcMinHeight(errorPanel, DEFAULT_HEIGHT)));
pane.setMaximumSize(new Dimension(-1, DEFAULT_HEIGHT));
return pane;
}
private static int calcMinHeight(@NotNull JComponent errorPanel, int defaultHeight) {
int height = errorPanel.getPreferredSize().height;
return height > defaultHeight ? defaultHeight : height;
}
private JComponent createProjectMappingDescription() {
final JBLabel label = new JBLabel(myProjectMessage);
label.setComponentStyle(UIUtil.ComponentStyle.SMALL);
label.setFontColor(UIUtil.FontColor.BRIGHTER);
label.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 0));
return label;
}
private JComponent createStoreBaseRevisionOption() {
final JBLabel noteLabel = new JBLabel("File texts bigger than " + ourMaximumFileForBaseRevisionSize / 1000 + "K are not stored");
noteLabel.setComponentStyle(UIUtil.ComponentStyle.SMALL);
noteLabel.setFontColor(UIUtil.FontColor.BRIGHTER);
noteLabel.setBorder(BorderFactory.createEmptyBorder(2, 25, 5, 0));
final JPanel panel = new JPanel(new BorderLayout());
panel.add(myBaseRevisionTexts, BorderLayout.NORTH);
panel.add(noteLabel, BorderLayout.SOUTH);
return panel;
}
private JComponent createShowChangedOption() {
myRecentlyChangedConfigurable = new VcsContentAnnotationConfigurable(myProject);
JComponent component = myRecentlyChangedConfigurable.createComponent();
assert component != null;
return component;
}
private JComponent createShowVcsRootErrorNotificationOption() {
myShowVcsRootErrorNotification = new JCheckBox("Notify about VCS root errors",
myVcsConfiguration.SHOW_VCS_ERROR_NOTIFICATIONS);
myShowVcsRootErrorNotification.setVisible(!myCheckers.isEmpty());
return myShowVcsRootErrorNotification;
}
private JComponent createUseCommitMessageRightMargin() {
myCommitMessageMarginConfigurable = new VcsCommitMessageMarginConfigurable(myProject, myVcsConfiguration);
return myCommitMessageMarginConfigurable.createComponent();
}
private JComponent createShowRecursivelyDirtyOption() {
myShowChangedRecursively = new JCheckBox("Show directories with changed descendants", myVcsConfiguration.SHOW_DIRTY_RECURSIVELY);
return myShowChangedRecursively;
}
@Override
public void reset() {
initializeModel();
}
@Override
public void apply() throws ConfigurationException {
myVcsManager.setDirectoryMappings(myModel.getItems());
myRecentlyChangedConfigurable.apply();
myLimitHistory.apply();
myScopeFilterConfig.apply();
myVcsConfiguration.INCLUDE_TEXT_INTO_SHELF = myBaseRevisionTexts.isSelected();
myVcsConfiguration.SHOW_VCS_ERROR_NOTIFICATIONS = myShowVcsRootErrorNotification.isSelected();
myVcsConfiguration.SHOW_DIRTY_RECURSIVELY = myShowChangedRecursively.isSelected();
myCommitMessageMarginConfigurable.apply();
initializeModel();
}
@Override
public boolean isModified() {
if (myRecentlyChangedConfigurable.isModified()) return true;
if (myLimitHistory.isModified()) return true;
if (myScopeFilterConfig.isModified()) return true;
if (myVcsConfiguration.INCLUDE_TEXT_INTO_SHELF != myBaseRevisionTexts.isSelected()) return true;
if (myVcsConfiguration.SHOW_VCS_ERROR_NOTIFICATIONS != myShowVcsRootErrorNotification.isSelected()) {
return true;
}
if (myVcsConfiguration.SHOW_DIRTY_RECURSIVELY != myShowChangedRecursively.isSelected()) {
return true;
}
if (myCommitMessageMarginConfigurable.isModified()) {
return true;
}
return !myModel.getItems().equals(myVcsManager.getDirectoryMappings());
}
public void addVcsListener(final ModuleVcsListener moduleVcsListener) {
myListeners.add(moduleVcsListener);
}
public void removeVcsListener(final ModuleVcsListener moduleVcsListener) {
myListeners.remove(moduleVcsListener);
}
private void checkNotifyListeners(Collection<AbstractVcs> oldVcses) {
Collection<AbstractVcs> vcses = getActiveVcses();
if (!vcses.equals(oldVcses)) {
for (ModuleVcsListener listener : myListeners) {
listener.activeVcsSetChanged(vcses);
}
}
}
public Collection<AbstractVcs> getActiveVcses() {
Set<AbstractVcs> vcses = new HashSet<AbstractVcs>();
for (VcsDirectoryMapping mapping : myModel.getItems()) {
if (mapping.getVcs().length() > 0) {
vcses.add(myVcsManager.findVcsByName(mapping.getVcs()));
}
}
return vcses;
}
@Override
@Nls
public String getDisplayName() {
return "Mappings";
}
@Override
public String getHelpTopic() {
return null;
}
@Override
public JComponent createComponent() {
return this;
}
@Override
public void disposeUIResources() {
myLimitHistory.disposeUIResources();
myScopeFilterConfig.disposeUIResources();
}
private static class VcsRootErrorLabel extends JPanel {
private final LinkLabel myAddLabel;
VcsRootErrorLabel(String title) {
super(new BorderLayout(DEFAULT_HGAP, DEFAULT_VGAP));
CompoundBorder outsideBorder =
BorderFactory.createCompoundBorder(BorderFactory.createMatteBorder(5, 0, 5, 0, UIUtil.getPanelBackground()),
BorderFactory.createLineBorder(UIUtil.getPanelBackground().darker()));
setBorder(BorderFactory.createCompoundBorder(outsideBorder, BorderFactory.createEmptyBorder(DEFAULT_VGAP, DEFAULT_HGAP,
DEFAULT_VGAP, DEFAULT_HGAP)));
setOpaque(true);
setBackground(new Color(255, 186, 192));
JBLabel label = new JBLabel(title);
if( UIUtil.isUnderDarcula()) {
label.setForeground(UIUtil.getPanelBackground());
}
myAddLabel = new LinkLabel("Add root", null);
myAddLabel.setOpaque(false);
JPanel actionsPanel = new JPanel(new BorderLayout(DEFAULT_HGAP, DEFAULT_VGAP));
actionsPanel.setOpaque(false);
actionsPanel.add(myAddLabel, BorderLayout.CENTER);
add(label, BorderLayout.CENTER);
add(actionsPanel, BorderLayout.EAST);
}
void setAddRootLinkHandler(final Runnable handler) {
myAddLabel.setListener(new LinkListener() {
@Override
public void linkSelected(LinkLabel aSource, Object aLinkData) {
handler.run();
}
}, null);
}
}
}