Merge remote branch 'origin/master'

This commit is contained in:
irengrig
2011-12-29 15:20:55 +04:00
23 changed files with 456 additions and 62 deletions
@@ -36,10 +36,10 @@ public class FormLayoutSerializer extends GridLayoutSerializer {
public static FormLayoutSerializer INSTANCE = new FormLayoutSerializer();
public static CellConstraints.Alignment[] ourHorizontalAlignments = new CellConstraints.Alignment[] {
public static CellConstraints.Alignment[] ourHorizontalAlignments = {
CellConstraints.LEFT, CellConstraints.CENTER, CellConstraints.RIGHT, CellConstraints.FILL
};
public static CellConstraints.Alignment[] ourVerticalAlignments = new CellConstraints.Alignment[] {
public static CellConstraints.Alignment[] ourVerticalAlignments = {
CellConstraints.TOP, CellConstraints.CENTER, CellConstraints.BOTTOM, CellConstraints.FILL
};
@@ -314,7 +314,7 @@ public class CompilerTask extends Task.Backgroundable {
(
CompilerWorkspaceConfiguration.getInstance(myProject).useCompileServer() /*todo: temporary*/||
CompilerMessageCategory.ERROR.equals(category) ||
(CompilerMessageCategory.WARNING.equals(category) && !ErrorTreeViewConfiguration.getInstance(myProject).isHideWarnings())
!ErrorTreeViewConfiguration.getInstance(myProject).isHideWarnings()
);
if (shouldAutoActivate) {
myMessagesAutoActivated = true;
@@ -19,6 +19,8 @@ package com.intellij.codeInsight.folding;
import com.intellij.codeInsight.folding.impl.CodeFoldingManagerImpl
import com.intellij.openapi.application.ex.PathManagerEx
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
import com.intellij.codeInsight.folding.impl.JavaCodeFoldingSettingsImpl
import com.intellij.openapi.editor.impl.FoldingModelImpl
/**
* @author Denis Zhdanov
@@ -26,6 +28,23 @@ import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
*/
public class JavaFoldingTest extends LightCodeInsightFixtureTestCase {
def JavaCodeFoldingSettingsImpl myFoldingSettings
def JavaCodeFoldingSettingsImpl myFoldingStateToRestore
@Override
public void setUp() {
super.setUp()
myFoldingSettings = JavaCodeFoldingSettings.instance as JavaCodeFoldingSettingsImpl
myFoldingStateToRestore = new JavaCodeFoldingSettingsImpl()
myFoldingStateToRestore.loadState(myFoldingSettings)
}
@Override
protected void tearDown() {
myFoldingSettings.loadState(myFoldingStateToRestore)
super.tearDown()
}
public void testEndOfLineComments() {
myFixture.testFolding("$PathManagerEx.testDataPath/codeInsight/folding/${getTestName(false)}.java");
}
@@ -76,10 +95,52 @@ class Test {
myFixture.performEditorAction 'CollapseBlock'
assertEquals(text.indexOf('}', text.indexOf('i++')), myFixture.editor.caretModel.offset)
}
public void testFoldGroup() {
// Implied by IDEA-79420
myFoldingSettings.COLLAPSE_CLOSURES = true
def text = """\
class Test {
void test() {
new Runnable() {
public void run() {
int i = 1;
}
}.run();
}
}
"""
configure text
def foldingModel = myFixture.editor.foldingModel as FoldingModelImpl
def closureStartFold = foldingModel.getCollapsedRegionAtOffset(text.indexOf("Runnable"))
assertNotNull closureStartFold
assertFalse closureStartFold.expanded
assertNotNull closureStartFold.group
def closureFolds = foldingModel.getGroupedRegions(closureStartFold.group)
assertNotNull closureFolds
assertEquals(2, closureFolds.size())
def closureEndFold = closureFolds.get(1)
assertFalse closureEndFold.expanded
myFixture.editor.caretModel.moveToOffset(closureEndFold.startOffset + 1)
assertTrue closureStartFold.expanded
assertTrue closureEndFold.expanded
changeFoldRegions { closureStartFold.expanded = false }
assertTrue closureStartFold.expanded
assertTrue closureEndFold.expanded
}
private def configure(String text) {
myFixture.configureByText("a.java", text)
CodeFoldingManagerImpl.getInstance(getProject()).buildInitialFoldings(myFixture.editor);
myFixture.doHighlighting()
}
private def changeFoldRegions(Closure op) {
myFixture.editor.foldingModel.runBatchFoldingOperationDoNotCollapseCaret(op)
}
}
@@ -564,14 +564,16 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass
Document documentRange = documentManager.getDocument(file);
if (documentRange == null) continue;
List<InspectionResult> resultList = entry.getValue();
for (InspectionResult inspectionResult : resultList) {
indicator.checkCanceled();
LocalInspectionTool tool = inspectionResult.tool;
HighlightSeverity severity = inspectionProfile.getErrorLevel(HighlightDisplayKey.find(tool.getShortName()), file).getSeverity();
for (ProblemDescriptor descriptor : inspectionResult.foundProblems) {
synchronized (resultList) {
for (InspectionResult inspectionResult : resultList) {
indicator.checkCanceled();
PsiElement element = descriptor.getPsiElement();
createHighlightsForDescriptor(outInfos, emptyActionRegistered, ilManager, file, documentRange, tool, severity, descriptor, element);
LocalInspectionTool tool = inspectionResult.tool;
HighlightSeverity severity = inspectionProfile.getErrorLevel(HighlightDisplayKey.find(tool.getShortName()), file).getSeverity();
for (ProblemDescriptor descriptor : inspectionResult.foundProblems) {
indicator.checkCanceled();
PsiElement element = descriptor.getPsiElement();
createHighlightsForDescriptor(outInfos, emptyActionRegistered, ilManager, file, documentRange, tool, severity, descriptor, element);
}
}
}
}
@@ -87,6 +87,7 @@ public class FileStructurePopup implements Disposable {
private String myTitle;
private TreeSpeedSearch mySpeedSearch;
private SmartTreeStructure myTreeStructure;
private JComponent myPanel;
public FileStructurePopup(StructureViewModel structureViewModel,
@Nullable Editor editor,
@@ -130,20 +131,36 @@ public class FileStructurePopup implements Disposable {
myTree.setRootVisible(false);
myTree.setShowsRootHandles(true);
mySpeedSearch = new TreeSpeedSearch(myTree, TreeSpeedSearch.NODE_DESCRIPTOR_TOSTRING, true);
mySpeedSearch = new TreeSpeedSearch(myTree, TreeSpeedSearch.NODE_DESCRIPTOR_TOSTRING, true) {
@Override
protected Point getComponentLocationOnScreen() {
return myPopup.getContent().getLocationOnScreen();
}
@Override
protected Rectangle getComponentVisibleRect() {
return myPopup.getContent().getVisibleRect();
}
};
myAbstractTreeBuilder = new FilteringTreeBuilder(project, myTree, new FileStructurePopupFilter(), myTreeStructure, null) {
@Override
protected boolean validateNode(Object child) {
return StructureViewComponent.isValid(child);
}
@Override
public void revalidateTree() {
myTree.revalidate();
myTree.repaint();
}
};
}
public void show() {
final JComponent panel = createCenterPanel();
new MnemonicHelper().register(panel);
myPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(panel, null)
myPanel = createCenterPanel();
new MnemonicHelper().register(myPanel);
myPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(myPanel, null)
.setTitle(myTitle)
.setResizable(true)
.setFocusable(true)
@@ -168,21 +185,23 @@ public class FileStructurePopup implements Disposable {
});
}
});
final Alarm alarm = new Alarm(myPopup);
final Alarm alarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD, myPopup);
alarm.addRequest(new Runnable() {
String filter = "";
@Override
public void run() {
alarm.cancelAllRequests();
String prefix = mySpeedSearch.getEnteredPrefix();
myTree.getEmptyText().setText("Can't find '" + prefix + "'");
if (prefix == null) prefix = "";
if (!filter.equals(prefix)) {
filter = prefix;
myAbstractTreeBuilder.refilter();
//myAbstractTreeBuilder.refilter();
}
alarm.addRequest(this, 300);
alarm.addRequest(this, 500);
}
}, 300);
}, 500);
}
private void selectPsiElement(PsiElement element) {
@@ -389,7 +408,7 @@ public class FileStructurePopup implements Disposable {
final boolean state = chkFilter.isSelected();
myTreeActionsOwner.setActionIncluded(action, action instanceof FileStructureFilter ? !state : state);
myTreeStructure.rebuildTree();
myAbstractTreeBuilder.refilter(); //todo full update
myAbstractTreeBuilder.refilter();
myAbstractTreeBuilder.queueUpdate();
if (SpeedSearchBase.hasActiveSpeedSearch(myTree)) {
@@ -444,6 +463,15 @@ public class FileStructurePopup implements Disposable {
}
}
private class MyFilter extends ElementFilter.Active.Impl<StructureViewComponent.StructureViewTreeElementWrapper> {
@Override
public boolean shouldBeShowing(StructureViewComponent.StructureViewTreeElementWrapper value) {
return true;
}
}
private class FileStructurePopupFilter implements ElementFilter {
private String myLastFilter = null;
private HashSet<Object> myVisibleParents = new HashSet<Object>();
@@ -455,6 +483,7 @@ public class FileStructurePopup implements Disposable {
? mySpeedSearch.getEnteredPrefix() : null;
if (!StringUtil.equals(myLastFilter, filter)) {
myVisibleParents.clear();
myLastFilter = filter;
}
if (filter != null) {
if (myVisibleParents.contains(value)) {
@@ -101,6 +101,12 @@ public class SequentialModalProgressTask extends Task.Modal {
}
}
});
//if (ApplicationManager.getApplication().isDispatchThread()) {
// runnable.run();
//}
//else {
// ApplicationManagerEx.getApplicationEx().suspendReadAccessAndRunWriteAction(runnable);
//}
}
}
@@ -369,7 +369,7 @@ public class ParametersList implements Cloneable {
try {
builder.append(parameter);
StringUtil.escapeQuotes(builder);
if (builder.length() == 0 || StringUtil.indexOf(builder, ' ') >= 0) {
if (builder.length() == 0 || StringUtil.indexOf(builder, ' ') >= 0 || StringUtil.indexOf(builder, '|') >= 0) {
StringUtil.quote(builder);
}
return builder.toString();
@@ -285,7 +285,7 @@ public final class Presentation implements Cloneable {
myChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
}
public Object clone(){
public Presentation clone(){
try{
Presentation presentation = (Presentation)super.clone();
presentation.myChangeSupport = new PropertyChangeSupport(presentation);
@@ -20,7 +20,6 @@ import com.intellij.ide.util.treeView.AbstractTreeStructure;
import com.intellij.ide.util.treeView.NodeDescriptor;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.Navigatable;
import com.intellij.ui.CustomizeColoredTreeCellRenderer;
@@ -41,12 +40,10 @@ public class ErrorViewStructure extends AbstractTreeStructure {
private final ErrorTreeElement myRoot = new MyRootElement();
private final List<String> myGroupNames = new ArrayList<String>();
private final Map<String, GroupingElement> myGroupNameToElementMap = new HashMap<String, GroupingElement>();
private final Map<String, List<NavigatableMessageElement>> myGroupNameToMessagesMap =
new HashMap<String, List<NavigatableMessageElement>>();
private final Map<ErrorTreeElementKind, List<ErrorTreeElement>> mySimpleMessages =
new HashMap<ErrorTreeElementKind, List<ErrorTreeElement>>();
private final Map<String, List<NavigatableMessageElement>> myGroupNameToMessagesMap = new HashMap<String, List<NavigatableMessageElement>>();
private final Map<ErrorTreeElementKind, List<ErrorTreeElement>> mySimpleMessages = new EnumMap<ErrorTreeElementKind, List<ErrorTreeElement>>(ErrorTreeElementKind.class);
private static final ErrorTreeElementKind[] ourMessagesOrder = new ErrorTreeElementKind[]{
private static final ErrorTreeElementKind[] ourMessagesOrder = {
ErrorTreeElementKind.INFO,
ErrorTreeElementKind.ERROR,
ErrorTreeElementKind.WARNING,
@@ -70,10 +67,10 @@ public class ErrorViewStructure extends AbstractTreeStructure {
final List<Object> children = new ArrayList<Object>();
// simple messages
for (final ErrorTreeElementKind kind : ourMessagesOrder) {
if (ErrorTreeElementKind.WARNING.equals(kind) || ErrorTreeElementKind.NOTE.equals(kind)) {
if (myCanHideWarnings && ErrorTreeViewConfiguration.getInstance(myProject).isHideWarnings()) {
continue;
}
if (!ErrorTreeElementKind.ERROR.equals(kind) &&
myCanHideWarnings &&
ErrorTreeViewConfiguration.getInstance(myProject).isHideWarnings()) {
continue;
}
final List<ErrorTreeElement> elems = mySimpleMessages.get(kind);
if (elems != null) {
@@ -89,15 +86,15 @@ public class ErrorViewStructure extends AbstractTreeStructure {
}
return ArrayUtil.toObjectArray(children);
}
else if (element instanceof GroupingElement) {
if (element instanceof GroupingElement) {
synchronized (myGroupNameToMessagesMap) {
final List<NavigatableMessageElement> children = myGroupNameToMessagesMap.get(((GroupingElement)element).getName());
if (children != null && children.size() > 0) {
if (children != null && !children.isEmpty()) {
if (myCanHideWarnings && ErrorTreeViewConfiguration.getInstance(myProject).isHideWarnings()) {
final List<NavigatableMessageElement> filtered = new ArrayList<NavigatableMessageElement>(children.size());
for (final NavigatableMessageElement navigatableMessageElement : children) {
ErrorTreeElementKind kind = navigatableMessageElement.getKind();
if (ErrorTreeElementKind.WARNING.equals(kind) || ErrorTreeElementKind.NOTE.equals(kind)) {
if (!ErrorTreeElementKind.ERROR.equals(kind)) {
continue;
}
filtered.add(navigatableMessageElement);
@@ -120,7 +117,7 @@ public class ErrorViewStructure extends AbstractTreeStructure {
if (children != null) {
for (final NavigatableMessageElement child : children) {
ErrorTreeElementKind kind = child.getKind();
if (!ErrorTreeElementKind.WARNING.equals(kind) && !ErrorTreeElementKind.NOTE.equals(kind)) {
if (ErrorTreeElementKind.ERROR.equals(kind)) {
return true;
}
}
@@ -187,7 +184,7 @@ public class ErrorViewStructure extends AbstractTreeStructure {
public List<Object> getGroupChildrenData(final String groupName) {
synchronized (myGroupNameToMessagesMap) {
final List<NavigatableMessageElement> children = myGroupNameToMessagesMap.get(groupName);
if (children != null && (!children.isEmpty())) {
if (children != null && !children.isEmpty()) {
final List<Object> result = new ArrayList<Object>();
for (NavigatableMessageElement child : children) {
final Object data = child.getData();
@@ -302,12 +299,12 @@ public class ErrorViewStructure extends AbstractTreeStructure {
public ErrorTreeElement getFirstMessage(ErrorTreeElementKind kind) {
if (myCanHideWarnings &&
(ErrorTreeElementKind.WARNING.equals(kind) || ErrorTreeElementKind.NOTE.equals(kind)) &&
!ErrorTreeElementKind.ERROR.equals(kind) &&
ErrorTreeViewConfiguration.getInstance(myProject).isHideWarnings()) {
return null; // no warnings are available
}
final List<ErrorTreeElement> simpleMessages = mySimpleMessages.get(kind);
if (simpleMessages != null && simpleMessages.size() > 0) {
if (simpleMessages != null && !simpleMessages.isEmpty()) {
return simpleMessages.get(0);
}
for (final String path : myGroupNames) {
@@ -348,7 +345,6 @@ public class ErrorViewStructure extends AbstractTreeStructure {
}
private static class MyNavigatableWithDataElement extends NavigatableMessageElement {
private final static Icon ourFileIcon = IconLoader.getIcon("/fileTypes/unknown.png");
private final VirtualFile myVf;
private final CustomizeColoredTreeCellRenderer myCustomizeColoredTreeCellRenderer;
@@ -370,12 +366,10 @@ public class ErrorViewStructure extends AbstractTreeStructure {
boolean leaf,
int row,
boolean hasFocus) {
if (myVf != null) {
final Icon icon = myVf.getFileType().getIcon();
renderer.setIcon(icon);
}
final Icon icon = myVf.getFileType().getIcon();
renderer.setIcon(icon);
final String[] messages = getText();
final String text = ((messages == null) || (messages.length == 0)) ? vf.getPath() : messages[0];
final String text = messages == null || messages.length == 0 ? vf.getPath() : messages[0];
renderer.append(text);
}
};
@@ -563,14 +563,12 @@ public class NewErrorTreeViewPanel extends JPanel implements DataProvider, Occur
}
public boolean isSelected(AnActionEvent event) {
return ErrorTreeViewConfiguration.getInstance(myProject).isHideWarnings();
return isHideWarnings();
}
public void setSelected(AnActionEvent event, boolean flag) {
final ErrorTreeViewConfiguration configuration = ErrorTreeViewConfiguration.getInstance(myProject);
final boolean hideWarnings = configuration.isHideWarnings();
if (hideWarnings != flag) {
configuration.setHideWarnings(flag);
if (isHideWarnings() != flag) {
ErrorTreeViewConfiguration.getInstance(myProject).setHideWarnings(flag);
myBuilder.updateTree();
}
}
@@ -65,6 +65,17 @@ public class FoldRegionImpl extends RangeMarkerImpl implements FoldRegion {
} else {
for (final FoldRegion region : foldingModel.getGroupedRegions(myGroup)) {
doSetExpanded(expanded, foldingModel, region);
// There is a possible case that we can't change expanded status of particular fold region (e.g. we can't collapse
// if it contains caret). So, we revert all changes for the fold regions from the same group then.
if (region.isExpanded() != expanded) {
for (FoldRegion regionToRevert : foldingModel.getGroupedRegions(myGroup)) {
if (regionToRevert == region) {
break;
}
doSetExpanded(!expanded, foldingModel, regionToRevert);
}
return;
}
}
}
}
@@ -517,8 +517,8 @@ public abstract class SpeedSearchBase<Comp extends JComponent> extends SpeedSear
myPopupLayeredPane.add(mySearchPopup, JLayeredPane.POPUP_LAYER);
if (myPopupLayeredPane == null) return; // See # 27482. Somewho it does happen...
Point lPaneP = myPopupLayeredPane.getLocationOnScreen();
Point componentP = myComponent.getLocationOnScreen();
Rectangle r = myComponent.getVisibleRect();
Point componentP = getComponentLocationOnScreen();
Rectangle r = getComponentVisibleRect();
Dimension prefSize = mySearchPopup.getPreferredSize();
Window window = (Window)SwingUtilities.getAncestorOfClass(Window.class, myComponent);
Point windowP;
@@ -539,6 +539,14 @@ public abstract class SpeedSearchBase<Comp extends JComponent> extends SpeedSear
mySearchPopup.validate();
}
protected Rectangle getComponentVisibleRect() {
return myComponent.getVisibleRect();
}
protected Point getComponentLocationOnScreen() {
return myComponent.getLocationOnScreen();
}
private class MyToolWindowManagerListener extends ToolWindowManagerAdapter {
public void stateChanged() {
manageSearchPopup(null);
@@ -1104,7 +1104,7 @@ public class StringUtil {
}
@NotNull
public static Iterable<String> tokenize(@NotNull String s, final StringTokenizer tokenizer) {
public static Iterable<String> tokenize(final StringTokenizer tokenizer) {
return new Iterable<String>() {
public Iterator<String> iterator() {
return new Iterator<String>() {
@@ -21,7 +21,6 @@ import com.intellij.openapi.ui.VerticalFlowLayout;
import org.jetbrains.android.facet.AndroidFacet;
import javax.swing.*;
import java.awt.*;
/**
* @author Eugene.Kudelevsky
@@ -31,7 +30,7 @@ public class CheckModulePanel extends JPanel {
private boolean myHasWarnings;
public CheckModulePanel() {
super(new VerticalFlowLayout(FlowLayout.LEFT));
super(new VerticalFlowLayout(VerticalFlowLayout.TOP));
}
public void updateMessages(AndroidFacet facet) {
@@ -353,7 +353,7 @@ public abstract class DeviceConfiguratorPanel extends JPanel {
rightPabel.add(new JBScrollPane(myChosenQualifiersList, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER), BorderLayout.CENTER);
final JPanel buttonsPanel = new JPanel(new VerticalFlowLayout(FlowLayout.CENTER, 0, 0, true, false));
final JPanel buttonsPanel = new JPanel(new VerticalFlowLayout(VerticalFlowLayout.MIDDLE, 0, 0, true, false));
myAddQualifierButton = new JButton(">>");
buttonsPanel.add(myAddQualifierButton);
myRemoveQualifierButton = new JButton("<<");
@@ -55,4 +55,9 @@ gradle.generic.text.error.sdk.undefined=Gradle installation is unknown
gradle.home.setting.type.deduced=Gradle location is deduced
gradle.home.setting.type.unknown=Gradle location is unknown
gradle.home.setting.type.explicit.correct=Gradle location is defined
gradle.home.setting.type.explicit.incorrect=Gradle location is incorrect
gradle.home.setting.type.explicit.incorrect=Gradle location is incorrect
gradle.toolwindow.text.no.linked.project=\nThere is no linked Gradle project\nYou may use {link} to add the one.
gradle.action.link.project.text=Link gradle project
gradle.action.link.project.description=Allows to link any gradle project to the current IDE project
+7
View File
@@ -58,4 +58,11 @@
</component>
</project-components>
<actions>
<action id="Gradle.LinkToProject" class="org.jetbrains.plugins.gradle.config.GradleLinkToProjectAction" icon="/general/add.png"/>
<group id="Gradle.ChangeActionsToolbar">
<reference id="Gradle.LinkToProject"/>
</group>
</actions>
</idea-plugin>
@@ -0,0 +1,28 @@
package org.jetbrains.plugins.gradle.config;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.DumbAware;
import org.jetbrains.plugins.gradle.util.GradleBundle;
/**
* Allows to link gradle project to the current IntelliJ IDEA project.
* <p/>
* Not thread-safe.
*
* @author Denis Zhdanov
* @since 12/26/11 5:09 PM
*/
public class GradleLinkToProjectAction extends AnAction implements DumbAware {
public GradleLinkToProjectAction() {
getTemplatePresentation().setText(GradleBundle.message("gradle.action.link.project.text"));
getTemplatePresentation().setDescription(GradleBundle.message("gradle.action.link.project.description"));
}
@Override
public void actionPerformed(AnActionEvent e) {
// TODO den implement
System.out.println("action performed");
}
}
@@ -0,0 +1,141 @@
package org.jetbrains.plugins.gradle.config;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.ActionToolbar;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.ex.ActionButtonLook;
import com.intellij.openapi.actionSystem.impl.ActionButton;
import com.intellij.openapi.ui.SimpleToolWindowPanel;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.ScrollPaneFactory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.util.GradleBundle;
import org.jetbrains.plugins.gradle.util.GradleConstants;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.StringTokenizer;
/**
* Base class for high-level Gradle GUI controls used at the Gradle tool window. The basic idea is to encapsulate the same features in
* this class and allow to extend it via <code>Template Method</code> pattern. The shared features are listed below:
* <pre>
* <ul>
* <li>provide common actions at the toolbar;</li>
* <li>show info control when no gradle project is linked to the current IntelliJ IDEA project;</li>
* </ul>
* </pre>
* <p/>
* Not thread-safe.
*
* @author Denis Zhdanov
* @since 12/26/11 5:19 PM
*/
public abstract class GradleToolWindowPanel extends SimpleToolWindowPanel {
private static final String NON_LINKED_CARD_NAME = "NON_LINKED";
private static final String CONTENT_CARD_NAME = "CONTENT";
private static final String LINK_BUTTON_MARKER = "{link}";
private static final String TOOL_WINDOW_TOOLBAR_ID = "Gradle.ChangeActionsToolbar";
private static final String LINK_PROJECT_ACTION_ID = "Gradle.LinkToProject";
/** Show info control when no gradle project is linked, using {@link CardLayout} for that. */
private final CardLayout myLayout = new CardLayout();
/** Top-level container, managed by the card layout. */
private final JPanel myContent = new JPanel(myLayout);
/** Control to show when no gradle project is linked to the current IntelliJ IDEA project. */
private final JPanel myNonLinkedInfoPanel = new JPanel();
protected GradleToolWindowPanel(@NotNull String place) {
super(true);
final ActionManager actionManager = ActionManager.getInstance();
final ActionGroup actionGroup = (ActionGroup)actionManager.getAction(TOOL_WINDOW_TOOLBAR_ID);
ActionToolbar actionToolbar = actionManager.createActionToolbar(place, actionGroup, true);
setToolbar(actionToolbar.getComponent());
initContent();
setContent(myContent);
}
private void initContent() {
final JComponent payloadControl = buildContent();
myContent.add(ScrollPaneFactory.createScrollPane(payloadControl), CONTENT_CARD_NAME);
myNonLinkedInfoPanel.setLayout(new GridBagLayout());
final Color background = payloadControl.getBackground();
myNonLinkedInfoPanel.setBackground(background);
List<JComponent> rowComponents = new ArrayList<JComponent>();
final String sentence = GradleBundle.message("gradle.toolwindow.text.no.linked.project");
for (String s : StringUtil.tokenize(new StringTokenizer(sentence, " \n", true))) {
if (s.isEmpty()) {
continue;
}
if (LINK_BUTTON_MARKER.equals(s)) {
final ActionManager actionManager = ActionManager.getInstance();
final AnAction action = actionManager.getAction(LINK_PROJECT_ACTION_ID);
ActionButton button= new ActionButton(
action, action.getTemplatePresentation().clone(), GradleConstants.TOOL_WINDOW_TOOLBAR_PLACE, new Dimension(0, 0))
{
@Override
protected void paintButtonLook(Graphics g) {
// Don't draw border at the inline button.
ActionButtonLook look = getButtonLook();
look.paintBackground(g, this);
look.paintIcon(g, this, getIcon());
}
};
rowComponents.add(button);
}
else if (s.contains("\n")) {
addRow(rowComponents, background);
rowComponents.clear();
}
else {
final JLabel label = new JLabel(s);
label.setForeground(payloadControl.getForeground());
label.setBackground(background);
label.setFont(payloadControl.getFont());
rowComponents.add(label);
}
}
if (!rowComponents.isEmpty()) {
addRow(rowComponents, background);
}
GridBagConstraints constraints = new GridBagConstraints();
constraints.weighty = 1;
constraints.fill = GridBagConstraints.VERTICAL;
myNonLinkedInfoPanel.add(Box.createVerticalStrut(1), constraints);
myContent.add(myNonLinkedInfoPanel, NON_LINKED_CARD_NAME);
myLayout.show(myContent, NON_LINKED_CARD_NAME);
}
private void addRow(@NotNull Collection<JComponent> rowComponents, @NotNull Color backgroundColor) {
JPanel row = new MultiRowFlowPanel(FlowLayout.CENTER, 0, 3);
row.setBackground(backgroundColor);
if (rowComponents.isEmpty()) {
row.add(new JLabel(" "));
}
else {
for (JComponent component : rowComponents) {
row.add(component);
}
}
GridBagConstraints constraints = new GridBagConstraints();
constraints.gridwidth = GridBagConstraints.REMAINDER;
constraints.weightx = 1;
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.insets.top = 3;
myNonLinkedInfoPanel.add(row, constraints);
}
/**
* @return GUI control to be displayed at the current tab
*/
@NotNull
protected abstract JComponent buildContent();
}
@@ -0,0 +1,83 @@
package org.jetbrains.plugins.gradle.config;
import javax.swing.*;
import java.awt.*;
/**
* Flow layout calculates necessary size assuming that all components are layed out within a single row.
* That may cause troubles during initial space calculation, i.e. panel with flow layout is represented as a
* single wide row inside a scroll pane. This panel fixes that by calculating necessary size on its own.
* It fixes the width to use as a minimum between a width offered by default flow layout and customizable value
* and calculates the height. If the user has an ability to manually change panel size (e.g. indirectly via changing
* size of the dialog that serves as a container for the panel), that width is used as a maximum width.
*
* @author: Denis Zhdanov
* @since: Jul 28, 2008
*/
public class MultiRowFlowPanel extends JPanel {
private int maximumWidth = Toolkit.getDefaultToolkit().getScreenSize().width / 2;
public MultiRowFlowPanel(int align, int hGap, int vGap) {
super(new FlowLayout(align, hGap, vGap));
}
/**
* Calculates a preferred size assuming that the maximum row width is a value returned from
* {@link #getMaxRowWidth()}.
*/
@Override
public Dimension getPreferredSize() {
return calculateSize(getMaxRowWidth());
}
/**
* Calculates a preferred size assuming that the maximum row width is a value returned from
* {@link #getMaxRowWidth()}.
*/
@Override
public Dimension getMinimumSize() {
return calculateSize(getMaxRowWidth());
}
/**
* @return current representation width if the component is already showed; minimum of default preferred
* width (when all components are layed in a single row) and half screen width
*/
private int getMaxRowWidth() {
int result = getSize().width;
if (result == 0) {
result = Math.min(super.getPreferredSize().width, maximumWidth);
}
return result;
}
/**
* Iterates all child components and calculates the space enough to keep all of them assuming that the width is
* fixed.
*/
private Dimension calculateSize(int maxRowWidth) {
FlowLayout layout = (FlowLayout)getLayout();
int height = 0;
int currentRowWidth = 0;
int currentRowHeight = 0;
for (int i = 0, count = getComponentCount(); i < count; ++i) {
Component comp = getComponent(i);
Dimension bounds = comp.getPreferredSize();
if (!comp.isVisible()) {
continue;
}
currentRowHeight = Math.max(currentRowHeight, bounds.height);
if (currentRowWidth + layout.getHgap() + bounds.width <= maxRowWidth) {
if (bounds.width != 0) {
currentRowWidth += bounds.width + layout.getHgap();
}
continue;
}
height += currentRowHeight + layout.getVgap();
currentRowWidth = bounds.width;
currentRowHeight = bounds.height;
}
return new Dimension(maxRowWidth, height + currentRowHeight + 2 * layout.getVgap());
}
}
@@ -1,6 +1,9 @@
package org.jetbrains.plugins.gradle.sync;
import com.intellij.ui.treeStructure.SimpleTree;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.config.GradleToolWindowPanel;
import org.jetbrains.plugins.gradle.util.GradleConstants;
import javax.swing.*;
@@ -10,11 +13,20 @@ import javax.swing.*;
* @author Denis Zhdanov
* @since 11/3/11 3:58 PM
*/
public class GradleProjectStructureChangesPanel extends JPanel {
public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel {
private final GradleProjectStructureChangesModel myModel;
public GradleProjectStructureChangesPanel(@NotNull GradleProjectStructureChangesModel model) {
super(GradleConstants.TOOL_WINDOW_TOOLBAR_PLACE);
myModel = model;
}
@NotNull
@Override
protected JComponent buildContent() {
// TODO den implement
return new SimpleTree();
//return new JLabel("project-structure-change-content");
}
}
@@ -13,9 +13,10 @@ import javax.swing.*;
*/
public class GradleConstants {
public static final Icon GRADLE_ICON = IconLoader.getIcon("/icons/gradle.png");
@NonNls public static final String EXTENSION = "gradle";
@NonNls public static final String DEFAULT_SCRIPT_NAME = "build.gradle";
public static final Icon GRADLE_ICON = IconLoader.getIcon("/icons/gradle.png");
@NonNls public static final String EXTENSION = "gradle";
@NonNls public static final String DEFAULT_SCRIPT_NAME = "build.gradle";
@NonNls public static final String TOOL_WINDOW_TOOLBAR_PLACE = "GRADLE_SYNC_CHANGES_TOOLBAR";
private GradleConstants() {
}
@@ -102,6 +102,7 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit
private final Set<PropertiesFile> myBackSlashPressed = new THashSet<PropertiesFile>();
@NonNls private static final String VALUES = "values";
@NonNls private static final String NO_PROPERTY_SELECTED = "noPropertySelected";
private VirtualFileListener myVfsListener;
private PsiTreeChangeAdapter myPsiTreeChangeAdapter;
@NonNls protected static final String PROPORTION_PROPERTY = "RESOURCE_BUNDLE_SPLITTER_PROPORTION";
@@ -231,7 +232,12 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit
}
private void installPropertiesChangeListeners() {
VirtualFileManager.getInstance().addVirtualFileListener(new VirtualFileAdapter() {
final VirtualFileManager virtualFileManager = VirtualFileManager.getInstance();
if (myVfsListener != null) {
assert false;
virtualFileManager.removeVirtualFileListener(myVfsListener);
}
myVfsListener = new VirtualFileAdapter() {
@Override
public void fileCreated(VirtualFileEvent event) {
if (PropertiesUtil.isPropertiesFile(event.getFile(), myProject)) {
@@ -260,7 +266,9 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit
}
}
}
}, this);
};
virtualFileManager.addVirtualFileListener(myVfsListener, this);
myPsiTreeChangeAdapter = new PsiTreeChangeAdapter() {
public void childAdded(PsiTreeChangeEvent event) {
childrenChanged(event);
@@ -607,6 +615,7 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit
public void dispose() {
float proportion = getSplitter().getProportion();
PropertiesComponent.getInstance(myProject).setValue(PROPORTION_PROPERTY, Double.toString(proportion));
VirtualFileManager.getInstance().removeVirtualFileListener(myVfsListener);
myDisposed = true;
Disposer.dispose(myStructureViewComponent);