diff --git a/build/scripts/libLicenses.gant b/build/scripts/libLicenses.gant index ad492d318a49..d495f952b7a8 100644 --- a/build/scripts/libLicenses.gant +++ b/build/scripts/libLicenses.gant @@ -214,6 +214,7 @@ libraryLicense(name: "maven-core", version: "3.0.5", libraryNames: ["maven-core- libraryLicense(name: "plexus-component-annotations", version: "1.5.5", libraryNames: ["plexus-component-annotations-1.5.5.jar"], license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://maven.apache.org/license.html") libraryLicense(name: "Maven3", libraryNames: ["Maven3", "maven-dependency-tree-1.2.jar", "archetype-catalog-2.2.jar", "archetype-common-2.2.jar"], version: "3.0.5", license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://maven.apache.org/license.html") libraryLicense(name: "Gradle", version: "1.12", license: "Apache 2.0", url: "http://gradle.org/", licenseUrl: "http://gradle.org/license") +libraryLicense(name: "gradle-tooling-api-2.0.jar", version: "2.0", license: "Apache 2.0", url: "http://gradle.org/", licenseUrl: "http://gradle.org/license") libraryLicense(name: "GradleJnaPosix", version: "1.0.3", license: "LGPL 2.1", url: "http://www.jruby.org/", licenseUrl: "http://www.gnu.org/licenses/lgpl-2.1.txt") libraryLicense(name: "Slf4j", version: "1.7.2", license: "MIT License", url: "http://slf4j.org/", licenseUrl: "http://slf4j.org/license.html") libraryLicense(name: "GradleGuava", version: "14.0.1", license: "Apache 2.0", url: "http://code.google.com/p/guava-libraries/", licenseUrl: "http://apache.org/licenses/LICENSE-2.0") diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java b/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java index 5bfbf09c7914..20d95f8fff3d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java @@ -111,13 +111,13 @@ public class JavaDebuggerSupport extends DebuggerSupport { @Override @NotNull public DebuggerActionHandler getRunToCursorHandler() { - return myRunToCursorActionHandler; + return DISABLED; } @Override @NotNull public DebuggerActionHandler getForceRunToCursorHandler() { - return myForceRunToCursorActionHandler; + return DISABLED; } @Override diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java index bf083f92c66c..a5867d66d176 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java @@ -44,6 +44,7 @@ import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.wm.ex.IdeFocusTraversalPolicy; import com.intellij.packaging.artifacts.Artifact; import com.intellij.ui.JBSplitter; +import com.intellij.ui.OnePixelSplitter; import com.intellij.ui.components.panels.Wrapper; import com.intellij.ui.navigation.BackAction; import com.intellij.ui.navigation.ForwardAction; @@ -174,12 +175,9 @@ public class ProjectStructureConfigurable extends BaseConfigurable implements Se public JComponent createComponent() { myComponent = new MyPanel(); - mySplitter = new JBSplitter(false, .15f); + mySplitter = Registry.is("ide.new.project.settings") ? new OnePixelSplitter(false, .15f) : new JBSplitter(false, .15f); mySplitter.setSplitterProportionKey("ProjectStructure.TopLevelElements"); mySplitter.setHonorComponentsMinimumSize(true); - if (Registry.is("ide.new.project.settings")) { - mySplitter.setOnePixelMode(); - } initSidePanel(); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorImpl.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorImpl.java index 39453f32db4b..618f085f00bb 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorImpl.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorImpl.java @@ -206,7 +206,7 @@ public class ArtifactEditorImpl implements ArtifactEditorEx { myErrorPanelPlace.add(myValidationManager.getMainErrorPanel(), BorderLayout.CENTER); - JBSplitter splitter = new JBSplitter(false); + final JBSplitter splitter = Registry.is("ide.new.project.settings") ? new OnePixelSplitter(false) : new JBSplitter(false); final JPanel leftPanel = new JPanel(new BorderLayout()); JPanel treePanel = myLayoutTreeComponent.getTreePanel(); if (UIUtil.isUnderDarcula()) { @@ -262,7 +262,6 @@ public class ArtifactEditorImpl implements ArtifactEditorEx { } splitter.setSecondComponent(rightPanel); if (Registry.is("ide.new.project.settings")) { - splitter.setOnePixelMode(); splitter.getDivider().setBackground(UIUtil.getPanelBackground()); treePanel.setBorder(new EmptyBorder(0, 0, 0, 0)); rightPanel.setBorder(new EmptyBorder(0, 0, 0, 0)); diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java index cb0e1a298c9c..e6b2553085a8 100644 --- a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java +++ b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java @@ -72,6 +72,7 @@ public class UISettings implements PersistentStateComponent, Exporta public int RECENT_FILES_LIMIT = 50; public int CONSOLE_COMMAND_HISTORY_LIMIT = 300; public int EDITOR_TAB_LIMIT = 10; + public int EDITOR_TAB_TITLE_LIMIT = 100; public boolean ANIMATE_WINDOWS = true; public int ANIMATION_SPEED = 2000; // Pixels per second public boolean SHOW_TOOL_WINDOW_NUMBERS = true; diff --git a/platform/lang-impl/src/com/intellij/application/options/editor/EditorTabsConfigurable.form b/platform/lang-impl/src/com/intellij/application/options/editor/EditorTabsConfigurable.form index 9872c7c624aa..db23ce17b2c3 100644 --- a/platform/lang-impl/src/com/intellij/application/options/editor/EditorTabsConfigurable.form +++ b/platform/lang-impl/src/com/intellij/application/options/editor/EditorTabsConfigurable.form @@ -3,7 +3,7 @@ - + @@ -108,7 +108,7 @@ - + @@ -119,7 +119,7 @@ - + @@ -129,7 +129,9 @@ - + + + @@ -138,19 +140,38 @@ - + + + + + + + + + + + + + + + + + + + + - + @@ -184,7 +205,7 @@ - + diff --git a/platform/lang-impl/src/com/intellij/application/options/editor/EditorTabsConfigurable.java b/platform/lang-impl/src/com/intellij/application/options/editor/EditorTabsConfigurable.java index 4e1de817255a..8db2a882bfc7 100644 --- a/platform/lang-impl/src/com/intellij/application/options/editor/EditorTabsConfigurable.java +++ b/platform/lang-impl/src/com/intellij/application/options/editor/EditorTabsConfigurable.java @@ -45,6 +45,7 @@ public class EditorTabsConfigurable implements EditorOptionsProvider { private JCheckBox myShowCloseButtonOnCheckBox; private JCheckBox myShowDirectoryInTabCheckBox; private JRadioButton myActivateRightNeighbouringTabRadioButton; + private JTextField myTabTitleLimitField; public EditorTabsConfigurable() { myEditorTabPlacement.setModel(new DefaultComboBoxModel(new Object[]{ @@ -119,6 +120,7 @@ public class EditorTabsConfigurable implements EditorOptionsProvider { myHideKnownExtensions.setSelected(uiSettings.HIDE_KNOWN_EXTENSION_IN_TABS); myShowDirectoryInTabCheckBox.setSelected(uiSettings.SHOW_DIRECTORY_FOR_NON_UNIQUE_FILENAMES); myEditorTabLimitField.setText(Integer.toString(uiSettings.EDITOR_TAB_LIMIT)); + myTabTitleLimitField.setText(Integer.toString(uiSettings.EDITOR_TAB_TITLE_LIMIT)); myShowCloseButtonOnCheckBox.setSelected(uiSettings.SHOW_CLOSE_BUTTON); if (uiSettings.CLOSE_NON_MODIFIED_FILES_FIRST) { @@ -171,14 +173,29 @@ public class EditorTabsConfigurable implements EditorOptionsProvider { uiSettings.ACTIVATE_RIGHT_EDITOR_ON_CLOSE = myActivateRightNeighbouringTabRadioButton.isSelected(); String temp = myEditorTabLimitField.getText(); - if(temp.trim().length() > 0){ + if (temp.trim().length() > 0) { try { int newEditorTabLimit = Integer.parseInt(temp); - if(newEditorTabLimit>0&&newEditorTabLimit!=uiSettings.EDITOR_TAB_LIMIT){ - uiSettings.EDITOR_TAB_LIMIT=newEditorTabLimit; + if (newEditorTabLimit > 0 && newEditorTabLimit != uiSettings.EDITOR_TAB_LIMIT) { + uiSettings.EDITOR_TAB_LIMIT = newEditorTabLimit; uiSettingsChanged = true; } - }catch (NumberFormatException ignored){} + } + catch (NumberFormatException ignored) { + } + } + temp = myTabTitleLimitField.getText(); + if (temp.trim().length() > 0) { + try { + int newTabTitleLimit = Integer.parseInt(temp); + newTabTitleLimit = Math.max(10, Math.min(100, newTabTitleLimit)); + if (newTabTitleLimit != uiSettings.EDITOR_TAB_TITLE_LIMIT){ + uiSettings.EDITOR_TAB_TITLE_LIMIT = newTabTitleLimit; + uiSettingsChanged = true; + } + } + catch (NumberFormatException ignored) { + } } if(uiSettingsChanged){ uiSettings.fireUISettingsChanged(); @@ -191,6 +208,7 @@ public class EditorTabsConfigurable implements EditorOptionsProvider { boolean isModified = isModified(myCbModifiedTabsMarkedWithAsterisk, uiSettings.MARK_MODIFIED_TABS_WITH_ASTERISK); isModified |= isModified(myShowTabsTooltipsCheckBox, uiSettings.SHOW_TABS_TOOLTIPS); isModified |= isModified(myEditorTabLimitField, uiSettings.EDITOR_TAB_LIMIT); + isModified |= isModified(myTabTitleLimitField, uiSettings.EDITOR_TAB_TITLE_LIMIT); int tabPlacement = ((Integer)myEditorTabPlacement.getSelectedItem()).intValue(); isModified |= tabPlacement != uiSettings.EDITOR_TAB_PLACEMENT; isModified |= myHideKnownExtensions.isSelected() != uiSettings.HIDE_KNOWN_EXTENSION_IN_TABS; diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/impl/DetectedRootsChooserDialog.java b/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/impl/DetectedRootsChooserDialog.java index ee44bdf2f08b..bf3d383aeebb 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/impl/DetectedRootsChooserDialog.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/impl/DetectedRootsChooserDialog.java @@ -26,11 +26,13 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.*; import com.intellij.ui.treeStructure.treetable.TreeColumnInfo; import com.intellij.util.PlatformIcons; +import com.intellij.util.containers.Convertor; import com.intellij.util.ui.ColumnInfo; import com.intellij.util.ui.ComboBoxCellEditor; import com.intellij.util.ui.tree.TreeUtil; import com.intellij.xml.util.XmlStringUtil; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -38,12 +40,11 @@ import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; +import javax.swing.tree.TreePath; import java.awt.*; import java.io.File; -import java.util.Arrays; -import java.util.HashMap; +import java.util.*; import java.util.List; -import java.util.Map; /** * This dialog allows selecting paths inside selected archives or directories. @@ -108,17 +109,17 @@ public class DetectedRootsChooserDialog extends DialogWrapper { private JScrollPane myPane; private String myDescription; - public DetectedRootsChooserDialog(Component component, List suggestedRoots) { + public DetectedRootsChooserDialog(Component component, Collection suggestedRoots) { super(component, true); init(suggestedRoots); } - public DetectedRootsChooserDialog(Project project, List suggestedRoots) { + public DetectedRootsChooserDialog(Project project, Collection suggestedRoots) { super(project, true); init(suggestedRoots); } - private void init(List suggestedRoots) { + private void init(Collection suggestedRoots) { myDescription = XmlStringUtil.wrapInHtml(ApplicationNamesInfo.getInstance().getFullProductName() + " just scanned files and detected the following " + StringUtil.pluralize("root", suggestedRoots.size()) + ".
" + "Select items in the tree below or press Cancel to cancel operation."); @@ -128,7 +129,7 @@ public class DetectedRootsChooserDialog extends DialogWrapper { init(); } - private static CheckboxTreeTable createTreeTable(List suggestedRoots) { + private static CheckboxTreeTable createTreeTable(Collection suggestedRoots) { final CheckedTreeNode root = createRoot(suggestedRoots); CheckboxTreeTable treeTable = new CheckboxTreeTable(root, new CheckboxTree.CheckboxTreeCellRenderer(true) { @Override @@ -189,14 +190,30 @@ public class DetectedRootsChooserDialog extends DialogWrapper { column.setPreferredWidth(width); column.setMaxWidth(width); treeTable.setRootVisible(false); + new TreeTableSpeedSearch(treeTable, new Convertor() { + @Override + public String convert(TreePath o) { + Object node = o.getLastPathComponent(); + if (!(node instanceof VirtualFileCheckedTreeNode)) return ""; + return ((VirtualFileCheckedTreeNode)node).getFile().getPresentableUrl(); + } + }); TreeUtil.expandAll(treeTable.getTree()); return treeTable; } - private static CheckedTreeNode createRoot(List suggestedRoots) { + private static CheckedTreeNode createRoot(Collection suggestedRoots) { + SuggestedChildRootInfo[] sortedRoots = suggestedRoots.toArray(new SuggestedChildRootInfo[suggestedRoots.size()]); + Arrays.sort(sortedRoots, new Comparator() { + @Override + public int compare(@NotNull SuggestedChildRootInfo o1, @NotNull SuggestedChildRootInfo o2) { + return o1.getDetectedRoot().getFile().getPresentableUrl().compareTo(o2.getDetectedRoot().getFile().getPresentableUrl()); + } + }); + CheckedTreeNode root = new CheckedTreeNode(null); Map rootCandidateNodes = new HashMap(); - for (SuggestedChildRootInfo rootInfo : suggestedRoots) { + for (SuggestedChildRootInfo rootInfo : sortedRoots) { final VirtualFile rootCandidate = rootInfo.getRootCandidate(); CheckedTreeNode parent = rootCandidateNodes.get(rootCandidate); if (parent == null) { @@ -230,6 +247,12 @@ public class DetectedRootsChooserDialog extends DialogWrapper { return "DetectedRootsChooserDialog"; } + @Nullable + @Override + public JComponent getPreferredFocusedComponent() { + return myTreeTable; + } + private static class VirtualFileCheckedTreeNode extends CheckedTreeNode { private final VirtualFile myFile; diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/impl/SuggestedChildRootInfo.java b/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/impl/SuggestedChildRootInfo.java index 743e408b8c97..725216600ffa 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/impl/SuggestedChildRootInfo.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/impl/SuggestedChildRootInfo.java @@ -19,6 +19,7 @@ import com.intellij.openapi.roots.libraries.LibraryRootType; import com.intellij.openapi.roots.libraries.ui.DetectedLibraryRoot; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; import java.util.Arrays; import java.util.Map; @@ -32,17 +33,19 @@ class SuggestedChildRootInfo { private final Map myRootTypeNames; private LibraryRootType mySelectedRootType; - SuggestedChildRootInfo(VirtualFile rootCandidate, DetectedLibraryRoot detectedRoot, Map rootTypeNames) { + SuggestedChildRootInfo(@NotNull VirtualFile rootCandidate, @NotNull DetectedLibraryRoot detectedRoot, @NotNull Map rootTypeNames) { myRootCandidate = rootCandidate; myDetectedRoot = detectedRoot; myRootTypeNames = rootTypeNames; mySelectedRootType = detectedRoot.getTypes().get(0); } + @NotNull public VirtualFile getRootCandidate() { return myRootCandidate; } + @NotNull public DetectedLibraryRoot getDetectedRoot() { return myDetectedRoot; } @@ -51,6 +54,7 @@ class SuggestedChildRootInfo { return myRootTypeNames.get(type); } + @NotNull public LibraryRootType getSelectedRootType() { return mySelectedRootType; } @@ -64,6 +68,7 @@ class SuggestedChildRootInfo { } } + @NotNull public String[] getRootTypeNames() { final String[] types = ArrayUtil.toStringArray(myRootTypeNames.values()); Arrays.sort(types, String.CASE_INSENSITIVE_ORDER); diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/CommonContentEntriesEditor.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/CommonContentEntriesEditor.java index 330c084291fd..04f908a17c00 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/CommonContentEntriesEditor.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/CommonContentEntriesEditor.java @@ -39,6 +39,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.ex.VirtualFileManagerAdapter; import com.intellij.ui.JBSplitter; +import com.intellij.ui.OnePixelSplitter; import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.border.CustomLineBorder; import com.intellij.ui.roots.ToolbarPanel; @@ -171,10 +172,7 @@ public class CommonContentEntriesEditor extends ModuleElementsEditor { } entriesPanel.add(toolbarPanel, BorderLayout.CENTER); - final JBSplitter splitter = new JBSplitter(false); - if (Registry.is("ide.new.project.settings")) { - splitter.setOnePixelMode(); - } + final JBSplitter splitter = Registry.is("ide.new.project.settings") ? new OnePixelSplitter(false) : new JBSplitter(false); splitter.setProportion(0.6f); splitter.setHonorComponentsMinimumSize(true); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java index 89c531ec4bc5..6427765295c5 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java @@ -367,7 +367,7 @@ public class MapReduceIndex implements UpdatableIndex implements UpdatableIndex, Exception>() { diff --git a/platform/platform-api/src/com/intellij/openapi/diff/FragmentContent.java b/platform/platform-api/src/com/intellij/openapi/diff/FragmentContent.java index 26537316b4e9..d630bad790df 100644 --- a/platform/platform-api/src/com/intellij/openapi/diff/FragmentContent.java +++ b/platform/platform-api/src/com/intellij/openapi/diff/FragmentContent.java @@ -41,18 +41,28 @@ public class FragmentContent extends DiffContent { private final FileType myType; private final MyDocumentsSynchronizer mySynchonizer; public static final Key ORIGINAL_DOCUMENT = new Key("ORIGINAL_DOCUMENT"); + private final boolean myForceReadOnly; public FragmentContent(@NotNull DiffContent original, @NotNull TextRange range, Project project, VirtualFile file) { - this(original, range, project, file != null ? DiffContentUtil.getContentType(file) : null); + this(original, range, project, file, false); + } + + public FragmentContent(@NotNull DiffContent original, @NotNull TextRange range, Project project, VirtualFile file, boolean forceReadOnly) { + this(original, range, project, file != null ? DiffContentUtil.getContentType(file) : null, forceReadOnly); } public FragmentContent(@NotNull DiffContent original, @NotNull TextRange range, Project project, FileType fileType) { + this(original, range, project, fileType, false); + } + + public FragmentContent(@NotNull DiffContent original, @NotNull TextRange range, Project project, FileType fileType, boolean forceReadOnly) { RangeMarker rangeMarker = original.getDocument().createRangeMarker(range.getStartOffset(), range.getEndOffset(), true); rangeMarker.setGreedyToLeft(true); rangeMarker.setGreedyToRight(true); mySynchonizer = new MyDocumentsSynchronizer(project, rangeMarker); myOriginal = original; myType = fileType; + myForceReadOnly = forceReadOnly; } public FragmentContent(DiffContent original, TextRange range, Project project) { @@ -152,7 +162,7 @@ public class FragmentContent extends DiffContent { String textInRange = originalDocument.getCharsSequence().subSequence(myRangeMarker.getStartOffset(), myRangeMarker.getEndOffset()).toString(); final Document result = EditorFactory.getInstance().createDocument(textInRange); - result.setReadOnly(!originalDocument.isWritable()); + result.setReadOnly(myForceReadOnly || !originalDocument.isWritable()); result.putUserData(ORIGINAL_DOCUMENT, originalDocument); return result; } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java index 53572a523bc0..c64439f678ba 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java @@ -131,12 +131,9 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom protected MasterDetailsComponent(MasterDetailsState state) { myState = state; - mySplitter = new JBSplitter(false, .2f); + mySplitter = Registry.is("ide.new.project.settings") ? new OnePixelSplitter(false, .2f) : new JBSplitter(false, .2f); mySplitter.setSplitterProportionKey("ProjectStructure.SecondLevelElements"); mySplitter.setHonorComponentsMinimumSize(true); - if (Registry.is("ide.new.project.settings")) { - mySplitter.setOnePixelMode(); - } installAutoScroll(); reInitWholePanelIfNeeded(); diff --git a/platform/platform-api/src/com/intellij/openapi/ui/OnePixelDivider.java b/platform/platform-api/src/com/intellij/openapi/ui/OnePixelDivider.java new file mode 100644 index 000000000000..2b0097005dc1 --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/ui/OnePixelDivider.java @@ -0,0 +1,233 @@ +/* + * Copyright 2000-2014 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.ui; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.Weighted; +import com.intellij.openapi.wm.IdeGlassPane; +import com.intellij.openapi.wm.IdeGlassPaneUtil; +import com.intellij.ui.Gray; +import com.intellij.ui.JBColor; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/** + * @author Konstantin Bulenkov + */ +public class OnePixelDivider extends Divider { + private boolean myVertical; + private Splitter mySplitter; + private boolean myResizeEnabled; + private boolean mySwitchOrientationEnabled; + protected Point myPoint; + private IdeGlassPane myGlassPane; + private final MouseAdapter myListener = new MyMouseAdapter(); + private Disposable myDisposable; + + public OnePixelDivider(boolean vertical, Splitter splitter) { + super(new GridBagLayout()); + mySplitter = splitter; + myResizeEnabled = true; + mySwitchOrientationEnabled = false; + setFocusable(false); + enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK); + //setOpaque(false); + setOrientation(vertical); + setBackground(new JBColor(Gray._153.withAlpha(128), Gray._100.withAlpha(128))); + } + + @Override + public void addNotify() { + super.addNotify(); + init(); + } + + @Override + public void removeNotify() { + super.removeNotify(); + if (myDisposable != null && !Disposer.isDisposed(myDisposable)) { + Disposer.dispose(myDisposable); + } + } + + private boolean dragging = false; + private class MyMouseAdapter extends MouseAdapter implements Weighted { + @Override + public void mousePressed(MouseEvent e) { + dragging = isInDragZone(e); + _processMouseEvent(e); + } + + boolean isInDragZone(MouseEvent e) { + final MouseEvent event = getTargetEvent(e); + final Point p = event.getPoint(); + final int r = Math.abs(isVertical() ? p.y : p.x); + return r < 6; + } + + @Override + public void mouseReleased(MouseEvent e) { + _processMouseEvent(e); + dragging = false; + } + + @Override + public void mouseMoved(MouseEvent e) { + final OnePixelDivider divider = OnePixelDivider.this; + if (isInDragZone(e)) { + myGlassPane.setCursor(divider.getCursor(), divider); + } else { + myGlassPane.setCursor(null, divider); + } + _processMouseMotionEvent(e); + } + + @Override + public void mouseDragged(MouseEvent e) { + _processMouseMotionEvent(e); + } + @Override + public double getWeight() { + return 1; + } + private void _processMouseMotionEvent(MouseEvent e) { + MouseEvent event = getTargetEvent(e); + if (event == null) { + myGlassPane.setCursor(null, myListener); + return; + } + + processMouseMotionEvent(event); + if (event.isConsumed()) { + e.consume(); + } + } + + private void _processMouseEvent(MouseEvent e) { + MouseEvent event = getTargetEvent(e); + if (event == null) { + myGlassPane.setCursor(null, myListener); + return; + } + + processMouseEvent(event); + if (event.isConsumed()) { + e.consume(); + } + } + } + + private MouseEvent getTargetEvent(MouseEvent e) { + return SwingUtilities.convertMouseEvent(e.getComponent(), e, this); + } + + private void init() { + myGlassPane = IdeGlassPaneUtil.find(this); + myDisposable = Disposer.newDisposable(); + myGlassPane.addMouseMotionPreprocessor(myListener, myDisposable); + myGlassPane.addMousePreprocessor(myListener, myDisposable); + } + + public void setOrientation(boolean vertical) { + removeAll(); + myVertical = vertical; + final int cursorType = isVertical() ? Cursor.N_RESIZE_CURSOR : Cursor.W_RESIZE_CURSOR; + setCursor(Cursor.getPredefinedCursor(cursorType)); + } + + @Override + protected void processMouseMotionEvent(MouseEvent e) { + super.processMouseMotionEvent(e); + if (!myResizeEnabled) return; + if (MouseEvent.MOUSE_DRAGGED == e.getID() && dragging) { + myPoint = SwingUtilities.convertPoint(this, e.getPoint(), mySplitter); + float proportion; + final float firstMinProportion = getMinProportion(mySplitter.getFirstComponent()); + final float secondMinProportion = getMinProportion(mySplitter.getSecondComponent()); + if (isVertical()) { + if (getHeight() > 0) { + proportion = Math.min(1.0f, Math + .max(.0f, Math.min(Math.max(firstMinProportion, (float)myPoint.y / (float)mySplitter.getHeight()), 1 - secondMinProportion))); + mySplitter.setProportion(proportion); + } + } + else { + if (getWidth() > 0) { + proportion = Math.min(1.0f, Math.max(.0f, Math.min( + Math.max(firstMinProportion, (float)myPoint.x / (float)mySplitter.getWidth()), 1 - secondMinProportion))); + mySplitter.setProportion(proportion); + } + } + } + } + + private float getMinProportion(JComponent component) { + if (component != null && + mySplitter.getFirstComponent() != null && + mySplitter.getFirstComponent().isVisible() && + mySplitter.getSecondComponent() != null && + mySplitter.getSecondComponent().isVisible()) { + if (isVertical()) { + return (float)component.getMinimumSize().height / (float)(mySplitter.getHeight() - 1); + } else { + return (float)component.getMinimumSize().width / (float)(mySplitter.getWidth() - 1); + } + } + + return 0.0f; + } + + @Override + protected void processMouseEvent(MouseEvent e) { + super.processMouseEvent(e); + if (e.getID() == MouseEvent.MOUSE_CLICKED) { + if (mySwitchOrientationEnabled + && e.getClickCount() == 1 + && SwingUtilities.isLeftMouseButton(e) && (SystemInfo.isMac ? e.isMetaDown() : e.isControlDown())) { + mySplitter.setOrientation(!mySplitter.getOrientation()); + } + if (myResizeEnabled && e.getClickCount() == 2) { + mySplitter.setProportion(.5f); + } + } + } + + public void setResizeEnabled(boolean resizeEnabled) { + myResizeEnabled = resizeEnabled; + if (!myResizeEnabled) { + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + else { + setCursor(isVertical() ? + Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR) : + Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)); + } + } + + public void setSwitchOrientationEnabled(boolean switchOrientationEnabled) { + mySwitchOrientationEnabled = switchOrientationEnabled; + } + + + public boolean isVertical() { + return myVertical; + } +} diff --git a/platform/platform-api/src/com/intellij/ui/CheckboxTreeAdapter.java b/platform/platform-api/src/com/intellij/ui/CheckboxTreeAdapter.java new file mode 100644 index 000000000000..186904a4a843 --- /dev/null +++ b/platform/platform-api/src/com/intellij/ui/CheckboxTreeAdapter.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2014 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.ui; + +import org.jetbrains.annotations.NotNull; + +/** + * @author nik + */ +public abstract class CheckboxTreeAdapter implements CheckboxTreeListener { + @Override + public void mouseDoubleClicked(@NotNull CheckedTreeNode node) { + } + + @Override + public void nodeStateChanged(@NotNull CheckedTreeNode node) { + } + + @Override + public void beforeNodeStateChanged(@NotNull CheckedTreeNode node) { + } +} diff --git a/platform/platform-api/src/com/intellij/ui/CheckboxTreeBase.java b/platform/platform-api/src/com/intellij/ui/CheckboxTreeBase.java index d9755f342a3f..88f433f7c62a 100644 --- a/platform/platform-api/src/com/intellij/ui/CheckboxTreeBase.java +++ b/platform/platform-api/src/com/intellij/ui/CheckboxTreeBase.java @@ -16,67 +16,49 @@ package com.intellij.ui; import com.intellij.ui.treeStructure.Tree; +import com.intellij.util.EventDispatcher; import com.intellij.util.ui.UIUtil; -import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.tree.*; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeCellRenderer; +import javax.swing.tree.TreeNode; import java.awt.*; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.MouseEvent; -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Enumeration; public class CheckboxTreeBase extends Tree { - private final CheckPolicy myCheckPolicy; - private static final CheckPolicy DEFAULT_POLICY = new CheckPolicy(true, true, false, true); + private final CheckboxTreeHelper myHelper; + private final EventDispatcher myEventDispatcher; public CheckboxTreeBase() { this(new CheckboxTreeCellRendererBase(), null); } public CheckboxTreeBase(final CheckboxTreeCellRendererBase cellRenderer, CheckedTreeNode root) { - this(cellRenderer, root, DEFAULT_POLICY); + this(cellRenderer, root, CheckboxTreeHelper.DEFAULT_POLICY); } public CheckboxTreeBase(CheckboxTreeCellRendererBase cellRenderer, @Nullable CheckedTreeNode root, CheckPolicy checkPolicy) { - myCheckPolicy = checkPolicy; + myEventDispatcher = EventDispatcher.create(CheckboxTreeListener.class); + myEventDispatcher.addListener(new CheckboxTreeListener() { + @Override + public void mouseDoubleClicked(@NotNull CheckedTreeNode node) { + onDoubleClick(node); + } - setRootVisible(false); - setShowsRootHandles(true); - setLineStyleAngled(); - TreeUtil.installActions(this); + @Override + public void nodeStateChanged(@NotNull CheckedTreeNode node) { + CheckboxTreeBase.this.onNodeStateChanged(node); + } - installRenderer(cellRenderer); - - addKeyListener(new KeyAdapter() { - public void keyPressed(KeyEvent e) { - if (isToggleEvent(e)) { - TreePath treePath = getLeadSelectionPath(); - if (treePath == null) return; - final Object o = treePath.getLastPathComponent(); - if (!(o instanceof CheckedTreeNode)) return; - CheckedTreeNode firstNode = (CheckedTreeNode)o; - boolean checked = toggleNode(firstNode); - - TreePath[] selectionPaths = getSelectionPaths(); - for (int i = 0; selectionPaths != null && i < selectionPaths.length; i++) { - final TreePath selectionPath = selectionPaths[i]; - final Object o1 = selectionPath.getLastPathComponent(); - if (!(o1 instanceof CheckedTreeNode)) continue; - CheckedTreeNode node = (CheckedTreeNode)o1; - checkNode(node, checked); - ((DefaultTreeModel)getModel()).nodeChanged(node); - } - - e.consume(); - } + @Override + public void beforeNodeStateChanged(@NotNull CheckedTreeNode node) { + CheckboxTreeBase.this.nodeStateWillChange(node); } }); + myHelper = new CheckboxTreeHelper(checkPolicy, myEventDispatcher); + myHelper.initTree(this, this, cellRenderer); setSelectionRow(0); if (root != null) { @@ -84,57 +66,39 @@ public class CheckboxTreeBase extends Tree { } } + @Deprecated public void installRenderer(final CheckboxTreeCellRendererBase cellRenderer) { setCellRenderer(cellRenderer); - new ClickListener() { - @Override - public boolean onClick(@NotNull MouseEvent e, int clickCount) { - int row = getRowForLocation(e.getX(), e.getY()); - if (row < 0) return false; - final Object o = getPathForRow(row).getLastPathComponent(); - if (!(o instanceof CheckedTreeNode)) return false; - Rectangle rowBounds = getRowBounds(row); - cellRenderer.setBounds(rowBounds); - Rectangle checkBounds = cellRenderer.myCheckbox.getBounds(); - checkBounds.setLocation(rowBounds.getLocation()); + } - if (checkBounds.height == 0) checkBounds.height = checkBounds.width = rowBounds.height; + /** + * @deprecated use {@link #setNodeState} to change node state or subscribe to {@link #addCheckboxTreeListener} to get notifications about state changes + */ + @Deprecated + protected boolean toggleNode(CheckedTreeNode node) { + setNodeState(node, !node.isChecked()); + return node.isChecked(); + } - final CheckedTreeNode node = (CheckedTreeNode)o; - if (checkBounds.contains(e.getPoint())) { - if (node.isEnabled()) { - toggleNode(node); - setSelectionRow(row); - return true; - } - } - else if (clickCount > 1) { - onDoubleClick(node); - return true; - } - return false; - } - }.installOn(this); + /** + * @deprecated use {@link #setNodeState} to change node state or subscribe to {@link #addCheckboxTreeListener} to get notifications about state changes + */ + @Deprecated + protected void checkNode(CheckedTreeNode node, boolean checked) { + setNodeState(node, checked); + } + + public void setNodeState(@NotNull CheckedTreeNode node, boolean checked) { + myHelper.setNodeState(this, node, checked); + } + + public void addCheckboxTreeListener(@NotNull CheckboxTreeListener listener) { + myEventDispatcher.addListener(listener); } protected void onDoubleClick(final CheckedTreeNode node) { } - protected boolean isToggleEvent(KeyEvent e) { - return e.getKeyCode() == KeyEvent.VK_SPACE; - } - - protected boolean toggleNode(CheckedTreeNode node) { - boolean checked = !node.isChecked(); - checkNode(node, checked); - - // notify model listeners about model change - final TreeModel model = getModel(); - model.valueForPathChanged(new TreePath(node.getPath()), node.getUserObject()); - - return checked; - } - /** * Collect checked leaf nodes of the type {@code nodeType} and that are accepted by * {@code filter} @@ -144,38 +108,8 @@ public class CheckboxTreeBase extends Tree { * @param the type of the node * @return an array of collected nodes */ - @SuppressWarnings("unchecked") public T[] getCheckedNodes(final Class nodeType, @Nullable final NodeFilter filter) { - final ArrayList nodes = new ArrayList(); - final Object root = getModel().getRoot(); - if (!(root instanceof CheckedTreeNode)) { - throw new IllegalStateException( - "The root must be instance of the " + CheckedTreeNode.class.getName() + ": " + root.getClass().getName()); - } - new Object() { - @SuppressWarnings("unchecked") - public void collect(CheckedTreeNode node) { - if (node.isLeaf()) { - Object userObject = node.getUserObject(); - if (node.isChecked() && userObject != null && nodeType.isAssignableFrom(userObject.getClass())) { - final T value = (T)userObject; - if (filter != null && !filter.accept(value)) return; - nodes.add(value); - } - } - else { - for (int i = 0; i < node.getChildCount(); i++) { - final TreeNode child = node.getChildAt(i); - if (child instanceof CheckedTreeNode) { - collect((CheckedTreeNode)child); - } - } - } - } - }.collect((CheckedTreeNode)root); - T[] result = (T[])Array.newInstance(nodeType, nodes.size()); - nodes.toArray(result); - return result; + return CheckboxTreeHelper.getCheckedNodes(nodeType, filter, getModel()); } @@ -184,118 +118,14 @@ public class CheckboxTreeBase extends Tree { return -1; } - protected void checkNode(CheckedTreeNode node, boolean checked) { - adjustParentsAndChildren(node, checked); - repaint(); - } - protected void onNodeStateChanged(CheckedTreeNode node) { - } protected void nodeStateWillChange(CheckedTreeNode node) { - - } - - protected void adjustParentsAndChildren(final CheckedTreeNode node, final boolean checked) { - changeNodeState(node, checked); - if (!checked) { - if (myCheckPolicy.uncheckParentWithUncheckedChild) { - TreeNode parent = node.getParent(); - while (parent != null) { - if (parent instanceof CheckedTreeNode) { - changeNodeState((CheckedTreeNode)parent, false); - } - parent = parent.getParent(); - } - } - if (myCheckPolicy.uncheckChildrenWithUncheckedParent) { - uncheckChildren(node); - } - - } - else { - if (myCheckPolicy.checkChildrenWithCheckedParent) { - checkChildren(node); - } - - if (myCheckPolicy.checkParentWithCheckedChild) { - TreeNode parent = node.getParent(); - while (parent != null) { - if (parent instanceof CheckedTreeNode) { - changeNodeState((CheckedTreeNode)parent, true); - } - parent = parent.getParent(); - } - } - - } - repaint(); - } - - private void changeNodeState(final CheckedTreeNode node, final boolean checked) { - if (node.isChecked() != checked) { - nodeStateWillChange(node); - node.setChecked(checked); - onNodeStateChanged(node); - } - } - - private void uncheckChildren(final CheckedTreeNode node) { - final Enumeration children = node.children(); - while (children.hasMoreElements()) { - final Object o = children.nextElement(); - if (!(o instanceof CheckedTreeNode)) continue; - CheckedTreeNode child = (CheckedTreeNode)o; - changeNodeState(child, false); - uncheckChildren(child); - } - } - - private void checkChildren(final CheckedTreeNode node) { - final Enumeration children = node.children(); - while (children.hasMoreElements()) { - final Object o = children.nextElement(); - if (!(o instanceof CheckedTreeNode)) continue; - CheckedTreeNode child = (CheckedTreeNode)o; - changeNodeState(child, true); - checkChildren(child); - } } + @Deprecated protected void adjustParents(final CheckedTreeNode node, final boolean checked) { - TreeNode parentNode = node.getParent(); - if (!(parentNode instanceof CheckedTreeNode)) return; - CheckedTreeNode parent = (CheckedTreeNode)parentNode; - - if (!checked && isAllChildrenUnchecked(parent)) { - changeNodeState(parent, false); - adjustParents(parent, false); - } - else if (checked && isAllChildrenChecked(parent)) { - changeNodeState(parent, true); - adjustParents(parent, true); - } - } - - private static boolean isAllChildrenUnchecked(final CheckedTreeNode node) { - for (int i = 0; i < node.getChildCount(); i++) { - final TreeNode o = node.getChildAt(i); - if ((o instanceof CheckedTreeNode) && ((CheckedTreeNode)o).isChecked()) { - return false; - } - } - return true; - } - - private static boolean isAllChildrenChecked(final CheckedTreeNode node) { - for (int i = 0; i < node.getChildCount(); i++) { - final TreeNode o = node.getChildAt(i); - if ((o instanceof CheckedTreeNode) && !((CheckedTreeNode)o).isChecked()) { - return false; - } - } - return true; } public static class CheckboxTreeCellRendererBase extends JPanel implements TreeCellRenderer { @@ -395,8 +225,8 @@ public class CheckboxTreeBase extends Tree { } /** - * @deprecated * @see CheckboxTreeCellRendererBase#customizeRenderer(javax.swing.JTree, Object, boolean, boolean, boolean, int, boolean) + * @deprecated */ @Deprecated public void customizeCellRenderer(JTree tree, diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/impl/CheckboxTreeTable.java b/platform/platform-api/src/com/intellij/ui/CheckboxTreeHelper.java similarity index 55% rename from platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/impl/CheckboxTreeTable.java rename to platform/platform-api/src/com/intellij/ui/CheckboxTreeHelper.java index dd72da957fa2..3048d131caa7 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/impl/CheckboxTreeTable.java +++ b/platform/platform-api/src/com/intellij/ui/CheckboxTreeHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -13,19 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.openapi.roots.libraries.ui.impl; +package com.intellij.ui; -import com.intellij.ui.CheckboxTree; -import com.intellij.ui.CheckedTreeNode; -import com.intellij.ui.ClickListener; -import com.intellij.ui.dualView.TreeTableView; -import com.intellij.ui.treeStructure.treetable.ListTreeTableModelOnColumns; -import com.intellij.ui.treeStructure.treetable.TreeTableTree; -import com.intellij.util.ui.ColumnInfo; +import com.intellij.ui.speedSearch.SpeedSearchSupply; +import com.intellij.ui.treeStructure.Tree; +import com.intellij.util.EventDispatcher; import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import javax.swing.tree.DefaultTreeModel; +import javax.swing.*; import javax.swing.tree.TreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; @@ -40,21 +37,135 @@ import java.util.Enumeration; /** * @author nik */ -public class CheckboxTreeTable extends TreeTableView { - public CheckboxTreeTable(CheckedTreeNode root, CheckboxTree.CheckboxTreeCellRenderer renderer, final ColumnInfo[] columns) { - super(new ListTreeTableModelOnColumns(root, columns)); - initTree(getTree(), renderer); +class CheckboxTreeHelper { + static final CheckboxTreeBase.CheckPolicy DEFAULT_POLICY = new CheckboxTreeBase.CheckPolicy(true, true, false, true); + private final CheckboxTreeBase.CheckPolicy myCheckPolicy; + private final EventDispatcher myEventDispatcher; + + CheckboxTreeHelper(CheckboxTreeBase.CheckPolicy checkPolicy, EventDispatcher dispatcher) { + myCheckPolicy = checkPolicy; + myEventDispatcher = dispatcher; } - //todo[nik] I hate to copy-paste but have to copy the code below from CheckboxTreeBase to support CheckboxTree inside TreeTable in IDEA 11.1.x branch - //todo[nik] I solemnly swear to get rid of this code in IDEA 12 branch - private void initTree(final TreeTableTree tree, final CheckboxTree.CheckboxTreeCellRenderer cellRenderer) { + public void initTree(@NotNull final Tree tree, JComponent mainComponent, CheckboxTreeBase.CheckboxTreeCellRendererBase cellRenderer) { tree.setCellRenderer(cellRenderer); tree.setRootVisible(false); tree.setShowsRootHandles(true); tree.setLineStyleAngled(); TreeUtil.installActions(tree); + setupKeyListener(tree, mainComponent); + setupMouseListener(tree, mainComponent, cellRenderer); + } + + public void setNodeState(Tree tree, CheckedTreeNode node, boolean checked) { + changeNodeState(node, checked); + adjustParentsAndChildren(node, checked); + tree.repaint(); + + // notify model listeners about model change + final TreeModel model = tree.getModel(); + model.valueForPathChanged(new TreePath(node.getPath()), node.getUserObject()); + } + + private void toggleNode(Tree tree, CheckedTreeNode node) { + setNodeState(tree, node, !node.isChecked()); + } + + private void adjustParentsAndChildren(final CheckedTreeNode node, final boolean checked) { + if (!checked) { + if (myCheckPolicy.uncheckParentWithUncheckedChild) { + TreeNode parent = node.getParent(); + while (parent != null) { + if (parent instanceof CheckedTreeNode) { + changeNodeState((CheckedTreeNode)parent, false); + } + parent = parent.getParent(); + } + } + if (myCheckPolicy.uncheckChildrenWithUncheckedParent) { + uncheckChildren(node); + } + } + else { + if (myCheckPolicy.checkChildrenWithCheckedParent) { + checkChildren(node); + } + + if (myCheckPolicy.checkParentWithCheckedChild) { + TreeNode parent = node.getParent(); + while (parent != null) { + if (parent instanceof CheckedTreeNode) { + changeNodeState((CheckedTreeNode)parent, true); + } + parent = parent.getParent(); + } + } + } + } + + private void changeNodeState(final CheckedTreeNode node, final boolean checked) { + if (node.isChecked() != checked) { + myEventDispatcher.getMulticaster().beforeNodeStateChanged(node); + node.setChecked(checked); + myEventDispatcher.getMulticaster().nodeStateChanged(node); + } + } + + private void uncheckChildren(final CheckedTreeNode node) { + final Enumeration children = node.children(); + while (children.hasMoreElements()) { + final Object o = children.nextElement(); + if (!(o instanceof CheckedTreeNode)) continue; + CheckedTreeNode child = (CheckedTreeNode)o; + changeNodeState(child, false); + uncheckChildren(child); + } + } + + private void checkChildren(final CheckedTreeNode node) { + final Enumeration children = node.children(); + while (children.hasMoreElements()) { + final Object o = children.nextElement(); + if (!(o instanceof CheckedTreeNode)) continue; + CheckedTreeNode child = (CheckedTreeNode)o; + changeNodeState(child, true); + checkChildren(child); + } + } + + private void setupKeyListener(final Tree tree, final JComponent mainComponent) { + mainComponent.addKeyListener(new KeyAdapter() { + public void keyPressed(@NotNull KeyEvent e) { + if (isToggleEvent(e, mainComponent)) { + TreePath treePath = tree.getLeadSelectionPath(); + if (treePath == null) return; + final Object o = treePath.getLastPathComponent(); + if (!(o instanceof CheckedTreeNode)) return; + CheckedTreeNode firstNode = (CheckedTreeNode)o; + toggleNode(tree, firstNode); + boolean checked = firstNode.isChecked(); + + TreePath[] selectionPaths = tree.getSelectionPaths(); + for (int i = 0; selectionPaths != null && i < selectionPaths.length; i++) { + final TreePath selectionPath = selectionPaths[i]; + final Object o1 = selectionPath.getLastPathComponent(); + if (!(o1 instanceof CheckedTreeNode)) continue; + CheckedTreeNode node = (CheckedTreeNode)o1; + setNodeState(tree, node, checked); + } + + e.consume(); + } + } + }); + } + + private static boolean isToggleEvent(KeyEvent e, JComponent mainComponent) { + return e.getKeyCode() == KeyEvent.VK_SPACE && SpeedSearchSupply.getSupply(mainComponent) == null; + } + + private void setupMouseListener(final Tree tree, JComponent mainComponent, final CheckboxTreeBase.CheckboxTreeCellRendererBase cellRenderer) { new ClickListener() { @Override public boolean onClick(@NotNull MouseEvent e, int clickCount) { @@ -67,122 +178,33 @@ public class CheckboxTreeTable extends TreeTableView { Rectangle checkBounds = cellRenderer.myCheckbox.getBounds(); checkBounds.setLocation(rowBounds.getLocation()); - if (checkBounds.height == 0) checkBounds.height = rowBounds.height; + if (checkBounds.height == 0) checkBounds.height = checkBounds.width = rowBounds.height; final CheckedTreeNode node = (CheckedTreeNode)o; if (checkBounds.contains(e.getPoint())) { if (node.isEnabled()) { - toggleNode(node); + toggleNode(tree, node); tree.setSelectionRow(row); return true; } } + else if (clickCount > 1) { + myEventDispatcher.getMulticaster().mouseDoubleClicked(node); + return true; + } return false; } - }.installOn(this); - - addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent e) { - if (isToggleEvent(e)) { - TreePath treePath = tree.getLeadSelectionPath(); - if (treePath == null) return; - final Object o = treePath.getLastPathComponent(); - if (!(o instanceof CheckedTreeNode)) return; - CheckedTreeNode firstNode = (CheckedTreeNode)o; - boolean checked = toggleNode(firstNode); - - TreePath[] selectionPaths = tree.getSelectionPaths(); - for (int i = 0; selectionPaths != null && i < selectionPaths.length; i++) { - final TreePath selectionPath = selectionPaths[i]; - final Object o1 = selectionPath.getLastPathComponent(); - if (!(o1 instanceof CheckedTreeNode)) continue; - CheckedTreeNode node = (CheckedTreeNode)o1; - checkNode(node, checked); - ((DefaultTreeModel)tree.getModel()).nodeChanged(node); - } - - e.consume(); - } - } - }); - - tree.setSelectionRow(0); - } - - private static boolean isToggleEvent(KeyEvent e) { - return e.getKeyCode() == KeyEvent.VK_SPACE; - } - - protected boolean toggleNode(CheckedTreeNode node) { - boolean checked = !node.isChecked(); - checkNode(node, checked); - - // notify model listeners about model change - final TreeModel model = getTree().getModel(); - model.valueForPathChanged(new TreePath(node.getPath()), node.getUserObject()); - - return checked; - } - - private void checkNode(CheckedTreeNode node, boolean checked) { - adjustParentsAndChildren(node, checked); - repaint(); - } - - private void adjustParentsAndChildren(final CheckedTreeNode node, final boolean checked) { - changeNodeState(node, checked); - if (!checked) { - TreeNode parent = node.getParent(); - while (parent != null) { - if (parent instanceof CheckedTreeNode) { - changeNodeState((CheckedTreeNode)parent, false); - } - parent = parent.getParent(); - } - uncheckChildren(node); - } - else { - checkChildren(node); - } - repaint(); - } - - private static void changeNodeState(final CheckedTreeNode node, final boolean checked) { - if (node.isChecked() != checked) { - node.setChecked(checked); - } - } - - private static void uncheckChildren(final CheckedTreeNode node) { - final Enumeration children = node.children(); - while (children.hasMoreElements()) { - final Object o = children.nextElement(); - if (!(o instanceof CheckedTreeNode)) continue; - CheckedTreeNode child = (CheckedTreeNode)o; - changeNodeState(child, false); - uncheckChildren(child); - } - } - - private static void checkChildren(final CheckedTreeNode node) { - final Enumeration children = node.children(); - while (children.hasMoreElements()) { - final Object o = children.nextElement(); - if (!(o instanceof CheckedTreeNode)) continue; - CheckedTreeNode child = (CheckedTreeNode)o; - changeNodeState(child, true); - checkChildren(child); - } + }.installOn(mainComponent); } @SuppressWarnings("unchecked") - public T[] getCheckedNodes(final Class nodeType) { + public static T[] getCheckedNodes(final Class nodeType, @Nullable final Tree.NodeFilter filter, final TreeModel model) { final ArrayList nodes = new ArrayList(); - final Object root = getTree().getModel().getRoot(); + final Object root = model.getRoot(); if (!(root instanceof CheckedTreeNode)) { - throw new IllegalStateException("The root must be instance of the " + CheckedTreeNode.class.getName() + ": " + root.getClass().getName()); + throw new IllegalStateException( + "The root must be instance of the " + CheckedTreeNode.class.getName() + ": " + root.getClass().getName()); } new Object() { @SuppressWarnings("unchecked") @@ -191,6 +213,7 @@ public class CheckboxTreeTable extends TreeTableView { Object userObject = node.getUserObject(); if (node.isChecked() && userObject != null && nodeType.isAssignableFrom(userObject.getClass())) { final T value = (T)userObject; + if (filter != null && !filter.accept(value)) return; nodes.add(value); } } diff --git a/platform/platform-api/src/com/intellij/ui/CheckboxTreeListener.java b/platform/platform-api/src/com/intellij/ui/CheckboxTreeListener.java new file mode 100644 index 000000000000..792c4589c85d --- /dev/null +++ b/platform/platform-api/src/com/intellij/ui/CheckboxTreeListener.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2014 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.ui; + +import org.jetbrains.annotations.NotNull; + +import java.util.EventListener; + +/** + * @author nik + */ +public interface CheckboxTreeListener extends EventListener { + void mouseDoubleClicked(@NotNull CheckedTreeNode node); + + void nodeStateChanged(@NotNull CheckedTreeNode node); + + void beforeNodeStateChanged(@NotNull CheckedTreeNode node); +} diff --git a/platform/platform-api/src/com/intellij/ui/JBSplitter.java b/platform/platform-api/src/com/intellij/ui/JBSplitter.java index b4000dbcfae2..5f01602d92c5 100644 --- a/platform/platform-api/src/com/intellij/ui/JBSplitter.java +++ b/platform/platform-api/src/com/intellij/ui/JBSplitter.java @@ -94,14 +94,6 @@ public class JBSplitter extends Splitter { saveProportion(); } - public void setOnePixelMode() { - setDividerWidth(1); - setShowDividerIcon(false); - getDivider().setBackground(new JBColor(Gray._153.withAlpha(128), Gray._100.withAlpha(128))); - setShowDividerControls(false); - setOrientation(getOrientation()); - } - protected void loadProportion() { if (! StringUtil.isEmpty(mySplitterProportionKey)) { setProportion(PropertiesComponent.getInstance().getFloat(mySplitterProportionKey, myProportion)); diff --git a/platform/platform-api/src/com/intellij/ui/OnePixelSplitter.java b/platform/platform-api/src/com/intellij/ui/OnePixelSplitter.java new file mode 100644 index 000000000000..15dd5fdc2abb --- /dev/null +++ b/platform/platform-api/src/com/intellij/ui/OnePixelSplitter.java @@ -0,0 +1,59 @@ +/* + * Copyright 2000-2014 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.ui; + +import com.intellij.openapi.ui.Divider; +import com.intellij.openapi.ui.OnePixelDivider; + +/** + * @author Konstantin Bulenkov + */ +public class OnePixelSplitter extends JBSplitter { + + public OnePixelSplitter() { + super(); + init(); + } + + public OnePixelSplitter(boolean vertical) { + super(vertical); + init(); + } + + public OnePixelSplitter(boolean vertical, float proportion) { + super(vertical, proportion); + init(); + } + + public OnePixelSplitter(float proportion) { + super(proportion); + init(); + } + + public OnePixelSplitter(boolean vertical, float proportion, float minProp, float maxProp) { + super(vertical, proportion, minProp, maxProp); + init(); + } + + protected void init() { + setDividerWidth(1); + } + + @Override + protected Divider createDivider() { + return new OnePixelDivider(isVertical(), this); + } +} diff --git a/platform/platform-api/src/com/intellij/ui/tabs/TabInfo.java b/platform/platform-api/src/com/intellij/ui/tabs/TabInfo.java index d1dfa976e479..c8c944c86e4a 100644 --- a/platform/platform-api/src/com/intellij/ui/tabs/TabInfo.java +++ b/platform/platform-api/src/com/intellij/ui/tabs/TabInfo.java @@ -92,6 +92,7 @@ public final class TabInfo implements Queryable, PlaceProvider { * out of its container. (IDEA-61536) */ private WeakReference myPreviousSelection = new WeakReference(null); + private boolean myTitleShortened; public TabInfo(final JComponent component) { myComponent = component; @@ -392,6 +393,14 @@ public final class TabInfo implements Queryable, PlaceProvider { return myPreviousSelection.get(); } + public boolean isTitleShortened() { + return myTitleShortened; + } + + public void setTitleIsShortened(boolean titleIsShortened) { + myTitleShortened = titleIsShortened; + } + public interface DragOutDelegate { void dragOutStarted(MouseEvent mouseEvent, TabInfo info); diff --git a/platform/platform-api/src/com/intellij/ui/tabs/impl/JBEditorTabs.java b/platform/platform-api/src/com/intellij/ui/tabs/impl/JBEditorTabs.java index 8e5844fd4684..a842f623ac45 100644 --- a/platform/platform-api/src/com/intellij/ui/tabs/impl/JBEditorTabs.java +++ b/platform/platform-api/src/com/intellij/ui/tabs/impl/JBEditorTabs.java @@ -44,6 +44,7 @@ import java.util.List; */ public class JBEditorTabs extends JBTabsImpl { public static final String TABS_ALPHABETICAL_KEY = "tabs.alphabetical"; + static final String TABS_SHORTEN_TITLE_IF_NEED = "tabs.shorten.title.if.need"; private JBEditorTabsPainter myDarkPainter = new DarculaEditorTabsPainter(); private JBEditorTabsPainter myDefaultPainter = new DefaultEditorTabsPainter(); @@ -60,6 +61,13 @@ public class JBEditorTabs extends JBTabsImpl { return super.createSingleRowLayout(); } + @Override + protected TabLabel createTabLabel(TabInfo info) { + TabLabel label = super.createTabLabel(info); + label.putClientProperty(TABS_SHORTEN_TITLE_IF_NEED, Boolean.TRUE); + return label; + } + @Override public boolean isEditorTabs() { return true; diff --git a/platform/platform-api/src/com/intellij/ui/tabs/impl/TabLabel.java b/platform/platform-api/src/com/intellij/ui/tabs/impl/TabLabel.java index 21c36d5dd66a..a360c4e9294f 100644 --- a/platform/platform-api/src/com/intellij/ui/tabs/impl/TabLabel.java +++ b/platform/platform-api/src/com/intellij/ui/tabs/impl/TabLabel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -22,6 +22,7 @@ import com.intellij.openapi.actionSystem.ActionPlaces; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.util.Pass; import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.*; import com.intellij.ui.components.panels.Wrapper; import com.intellij.ui.tabs.JBTabsPosition; @@ -317,6 +318,16 @@ public class TabLabel extends JPanel { public void setText(final SimpleColoredText text) { + myInfo.setTitleIsShortened(false); + if (text != null && text.getTexts().size() == 1 && Boolean.TRUE == getClientProperty(JBEditorTabs.TABS_SHORTEN_TITLE_IF_NEED)) { + String title = text.getTexts().get(0); + if (title.length() > UISettings.getInstance().EDITOR_TAB_TITLE_LIMIT) { + SimpleTextAttributes attributes = text.getAttributes().get(0); + text.clear(); + text.append(StringUtil.getShortened(title, UISettings.getInstance().EDITOR_TAB_TITLE_LIMIT), attributes); + myInfo.setTitleIsShortened(true); + } + } myLabel.change(new Runnable() { public void run() { myLabel.clear(); diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/actions/CompareClipboardWithSelection.java b/platform/platform-impl/src/com/intellij/openapi/diff/actions/CompareClipboardWithSelection.java index a916d9e5bb34..372b14efcfe6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/actions/CompareClipboardWithSelection.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/actions/CompareClipboardWithSelection.java @@ -73,8 +73,9 @@ public class CompareClipboardWithSelection extends BaseDiffAction { SelectionModel selectionModel = myEditor.getSelectionModel(); if (selectionModel.hasSelection()) { TextRange range = new TextRange(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd()); + boolean forceReadOnly = myEditor.isViewer(); myContents[1] = new FragmentContent(DiffContent.fromDocument(getProject(), getDocument()), - range, getProject(), getDocumentFile(getDocument())); + range, getProject(), getDocumentFile(getDocument()), forceReadOnly); } else { myContents [1] = DiffContent.fromDocument(getProject(), getDocument()); diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffSplitter.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffSplitter.java index 5f4507dcfad3..4b6a289d476e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffSplitter.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffSplitter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -19,6 +19,7 @@ import com.intellij.openapi.diff.impl.highlighting.DiffPanelState; import com.intellij.openapi.diff.impl.splitter.DiffDividerPaint; import com.intellij.openapi.editor.event.VisibleAreaEvent; import com.intellij.openapi.editor.event.VisibleAreaListener; +import com.intellij.openapi.ui.Divider; import com.intellij.openapi.ui.Splitter; import javax.swing.*; @@ -43,8 +44,8 @@ class DiffSplitter extends Splitter implements DiffSplitterI { setHonorComponentsMinimumSize(false); } - protected Splitter.Divider createDivider() { - return new Divider(){ + protected Divider createDivider() { + return new DividerImpl(){ public void paint(Graphics g) { super.paint(g); myPaint.paint(g, this); diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java index c2353d5db207..03b03faffe03 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java @@ -277,6 +277,8 @@ public final class EditorTabbedContainer implements Disposable, CloseAction.Clos myTabs.getTabAt(index).setTooltipText(text); } + public boolean isTitleShortened(int index) { return myTabs.getTabAt(index).isTitleShortened(); } + public void setBackgroundColorAt(final int index, final Color color) { myTabs.getTabAt(index).setTabColor(color); } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java index 14b2afe16345..06a3966ade1d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java @@ -464,6 +464,10 @@ public class EditorWindow { } } + private boolean isTitleShortenedAt(int index) { + return myTabbedPane != null && myTabbedPane.isTitleShortened(index); + } + private void setBackgroundColorAt(final int index, final Color color) { if (myTabbedPane != null) { myTabbedPane.setBackgroundColorAt(index, color); @@ -908,7 +912,9 @@ public class EditorWindow { final int index = findEditorIndex(findFileComposite(file)); if (index != -1) { setTitleAt(index, EditorTabbedContainer.calcTabTitle(getManager().getProject(), file)); - setToolTipTextAt(index, UISettings.getInstance().SHOW_TABS_TOOLTIPS ? getManager().getFileTooltipText(file) : null); + setToolTipTextAt(index, UISettings.getInstance().SHOW_TABS_TOOLTIPS || isTitleShortenedAt(index) + ? getManager().getFileTooltipText(file) + : null); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorProvider.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorProvider.java index 60b42f75c22c..690e7c7d2820 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorProvider.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorProvider.java @@ -278,19 +278,22 @@ public class TextEditorProvider implements FileEditorProvider, DumbAware { } protected void setStateImpl(final Project project, final Editor editor, final TextEditorState state){ - if (editor.getCaretModel().supportsMultipleCarets()) { - CaretModel caretModel = editor.getCaretModel(); - List states = new ArrayList(state.CARETS.length); - for (TextEditorState.CaretState caretState : state.CARETS) { - states.add(new CaretState(new LogicalPosition(caretState.LINE, caretState.COLUMN), - new LogicalPosition(caretState.SELECTION_START_LINE, caretState.SELECTION_START_COLUMN), - new LogicalPosition(caretState.SELECTION_END_LINE, caretState.SELECTION_END_COLUMN))); + if (state.CARETS != null) { + if (editor.getCaretModel().supportsMultipleCarets()) { + CaretModel caretModel = editor.getCaretModel(); + List states = new ArrayList(state.CARETS.length); + for (TextEditorState.CaretState caretState : state.CARETS) { + states.add(new CaretState(new LogicalPosition(caretState.LINE, caretState.COLUMN), + new LogicalPosition(caretState.SELECTION_START_LINE, caretState.SELECTION_START_COLUMN), + new LogicalPosition(caretState.SELECTION_END_LINE, caretState.SELECTION_END_COLUMN))); + } + caretModel.setCaretsAndSelections(states); + } + else { + LogicalPosition pos = new LogicalPosition(state.CARETS[0].LINE, state.CARETS[0].COLUMN); + editor.getCaretModel().moveToLogicalPosition(pos); + editor.getSelectionModel().removeSelection(); } - caretModel.setCaretsAndSelections(states); - } else { - LogicalPosition pos = new LogicalPosition(state.CARETS[0].LINE, state.CARETS[0].COLUMN); - editor.getCaretModel().moveToLogicalPosition(pos); - editor.getSelectionModel().removeSelection(); } EditorEx editorEx = editor instanceof EditorEx ? (EditorEx)editor : null; boolean preciselyScrollVertically = diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeGlassPaneImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeGlassPaneImpl.java index d33ef5bfb3d1..71f964504102 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeGlassPaneImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeGlassPaneImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -21,8 +21,8 @@ import com.intellij.ide.dnd.DnDAware; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.ui.Divider; import com.intellij.openapi.ui.Painter; -import com.intellij.openapi.ui.Splitter; import com.intellij.openapi.ui.impl.GlassPaneDialogWrapperPeer; import com.intellij.openapi.ui.popup.Balloon; import com.intellij.openapi.ui.popup.JBPopupFactory; @@ -381,7 +381,7 @@ public class IdeGlassPaneImpl extends JPanel implements IdeGlassPaneEx, IdeEvent private boolean canProcessCursorFor(Component target) { if (target instanceof JMenu || target instanceof JMenuItem || - target instanceof Splitter.Divider || + target instanceof Divider || target instanceof JSeparator || (target instanceof JEditorPane && ((JEditorPane)target).getEditorKit() instanceof HTMLEditorKit)) { return false; diff --git a/platform/platform-impl/src/com/intellij/ui/CheckboxTree.java b/platform/platform-impl/src/com/intellij/ui/CheckboxTree.java index c91be65978c1..1443a9303e39 100644 --- a/platform/platform-impl/src/com/intellij/ui/CheckboxTree.java +++ b/platform/platform-impl/src/com/intellij/ui/CheckboxTree.java @@ -15,8 +15,6 @@ */ package com.intellij.ui; -import java.awt.event.KeyEvent; - /** * User: lex * Date: Sep 18, 2003 @@ -56,11 +54,4 @@ public class CheckboxTree extends CheckboxTreeBase { protected void installSpeedSearch() { new TreeSpeedSearch(this); } - - - protected boolean isToggleEvent(KeyEvent e) { - return super.isToggleEvent(e) && !SpeedSearchBase.hasActiveSpeedSearch(this); - } - - } diff --git a/platform/platform-impl/src/com/intellij/ui/CheckboxTreeTable.java b/platform/platform-impl/src/com/intellij/ui/CheckboxTreeTable.java new file mode 100644 index 000000000000..369dd0cc1803 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ui/CheckboxTreeTable.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2012 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.ui; + +import com.intellij.ui.dualView.TreeTableView; +import com.intellij.ui.treeStructure.treetable.ListTreeTableModelOnColumns; +import com.intellij.ui.treeStructure.treetable.TreeTableTree; +import com.intellij.util.EventDispatcher; +import com.intellij.util.ui.ColumnInfo; +import org.jetbrains.annotations.NotNull; + +/** + * @author nik + */ +public class CheckboxTreeTable extends TreeTableView { + private final EventDispatcher myEventDispatcher; + + public CheckboxTreeTable(CheckedTreeNode root, CheckboxTree.CheckboxTreeCellRenderer renderer, final ColumnInfo[] columns) { + super(new ListTreeTableModelOnColumns(root, columns)); + final TreeTableTree tree = getTree(); + myEventDispatcher = EventDispatcher.create(CheckboxTreeListener.class); + CheckboxTreeHelper helper = new CheckboxTreeHelper(CheckboxTreeHelper.DEFAULT_POLICY, myEventDispatcher); + helper.initTree(tree, this, renderer); + tree.setSelectionRow(0); + } + + public void addCheckboxTreeListener(@NotNull CheckboxTreeListener listener) { + myEventDispatcher.addListener(listener); + } + + public T[] getCheckedNodes(final Class nodeType) { + return CheckboxTreeHelper.getCheckedNodes(nodeType, null, getTree().getModel()); + } +} diff --git a/platform/platform-impl/src/com/intellij/ui/SplitterWithSecondHideable.java b/platform/platform-impl/src/com/intellij/ui/SplitterWithSecondHideable.java index 99c41b52cbea..e219b778f44d 100644 --- a/platform/platform-impl/src/com/intellij/ui/SplitterWithSecondHideable.java +++ b/platform/platform-impl/src/com/intellij/ui/SplitterWithSecondHideable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -16,6 +16,7 @@ package com.intellij.ui; import com.intellij.icons.AllIcons; +import com.intellij.openapi.ui.Divider; import com.intellij.openapi.ui.PseudoSplitter; import com.intellij.openapi.ui.Splitter; import com.intellij.openapi.vcs.changes.RefreshablePanel; @@ -41,7 +42,7 @@ public abstract class SplitterWithSecondHideable { private final boolean myVertical; private final OnOffListener myListener; private final JPanel myFictivePanel; - private Splitter.Divider mySuperDivider; + private Splitter.DividerImpl mySuperDivider; private float myPreviousProportion; public SplitterWithSecondHideable(final boolean vertical, @@ -185,7 +186,7 @@ public abstract class SplitterWithSecondHideable { return vertical ? myTitledSeparator.getHeight() : myTitledSeparator.getWidth(); } - class MyDivider extends Divider { + class MyDivider extends DividerImpl { @Override public void processMouseMotionEvent(MouseEvent e) { super.processMouseMotionEvent(e); diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties index bbd737afedf1..5d539357ca3d 100644 --- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties +++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties @@ -360,6 +360,7 @@ label.collapse.by.default=Collapse by default: checkbox.show.code.folding.outline=Show code folding outline group.tab.appearance=Tab Appearance editbox.tab.limit=Tab limit: +editbox.tab.title.limit=Tab title limit: combobox.editor.tab.placement=Placement: checkbox.editor.tabs.in.single.row=Show tabs in single row checkbox.editor.tabs.show.close.button=Show "close" button on editor tabs diff --git a/platform/platform-resources/src/idea/Keymap_EclipseMac.xml b/platform/platform-resources/src/idea/Keymap_EclipseMac.xml index dc1dcb5e66ec..f35e24c776b0 100644 --- a/platform/platform-resources/src/idea/Keymap_EclipseMac.xml +++ b/platform/platform-resources/src/idea/Keymap_EclipseMac.xml @@ -312,6 +312,10 @@ + + + + diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/CompiledPattern.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/CompiledPattern.java index 565f80ac01ce..70c1cdccd03e 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/CompiledPattern.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/CompiledPattern.java @@ -82,7 +82,7 @@ public abstract class CompiledPattern { public boolean isRealTypedVar(PsiElement element) { if (element!=null && element.getTextLength()>0) { String str = getTypedVarString(element); - if (str.length()==0) { + if (str == null || str.length()==0) { return false; } return isTypedVar( str ); diff --git a/platform/usageView/src/com/intellij/usages/ChunkExtractor.java b/platform/usageView/src/com/intellij/usages/ChunkExtractor.java index eea15c93605d..dbbaeb48b72f 100644 --- a/platform/usageView/src/com/intellij/usages/ChunkExtractor.java +++ b/platform/usageView/src/com/intellij/usages/ChunkExtractor.java @@ -204,7 +204,7 @@ public class ChunkExtractor { highlighter.restart(chars); myDocumentStamp = myDocument.getModificationStamp(); } else if(lexer.getTokenStart() > start) { - highlighter.resetPosition(0); + highlighter.resetPosition(0); // todo restart from nearest position with initial state } boolean isBeginning = true; diff --git a/platform/usageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java b/platform/usageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java index d6c47e658df6..418890ce17d9 100644 --- a/platform/usageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java +++ b/platform/usageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java @@ -40,10 +40,7 @@ import com.intellij.usageView.UsageInfo; import com.intellij.usageView.UsageViewBundle; import com.intellij.usages.impl.rules.UsageType; import com.intellij.usages.rules.*; -import com.intellij.util.ArrayUtil; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.NotNullFunction; -import com.intellij.util.Processor; +import com.intellij.util.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -80,7 +77,8 @@ public class UsageInfo2UsageAdapter implements UsageInModule, private final int myLineNumber; private final int myOffset; protected Icon myIcon; - private Reference myTextChunks; // allow to be gced and recreated on-demand because it requires a lot of memory + private volatile Reference myTextChunks; // allow to be gced and recreated on-demand because it requires a lot of memory + private volatile UsageType myUsageType; public UsageInfo2UsageAdapter(@NotNull final UsageInfo usageInfo) { myUsageInfo = usageInfo; @@ -337,7 +335,7 @@ public class UsageInfo2UsageAdapter implements UsageInModule, UsageInfo[] merged = ArrayUtil.mergeArrays(getMergedInfos(), u2.getMergedInfos()); myMergedUsageInfos = merged.length == 1 ? merged[0] : merged; Arrays.sort(getMergedInfos(), BY_NAVIGATION_OFFSET); - initChunks(); + myTextChunks = null; // chunks will be rebuilt lazily (IDEA-126048) return true; } @@ -496,13 +494,42 @@ public class UsageInfo2UsageAdapter implements UsageInModule, } public @Nullable UsageType getUsageType() { - TextChunk[] chunks = getText(); - for(TextChunk chunk:chunks) { - UsageType type = chunk.getType(); - if (type != null) { - return type; + UsageType usageType = myUsageType; + + if (usageType == null) { + usageType = UsageType.UNCLASSIFIED; + PsiFile file = getPsiFile(); + + if (file != null) { + ChunkExtractor extractor = ChunkExtractor.getExtractor(file); + Segment segment = getFirstSegment(); + + if (segment != null) { + Document document = PsiDocumentManager.getInstance(getProject()).getDocument(file); + + if (document != null) { + SmartList chunks = new SmartList(); + extractor.createTextChunks( + this, + document.getCharsSequence(), + segment.getStartOffset(), + segment.getEndOffset(), + false, + chunks + ); + + for(TextChunk chunk:chunks) { + UsageType chunkUsageType = chunk.getType(); + if (chunkUsageType != null) { + usageType = chunkUsageType; + break; + } + } + } + } } + myUsageType = usageType; } - return null; + return usageType; } } diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 99ff576c6ad6..bb8246ebc351 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -388,7 +388,7 @@ console.too.much.text.buffer.ratio.description=Used for disabling of console pro when there is too much of text to process.\n\ The ratio is used against the console cycle buffer size (idea.cycle.buffer.size/theRatio=maxTextLength). ide.file.settings.order.new=false -ide.new.project.settings=false +ide.new.project.settings=true ide.new.project.settings.description=Temporary key for new project settings dialog UI commonjs.complete.required.filename.with.extension=false diff --git a/platform/util/src/com/intellij/openapi/ui/Divider.java b/platform/util/src/com/intellij/openapi/ui/Divider.java new file mode 100644 index 000000000000..1b2b6b1a3d6a --- /dev/null +++ b/platform/util/src/com/intellij/openapi/ui/Divider.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2014 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.ui; + +import javax.swing.*; +import java.awt.*; + +/** + * @author Konstantin Bulenkov + */ +public abstract class Divider extends JPanel { + public Divider(LayoutManager layout) { + super(layout); + } + + public abstract void setResizeEnabled(boolean resizeEnabled); + + public abstract void setSwitchOrientationEnabled(boolean switchOrientationEnabled); + + public abstract void setOrientation(boolean vertical); +} diff --git a/platform/util/src/com/intellij/openapi/ui/Splitter.java b/platform/util/src/com/intellij/openapi/ui/Splitter.java index 44d2317088c6..71a026702563 100644 --- a/platform/util/src/com/intellij/openapi/ui/Splitter.java +++ b/platform/util/src/com/intellij/openapi/ui/Splitter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -177,7 +177,7 @@ public class Splitter extends JPanel { } protected Divider createDivider() { - return new Divider(); + return new DividerImpl(); } @Override @@ -481,12 +481,12 @@ public class Splitter extends JPanel { return myDivider; } - public class Divider extends JPanel { + public class DividerImpl extends Divider { private boolean myResizeEnabled; private boolean mySwitchOrientationEnabled; protected Point myPoint; - public Divider() { + public DividerImpl() { super(new GridBagLayout()); myResizeEnabled = true; mySwitchOrientationEnabled = false; @@ -496,7 +496,7 @@ public class Splitter extends JPanel { setOrientation(myVerticalSplit); } - private void setOrientation(boolean isVerticalSplit) { + public void setOrientation(boolean isVerticalSplit) { removeAll(); setCursor(isVertical() ? diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java index 3556f1cce3bd..61ec6edb41cd 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java @@ -2658,6 +2658,56 @@ public class StringUtil extends StringUtilRt { return s.startsWith(smallPart.toLowerCase()) && bigPart.toLowerCase().startsWith(s); } + public static String getShortened(String s, int maxWidth) { + int length = s.length(); + if (isEmpty(s) || length <= maxWidth) return s; + ArrayList words = new ArrayList(); + + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < length; i++) { + char ch = s.charAt(i); + + if (i == length - 1) { + builder.append(ch); + words.add(builder.toString()); + builder.delete(0, builder.length()); + continue; + } + + if (i > 0 && (ch == '/' || ch == '.' || Character.isUpperCase(ch))) { + words.add(builder.toString()); + builder.delete(0, builder.length()); + } + builder.append(ch); + } + + int removedLength = 0; + + String toPaste = "..."; + int index; + while (true) { + index = Math.max(0, words.size() / 2 - 1); + String aWord = words.get(index); + words.remove(index); + if (words.size() < 2) { + int toCut = length - removedLength - maxWidth + 3; + int pos = (aWord.length() - toCut) / 2; + toPaste = aWord.substring(0, pos) + "..." + aWord.substring(pos+toCut); + break; + } + removedLength += aWord.length(); + if (length - removedLength <= maxWidth - 3) { + break; + } + } + for (int i = 0; i < words.size(); i++) { + String word = words.get(i); + if (i == index || words.size() == 1) builder.append(toPaste); + builder.append(word); + } + return builder.toString().replaceAll("\\.{4,}", "..."); + } + /** * Expirable CharSequence. Very useful to control external library execution time, * i.e. when java.util.regex.Pattern match goes out of control. diff --git a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java index 2f31dc4f4e61..e1d28d247d72 100644 --- a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java +++ b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java @@ -195,4 +195,15 @@ public class StringUtilTest extends TestCase { assertEquals(Arrays.asList("\n", "\r\n", "\n", "\r\n", "\r", "\r", "aa\r", "bb\r\n", "cc\n", "\r", "dd\n", "\n", "\r\n", "\r"), Arrays.asList(StringUtil.splitByLinesKeepSeparators("\n\r\n\n\r\n\r\raa\rbb\r\ncc\n\rdd\n\n\r\n\r"))); } + + public void testShortened() { + String[] names = {"AVeryVeeryLongClassName.java", "com.test.SomeJAVAClassName.java", "strangelowercaseclassname.java"}; + for (String name : names) { + for (int i = name.length() + 1; i > 15; i--) { + String shortened = StringUtil.getShortened(name, i); + assertTrue(shortened.length() <= i); + assertTrue(!shortened.contains("....")); + } + } + } } diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/ProjectLevelVcsManager.java b/platform/vcs-api/src/com/intellij/openapi/vcs/ProjectLevelVcsManager.java index 203f4fc0f539..c6b0daa0852d 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/ProjectLevelVcsManager.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/ProjectLevelVcsManager.java @@ -272,7 +272,7 @@ public abstract class ProjectLevelVcsManager { public abstract VcsHistoryCache getVcsHistoryCache(); public abstract ContentRevisionCache getContentRevisionCache(); public abstract boolean isFileInContent(final VirtualFile vf); - public abstract boolean isIgnoredByVcs(VirtualFile vf); + public abstract boolean isIgnored(VirtualFile vf); public abstract boolean dvcsUsedInProject(); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LocalChangeListImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LocalChangeListImpl.java index ad62491e1add..1d310d5a023a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LocalChangeListImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LocalChangeListImpl.java @@ -173,7 +173,7 @@ public class LocalChangeListImpl extends LocalChangeList { return false; } VirtualFile vFile = revision.getFile().getVirtualFile(); - return vFile != null && ProjectLevelVcsManager.getInstance(project).isIgnoredByVcs(vFile); + return vFile != null && ProjectLevelVcsManager.getInstance(project).isIgnored(vFile); } }); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/UpdatingChangeListBuilder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/UpdatingChangeListBuilder.java index 76b21762cf1f..d06c8f888ad7 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/UpdatingChangeListBuilder.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/UpdatingChangeListBuilder.java @@ -121,7 +121,7 @@ class UpdatingChangeListBuilder implements ChangelistBuilder { @Override public Boolean compute() { checkIfDisposed(); - return myVcsManager.isIgnoredByVcs(file); + return myVcsManager.isIgnored(file); } }); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsGuess.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsGuess.java index 394f2e7f6414..112caa4a40b4 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsGuess.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsGuess.java @@ -73,7 +73,7 @@ public class VcsGuess { final boolean inContent = myVcsManager.isFileInContent(validParent); if (inContent) return true; if (filePath != null) { - return isFileInBaseDir(filePath, myProject.getBaseDir()) && !myVcsManager.isIgnoredByVcs(validParent); + return isFileInBaseDir(filePath, myProject.getBaseDir()) && !myVcsManager.isIgnored(validParent); } return false; } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java index b230d4f72a0d..e699383321ae 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java @@ -845,13 +845,13 @@ public class ProjectLevelVcsManagerImpl extends ProjectLevelVcsManagerEx impleme return vf != null && (myExcludedIndex.isInContent(vf) || isFileInBaseDir(vf) || vf.equals(myProject.getBaseDir()) || hasExplicitMapping(vf) || isInDirectoryBasedRoot(vf) || !Registry.is("ide.hide.excluded.files") && myExcludedIndex.isExcludedFile(vf)) - && !isIgnoredByVcs(vf); + && !isIgnored(vf); } }); } @Override - public boolean isIgnoredByVcs(VirtualFile vf) { + public boolean isIgnored(VirtualFile vf) { if (Registry.is("ide.hide.excluded.files")) { return myExcludedIndex.isExcludedFile(vf); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsRootIterator.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsRootIterator.java index 074055ac87ef..cfddcaa3e65d 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsRootIterator.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsRootIterator.java @@ -67,7 +67,7 @@ public class VcsRootIterator { return ApplicationManager.getApplication().runReadAction(new Computable() { @Override public Boolean compute() { - return !project.isDisposed() && vcsManager.isIgnoredByVcs(file); + return !project.isDisposed() && vcsManager.isIgnored(file); } }); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/projectlevelman/NewMappings.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/projectlevelman/NewMappings.java index 80e46c235643..5ff541ebc67d 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/projectlevelman/NewMappings.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/projectlevelman/NewMappings.java @@ -234,7 +234,7 @@ public class NewMappings { @Nullable public VcsDirectoryMapping getMappingFor(final VirtualFile file, final Object parentModule) { // if parentModule is not null it means that file belongs to the module so it isn't excluded - if (parentModule == null && myVcsManager.isIgnoredByVcs(file)) { + if (parentModule == null && myVcsManager.isIgnored(file)) { return null; } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java index 3fe8b70d1a8d..08d7012eeeea 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java @@ -91,7 +91,7 @@ public class XDebugSessionImpl implements XDebugSession { private XDebugProcess myDebugProcess; private final Map, CustomizedBreakpointPresentation> myRegisteredBreakpoints = new THashMap, CustomizedBreakpointPresentation>(); - private final Set> myInactiveSlaveBreakpoints = new SmartHashSet>(); + private final Set> myInactiveSlaveBreakpoints = Collections.synchronizedSet(new SmartHashSet>()); private boolean myBreakpointsDisabled; private final XDebuggerManagerImpl myDebuggerManager; private MyBreakpointListener myBreakpointListener; @@ -295,12 +295,15 @@ public class XDebugSessionImpl implements XDebugSession { XBreakpointManagerImpl breakpointManager = myDebuggerManager.getBreakpointManager(); XDependentBreakpointManager dependentBreakpointManager = breakpointManager.getDependentBreakpointManager(); disableSlaveBreakpoints(dependentBreakpointManager); - processAllBreakpoints(true, false); + // listeners have to be applied before processing all existing breakpoints, + // otherwise we may not process breakpoints added during the processing myBreakpointListener = new MyBreakpointListener(); breakpointManager.addBreakpointListener(myBreakpointListener); myDependentBreakpointListener = new MyDependentBreakpointListener(); dependentBreakpointManager.addListener(myDependentBreakpointListener); + + processAllBreakpoints(true, false); } @Override diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerRunToCursorActionHandler.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerRunToCursorActionHandler.java index 66684da99205..2f38008f5c5a 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerRunToCursorActionHandler.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerRunToCursorActionHandler.java @@ -15,6 +15,7 @@ */ package com.intellij.xdebugger.impl.actions.handlers; +import com.intellij.xdebugger.XDebuggerUtil; import com.intellij.xdebugger.impl.actions.XDebuggerSuspendedActionHandler; import com.intellij.xdebugger.impl.XDebuggerUtilImpl; import com.intellij.xdebugger.XDebugSession; @@ -33,7 +34,9 @@ public class XDebuggerRunToCursorActionHandler extends XDebuggerSuspendedActionH } protected boolean isEnabled(final @NotNull XDebugSession session, final DataContext dataContext) { - return super.isEnabled(session, dataContext) && XDebuggerUtilImpl.getCaretPosition(session.getProject(), dataContext) != null; + if (!super.isEnabled(session, dataContext)) return false; + XSourcePosition position = XDebuggerUtilImpl.getCaretPosition(session.getProject(), dataContext); + return position != null && XDebuggerUtil.getInstance().canPutBreakpointAt(session.getProject(), position.getFile(), position.getLine()); } protected void perform(@NotNull final XDebugSession session, final DataContext dataContext) { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java index be227cec1698..ebcd027c2643 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java @@ -240,14 +240,15 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta @NotNull public > Collection getBreakpoints(@NotNull final XBreakpointType type) { ApplicationManager.getApplication().assertReadAccessAllowed(); - Collection> breakpoints = myBreakpoints.get(type); - Collection regular = breakpoints != null ? Collections.unmodifiableCollection((Collection)breakpoints) : Collections.emptyList(); - - final XBreakpointBase defaultBreakpoint = myDefaultBreakpoints.get(type); - if (defaultBreakpoint == null) return regular; List result = new ArrayList(); - result.add((B)defaultBreakpoint); - result.addAll(regular); + B defaultBreakpoint = getDefaultBreakpoint(type); + if (defaultBreakpoint != null) { + result.add(defaultBreakpoint); + } + Collection> breakpoints = myBreakpoints.get(type); + if (breakpoints != null) { + result.addAll((Collection)breakpoints); + } return result; } diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectorUtils.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectorUtils.java index 96f29f253e4e..1b4e43ec4df1 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectorUtils.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectorUtils.java @@ -247,17 +247,17 @@ public class InjectorUtils { // make sure comment is close enough and ... int off1 = r0.getEndOffset(); int off2 = e2.getTextRange().getStartOffset(); - if (off2 - off1 > 120) return null; - if (off2 - off1 > 2) { - // ... there's nothing in between on the top level and ... - for (PsiElement e = e1; e != e2; e = e.getNextSibling()) { - if (!isWhitespaceCommentOrBlank(e)) return null; - } - // ... there's no non-empty host in the left (comment) subtree - Producer producer = prevWalker(PsiTreeUtil.getDeepestLast(e1), e1); + if (off2 - off1 > 120) { + return null; + } + else if (off2 - off1 > 2) { + // ... there's no non-empty valid host in between comment and e2 + Producer producer = prevWalker(e2, commonParent); PsiElement e; while ( (e = producer.produce()) != null && e != psiComment) { - if (e instanceof PsiLanguageInjectionHost && !StringUtil.isEmptyOrSpaces(e.getText())) { + if (e instanceof PsiLanguageInjectionHost && + ((PsiLanguageInjectionHost)e).isValidHost() && + !StringUtil.isEmptyOrSpaces(e.getText())) { return null; } } @@ -268,11 +268,6 @@ public class InjectorUtils { return new BaseInjection(supportId).copyFrom(entry.getValue()); } - protected static boolean isWhitespaceCommentOrBlank(PsiElement e) { - return e instanceof PsiWhiteSpace || e instanceof PsiComment || - e instanceof PsiLanguageInjectionHost && StringUtil.isEmptyOrSpaces(e.getText()); - } - @Nullable private static TreeMap getInjectionMap(@Nullable final PsiFile file) { if (file == null) return null; // e.g. null for synthetic groovy variables @@ -295,8 +290,6 @@ public class InjectorUtils { CharSequence contents = file.getViewProvider().getContents(); final char[] contentsArray = CharArrayUtil.fromSequenceWithoutCopying(contents); - //long time = System.currentTimeMillis(); - int s0 = 0, s1 = contents.length(); for (int idx = searcher.scan(contents, contentsArray, s0, s1); idx != -1; @@ -311,30 +304,6 @@ public class InjectorUtils { } } } - - //VirtualFile virtualFile = file.getVirtualFile(); - //Document document = FileDocumentManager.getInstance().getDocument(virtualFile); - //EditorHighlighter highlighter = EditorHighlighterCache.getEditorHighlighterForCachesBuilding(document); - // - //ParserDefinition definition = LanguageParserDefinitions.INSTANCE.forLanguage(file.getLanguage()); - //TokenSet commentTokens = definition.getCommentTokens(); - //HighlighterIterator it = highlighter != null && PlatformIdTableBuilding.checkCanUseCachedEditorHighlighter(contents, highlighter) ? - // highlighter.createIterator(0) : null; - // - //do { - // if (it != null) { - // while (!it.atEnd() && !commentTokens.contains(it.getTokenType())) it.advance(); - // if (it.atEnd()) break; - // } - // int s0 = it == null ? 0 : it.getStart(); - // int s1 = it == null ? contents.length() : it.getEnd(); - // - // for () { .. } - // - // if (it != null && !it.atEnd()) it.advance(); - //} while (it != null && !it.atEnd()); - - //System.out.println(Thread.currentThread().getName() + ": " + file.getName() + "@" + file.hashCode() + " indexed: " + (System.currentTimeMillis() - time)); return injectionMap; } @@ -375,18 +344,11 @@ public class InjectorUtils { if (e == null || e == scope) return null; PsiElement prev = e.getPrevSibling(); if (prev != null) { - e = prev; - while (true) { - PsiElement lastChild = e.getLastChild(); - if (lastChild == null) break; - e = lastChild; - } - return e; + return e = PsiTreeUtil.getDeepestLast(prev); } else { PsiElement parent = e.getParent(); - e = parent == scope || parent instanceof PsiFile ? null : parent; - return e; + return e = parent == scope || parent instanceof PsiFile ? null : parent; } } }; diff --git a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsstatuses/CvsChangeProvider.java b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsstatuses/CvsChangeProvider.java index 784a18d62461..a652289a59c7 100644 --- a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsstatuses/CvsChangeProvider.java +++ b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsstatuses/CvsChangeProvider.java @@ -164,7 +164,7 @@ public class CvsChangeProvider implements ChangeProvider { for (VirtualFile file : children) { progress.checkCanceled(); if (file.isDirectory()) { - final boolean isIgnored = myVcsManager.isIgnoredByVcs(file); + final boolean isIgnored = myVcsManager.isIgnored(file); if (!isIgnored) { processEntriesIn(file, scope, builder, true, progress); } diff --git a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/ui/experts/importToCvs/ImportTree.java b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/ui/experts/importToCvs/ImportTree.java index 49c2025908e0..eb30dd74752c 100644 --- a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/ui/experts/importToCvs/ImportTree.java +++ b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/ui/experts/importToCvs/ImportTree.java @@ -256,6 +256,6 @@ public class ImportTree extends NodeRenderer { } private boolean isIgnoredByVcs(VirtualFile vFile) { - return myProject != null && ProjectLevelVcsManager.getInstance(myProject).isIgnoredByVcs(vFile); + return myProject != null && ProjectLevelVcsManager.getInstance(myProject).isIgnored(vFile); } } diff --git a/plugins/devkit/src/build/PrepareToDeployAction.java b/plugins/devkit/src/build/PrepareToDeployAction.java index b501331596b5..37bedb4d1d3a 100644 --- a/plugins/devkit/src/build/PrepareToDeployAction.java +++ b/plugins/devkit/src/build/PrepareToDeployAction.java @@ -164,6 +164,7 @@ public class PrepareToDeployAction extends AnAction { else { FileUtil.copy(jarFile, dstFile); } + LocalFileSystem.getInstance().refreshIoFiles(Collections.singleton(dstFile), true, false, null); successMessages.add(DevKitBundle.message("saved.message", isZip ? 1 : 2, pluginName, dstPath)); } catch (final IOException e) { diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java index 3c609a91f55d..7ba292889b9f 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java @@ -354,7 +354,7 @@ public class GithubShareAction extends DumbAwareAction { return ContainerUtil.filter(files, new Condition() { @Override public boolean value(VirtualFile file) { - return !changeListManager.isIgnoredFile(file) && !vcsManager.isIgnoredByVcs(file); + return !changeListManager.isIgnoredFile(file) && !vcsManager.isIgnored(file); } }); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusWalkerPartner.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusWalkerPartner.java index a3f722bfe65d..690eb1e76ee3 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusWalkerPartner.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusWalkerPartner.java @@ -79,7 +79,7 @@ public class StatusWalkerPartner { @Override public Boolean compute() { if (myVcs.getProject().isDisposed()) throw new ProcessCanceledException(); - return myVcsManager.isIgnoredByVcs(vFile); + return myVcsManager.isIgnored(vFile); } }); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnExcludingIgnoredOperation.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnExcludingIgnoredOperation.java index 59c3c538aa4a..94fc2e11c96e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnExcludingIgnoredOperation.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnExcludingIgnoredOperation.java @@ -70,7 +70,7 @@ public class SvnExcludingIgnoredOperation { return ApplicationManager.getApplication().runReadAction(new Computable() { @Override public Boolean compute() { - return myVcsManager.isIgnoredByVcs(file); + return myVcsManager.isIgnored(file); } }); } diff --git a/python/helpers/pycharm/behave_runner.py b/python/helpers/pycharm/behave_runner.py index e66805cfafb2..4a1b2f6557c5 100644 --- a/python/helpers/pycharm/behave_runner.py +++ b/python/helpers/pycharm/behave_runner.py @@ -141,7 +141,11 @@ class _BehaveRunner(_bdd_utils.BddRunner): elif element.status == 'passed': self._test_passed(element.name, element.duration) elif element.status == 'failed': - self._test_failed(element.name, element.error_message, traceback.format_exc()) + try: + trace = traceback.format_exc() + except Exception: + trace = "".join(traceback.format_tb(element.exc_traceback)) + self._test_failed(element.name, element.error_message, trace) elif element.status == 'undefined': self._test_undefined(element.name, element.location) else: @@ -231,7 +235,7 @@ if __name__ == "__main__": if not my_config.paths: # No path provided, trying to load dit manually if os.path.isfile(what_to_run): # File is provided, load it my_config.paths = [what_to_run] - else: # Dir is provided, find subdirs ro run + else: # Dir is provided, find subdirs ro run my_config.paths = _get_dirs_to_run(base_dir) _BehaveRunner(my_config, base_dir).run() diff --git a/python/src/com/jetbrains/python/PyAddImportFix.java b/python/src/com/jetbrains/python/PyAddImportFix.java new file mode 100644 index 000000000000..c13fed13fdcb --- /dev/null +++ b/python/src/com/jetbrains/python/PyAddImportFix.java @@ -0,0 +1,55 @@ +package com.jetbrains.python; + +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.jetbrains.python.codeInsight.imports.AddImportHelper; +import com.jetbrains.python.psi.LanguageLevel; +import com.jetbrains.python.psi.PyElementGenerator; +import com.jetbrains.python.psi.PyFile; +import com.jetbrains.python.psi.PyImportStatementBase; +import org.jetbrains.annotations.NotNull; + +/** + * Quick fix that adds import to file + * + * @author Ilya.Kazakevich + */ +public class PyAddImportFix implements LocalQuickFix { + @NotNull + private final String myImportToAdd; + @NotNull + private final PyFile myFile; + + /** + * @param importToAdd string representing what to add (i.e. "from foo import bar") + * @param file where to add + */ + public PyAddImportFix(@NotNull final String importToAdd, @NotNull final PyFile file) { + myImportToAdd = importToAdd; + myFile = file; + } + + @NotNull + @Override + public String getName() { + return PyBundle.message("QFIX.add.import", myImportToAdd); + } + + @NotNull + @Override + public String getFamilyName() { + return getName(); + } + + @Override + public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) { + final PyElementGenerator generator = PyElementGenerator.getInstance(project); + final PyImportStatementBase statement = + generator.createFromText(LanguageLevel.forElement(myFile), PyImportStatementBase.class, myImportToAdd); + final PsiElement recommendedPosition = AddImportHelper.getFileInsertPosition(myFile); + myFile.addAfter(statement, recommendedPosition); + } +} + diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index 5d29d3f79d50..482daa88b66c 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -32,6 +32,8 @@ QFIX.create.property=Create property QFIX.add.encoding=Add encoding declaration +QFIX.add.import=Add "''{0}''" + QFIX.NAME.parameters=Parameters of functions and methods QFIX.rename.parameter.to.$0=Rename to ''{0}'' diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index 877da8df6dd9..f1dd16078696 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -1645,6 +1645,11 @@ public class PyUtil { return Collections2.filter(pyMemberInfos, new ObjectPredicate(false)); } + public static boolean isStarImportableFrom(@NotNull String name, @NotNull PyFile file) { + final List dunderAll = file.getDunderAll(); + return dunderAll != null ? dunderAll.contains(name) : !name.startsWith("_"); + } + /** * Filters only pyclass object (new class) */ diff --git a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java index 030fcfe3d7e5..02b790622fe7 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java @@ -477,8 +477,9 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression { if (starImportSource != null) { starImportSource = PyUtil.turnDirIntoInit(starImportSource); if (starImportSource instanceof PyFile) { - final PsiElement result = ((PyFile)starImportSource).getElementNamed(name); - if (result != null) { + final PyFile file = (PyFile)starImportSource; + final PsiElement result = file.getElementNamed(name); + if (result != null && PyUtil.isStarImportableFrom(name, file)) { return result; } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java index 4011c233e38d..88c3134481a8 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyStarImportElementImpl.java @@ -52,11 +52,8 @@ public class PyStarImportElementImpl extends PyElementImpl implements PyStarImpo for (PsiElement importedFile : new HashSet(importedFiles)) { // resolver gives lots of duplicates final PsiElement source = PyUtil.turnDirIntoInit(importedFile); if (source instanceof PyFile) { - Iterable declaredNames = ((PyFile)source).iterateNames(); - if (((PyFile)source).getDunderAll() == null) { - declaredNames = excludeUnderscoredNames(declaredNames); - } - chain.add(declaredNames); + final PyFile sourceFile = (PyFile)source; + chain.add(filterStarImportableNames(sourceFile.iterateNames(), sourceFile)); } } return chain; @@ -64,15 +61,13 @@ public class PyStarImportElementImpl extends PyElementImpl implements PyStarImpo return Collections.emptyList(); } - private static Iterable excludeUnderscoredNames(Iterable declaredNames) { + @NotNull + private static Iterable filterStarImportableNames(@NotNull Iterable declaredNames, @NotNull final PyFile file) { return Iterables.filter(declaredNames, new Predicate() { @Override public boolean apply(@Nullable PyElement input) { final String name = input != null ? input.getName() : null; - if (name != null && name.startsWith("_")) { - return false; - } - return true; + return name != null && PyUtil.isStarImportableFrom(name, file); } }); } @@ -93,11 +88,7 @@ public class PyStarImportElementImpl extends PyElementImpl implements PyStarImpo final List results = moduleType.resolveMember(name, null, AccessDirection.READ, PyResolveContext.defaultContext()); final PsiElement result = results != null && !results.isEmpty() ? results.get(0).getElement() : null; - if (result != null) { - final List all = sourceFile.getDunderAll(); - if (all != null ? !all.contains(name) : name.startsWith("_")) { - continue; - } + if (result != null && PyUtil.isStarImportableFrom(name, sourceFile) ) { return result; } } diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedImportBeforeStarDunderAll/a.py b/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedImportBeforeStarDunderAll/a.py new file mode 100644 index 000000000000..6d444960ee9d --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedImportBeforeStarDunderAll/a.py @@ -0,0 +1,3 @@ +import b +from p1 import * +print(b) diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedImportBeforeStarDunderAll/b.py b/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedImportBeforeStarDunderAll/b.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedImportBeforeStarDunderAll/p1/__init__.py b/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedImportBeforeStarDunderAll/p1/__init__.py new file mode 100644 index 000000000000..31f7e1aa969c --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedImportBeforeStarDunderAll/p1/__init__.py @@ -0,0 +1 @@ +from p1.m1 import * diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedImportBeforeStarDunderAll/p1/m1.py b/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedImportBeforeStarDunderAll/p1/m1.py new file mode 100644 index 000000000000..3f8018db03f2 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/UnusedImportBeforeStarDunderAll/p1/m1.py @@ -0,0 +1,2 @@ +import b +__all__ = [] diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index 176708421fcd..a0a2a1232b2e 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -376,6 +376,11 @@ public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase { doMultiFileTest(); } + // PY-13585 + public void testUnusedImportBeforeStarDunderAll() { + doMultiFileTest(); + } + @NotNull @Override protected Class getInspectionClass() {