From b9c4348c8b82798ff18979217c268cc94402bc1c Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Tue, 17 Mar 2015 16:16:48 +0300 Subject: [PATCH 1/7] diff: use right side as master by-default the most common usecase is to use local content on the right. And most likely, it should be the master one. In most of other cases we don't have such asymmetry, so we don't know which side to choose. Right is as good as left. --- .../com/intellij/diff/tools/fragmented/OnesideDiffViewer.java | 2 +- .../com/intellij/openapi/vcs/actions/DiffActionExecutor.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/OnesideDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/OnesideDiffViewer.java index 788f7042acef..79d0d049a4a7 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/OnesideDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/OnesideDiffViewer.java @@ -88,7 +88,7 @@ public class OnesideDiffViewer extends TextDiffViewerBase { @NotNull private final MyScrollToLineHelper myScrollToLineHelper = new MyScrollToLineHelper(); @NotNull private final MyFoldingModel myFoldingModel; - @NotNull protected Side myMasterSide = Side.LEFT; + @NotNull protected Side myMasterSide = Side.RIGHT; @Nullable private ChangedBlockData myChangedBlockData; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/DiffActionExecutor.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/DiffActionExecutor.java index 9497de99c8e9..d1aab151c7b3 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/DiffActionExecutor.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/DiffActionExecutor.java @@ -135,11 +135,13 @@ public abstract class DiffActionExecutor { if (inverted) { SimpleDiffRequest request = new SimpleDiffRequest(title, content2, content1, title2, title1); if (line != null) request.putUserData(DiffUserDataKeys.SCROLL_TO_LINE, Pair.create(Side.LEFT, line)); + request.putUserData(DiffUserDataKeys.MASTER_SIDE, Side.LEFT); requestRef.set(request); } else { SimpleDiffRequest request = new SimpleDiffRequest(title, content1, content2, title1, title2); if (line != null) request.putUserData(DiffUserDataKeys.SCROLL_TO_LINE, Pair.create(Side.RIGHT, line)); + request.putUserData(DiffUserDataKeys.MASTER_SIDE, Side.RIGHT); requestRef.set(request); } } From abb848fec5759c9cefa5fbd665b5daab7e0ce11f Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Tue, 17 Mar 2015 16:08:15 +0300 Subject: [PATCH 2/7] diff: fix oneside 'Open In Editor' pass actual offsets to getOpenFileDescriptor (instead of offset in 'combined' text representation) --- .../diff/tools/fragmented/OnesideDiffViewer.java | 13 ++++++++++--- .../src/com/intellij/diff/util/DiffUtil.java | 9 +++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/OnesideDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/OnesideDiffViewer.java index 79d0d049a4a7..78a522d0ffef 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/OnesideDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/OnesideDiffViewer.java @@ -575,9 +575,16 @@ public class OnesideDiffViewer extends TextDiffViewerBase { return myActualContent2.getOpenFileDescriptor(offset); } - Pair pair = transferLineFromOneside(myEditor.offsetToLogicalPosition(offset).line); - OpenFileDescriptor descriptor1 = myActualContent1.getOpenFileDescriptor(offset); - OpenFileDescriptor descriptor2 = myActualContent2.getOpenFileDescriptor(offset); + LogicalPosition position = myEditor.offsetToLogicalPosition(offset); + Pair pair = transferLineFromOneside(position.line); + int offset1 = DiffUtil.getOffset(myActualContent1.getDocument(), pair.first[0], position.column); + int offset2 = DiffUtil.getOffset(myActualContent2.getDocument(), pair.first[1], position.column); + + // TODO: issue: non-optimal GoToSource position with caret on deleted block for "Compare with local" + // we should transfer using calculated diff, not jump to "somehow related" position from old content's descriptor + + OpenFileDescriptor descriptor1 = myActualContent1.getOpenFileDescriptor(offset1); + OpenFileDescriptor descriptor2 = myActualContent2.getOpenFileDescriptor(offset2); if (descriptor1 == null) return descriptor2; if (descriptor2 == null) return descriptor1; return pair.second.select(descriptor1, descriptor2); diff --git a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java index aea930a79eb6..8fb5527a588c 100644 --- a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java @@ -706,6 +706,15 @@ public class DiffUtil { } } + public static int getOffset(@NotNull Document document, int line, int column) { + if (line < 0) return 0; + if (line >= getLineCount(document)) return document.getTextLength(); + + int start = document.getLineStartOffset(line); + int end = document.getLineEndOffset(line); + return Math.min(start + column, end); + } + public static int getLineCount(@NotNull Document document) { return Math.max(document.getLineCount(), 1); } From 18503739d89c5c00fa295b1e5b60a98860aff6c8 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Tue, 17 Mar 2015 19:21:23 +0300 Subject: [PATCH 3/7] [vcs-log] try to fix intelli sort icon by not fliping in runtime it but rather use already flipped version IDEA-137760 --- platform/vcs-log/impl/gen/icons/VcsLogIcons.java | 1 + .../vcs-log/impl/resources/icons/IntelliSort.png | Bin 0 -> 310 bytes .../impl/resources/icons/IntelliSort@2x.png | Bin 0 -> 544 bytes .../impl/resources/icons/IntelliSort@2x_dark.png | Bin 0 -> 510 bytes .../impl/resources/icons/IntelliSort_dark.png | Bin 0 -> 311 bytes .../actions/IntelliSortChooserToggleAction.java | 2 +- 6 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 platform/vcs-log/impl/resources/icons/IntelliSort.png create mode 100644 platform/vcs-log/impl/resources/icons/IntelliSort@2x.png create mode 100644 platform/vcs-log/impl/resources/icons/IntelliSort@2x_dark.png create mode 100644 platform/vcs-log/impl/resources/icons/IntelliSort_dark.png diff --git a/platform/vcs-log/impl/gen/icons/VcsLogIcons.java b/platform/vcs-log/impl/gen/icons/VcsLogIcons.java index 50b0c14614dd..cd100c9d8ef2 100644 --- a/platform/vcs-log/impl/gen/icons/VcsLogIcons.java +++ b/platform/vcs-log/impl/gen/icons/VcsLogIcons.java @@ -18,5 +18,6 @@ public class VcsLogIcons { public static final Icon CollapseMerges = load("/icons/CollapseMerges.png"); // 16x16 public static final Icon ExpandBranches = load("/icons/ExpandBranches.png"); // 16x16 public static final Icon ExpandMerges = load("/icons/ExpandMerges.png"); // 16x16 + public static final Icon IntelliSort = load("/icons/IntelliSort.png"); // 16x16 public static final Icon ShowHideLongEdges = load("/icons/ShowHideLongEdges.png"); // 16x16 } diff --git a/platform/vcs-log/impl/resources/icons/IntelliSort.png b/platform/vcs-log/impl/resources/icons/IntelliSort.png new file mode 100644 index 0000000000000000000000000000000000000000..0941cce71dfef5f8d72f5bdceda749d4acebc981 GIT binary patch literal 310 zcmV-60m=S}P)VB~ny zQ_o#oyY4c9pjlX={2CwUm2Zu`)t(s6g(Y&<2t-C8lqG5eCXSHy-8l=o)lQG-C*iu~9JiikjsJ{G)@=m8?AtFC(mK~yO0gVX=m zjHtNk=xz#i@neTG%*=o0obwkAA~ME_F);#)#i9`ohXrs!Rl;K-=Ykc011wOEMx*37 z4yDs+;xWhMoMGFxFL()XW3d<&3I)QA8}K+DkCS|fzy(zJ=IU?-$1wMSg)3td5Q#(x z3%|e>SPm=&obzreK>P&@Ux5;G0W7}-2vvlcOs2C41r|<$6nJY9k_EyS0kYLhehGeZ zMi!r`+E8vV4IEIHLbyK8!P3YA6mnx~jdkgQ8F17gpI0o->9e+>2+-l;& z@S>*^cBDY`5ulg{r}8CONPTN3b-9+v-QvKi#0BE;xfZAsE^`r2v<6u9JeEPB?@B!3EbW!faa+ilLlPM*z1Pz9!!mtw@Y)L$hle4q`;Q z0u*Y$*4ShU=;wq(q(J_vgBI}bgiR;pbVz)0 iLQaRo+X?^dzvFMI=k|0f7ACisH5vbm5IXLx>86{o(YTW;d(P!~UTm|^C8Gv}O7w1~)BCRSzybh}-vUau<|PUO&=-*AB-J&;w4YPRLK3FEk!F zV6pu|xN!)N^QAi$5ttg$&{P2E^UZZ|4bNe1m`MSNQjp{)Rs;m5DVXSlGYC*za4|)w zW_H4)0=U)iwZoU-ZUEAT_SiN|YD6XiH2S>gTs8$HaYDlss4*#+&j}5R(3wz#PA1zh zkr5dPNXH4&6!7naQ77yR3vohDhY;_CfA-(;H~ImY%NbVwpa1{>07*qoM6N<$f)n=N AY5)KL literal 0 HcmV?d00001 diff --git a/platform/vcs-log/impl/resources/icons/IntelliSort_dark.png b/platform/vcs-log/impl/resources/icons/IntelliSort_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..db2b0522f196589df465d40307924c58cd19f618 GIT binary patch literal 311 zcmV-70m%M|P) Date: Tue, 17 Mar 2015 19:35:17 +0400 Subject: [PATCH 4/7] do not allow sync editing from keyboard if not supported --- .../dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java index 60832f1f49b8..d96dfee6ee73 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java @@ -64,8 +64,11 @@ public class PushLog extends JPanel implements DataProvider { private boolean myShouldRepaint = false; private boolean mySyncStrategy; @Nullable private String mySyncRenderedText; + private final boolean myAllowSyncStrategy; + public PushLog(Project project, final CheckedTreeNode root, final boolean allowSyncStrategy) { + myAllowSyncStrategy = allowSyncStrategy; DefaultTreeModel treeModel = new DefaultTreeModel(root); treeModel.nodeStructureChanged(root); myTreeCellRenderer = new MyTreeCellRenderer(); @@ -210,7 +213,7 @@ public class PushLog extends JPanel implements DataProvider { setDefaultEmptyText(); Splitter splitter = new Splitter(false, 0.7f); - final JComponent syncStrategyPanel = allowSyncStrategy ? createStrategyPanel() : null; + final JComponent syncStrategyPanel = myAllowSyncStrategy ? createStrategyPanel() : null; myScrollPane = new JBScrollPane(myTree) { @Override @@ -392,7 +395,7 @@ public class PushLog extends JPanel implements DataProvider { } return true; } - if (e.getKeyCode() == KeyEvent.VK_F2 && e.getModifiers() == InputEvent.ALT_MASK && pressed) { + if (myAllowSyncStrategy && e.getKeyCode() == KeyEvent.VK_F2 && e.getModifiers() == InputEvent.ALT_MASK && pressed) { mySyncStrategy = true; DefaultMutableTreeNode node = getFirstNodeToEdit(); if (node != null) { From 628589af84ea3039b1ad2dc8b7a633acc2803d3e Mon Sep 17 00:00:00 2001 From: Nadya Zabrodina Date: Tue, 17 Mar 2015 19:41:15 +0400 Subject: [PATCH 5/7] IDEA-131544 Push dialog: be more keyboard friendly, especially in the case of Git repository with multiple remotes * change GitPushTargetPanel focus policy to cycle policy in case of multiRemote; * after popup closed in edit mode then focus force returned to edit field; * do not update target while edit mode is not finished; * restore tree selection if needed --- .../com/intellij/dvcs/push/ui/PushLog.java | 9 +++ .../src/git4idea/push/GitPushTargetPanel.java | 73 +++++++++++++++++-- 2 files changed, 74 insertions(+), 8 deletions(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java index d96dfee6ee73..4c8b86b75fef 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java @@ -113,15 +113,18 @@ public class PushLog extends JPanel implements DataProvider { if (myShouldRepaint) { refreshNode(root); } + restoreSelection(node); return result; } @Override public void cancelEditing() { + DefaultMutableTreeNode lastSelectedPathComponent = (DefaultMutableTreeNode)myTree.getLastSelectedPathComponent(); super.cancelEditing(); if (myShouldRepaint) { refreshNode(root); } + restoreSelection(lastSelectedPathComponent); } }; myTree.setUI(new MyTreeUi()); @@ -241,6 +244,12 @@ public class PushLog extends JPanel implements DataProvider { myTree.setRowHeight(0); } + private void restoreSelection(@Nullable DefaultMutableTreeNode node) { + if (node != null) { + TreeUtil.selectNode(myTree, node); + } + } + private JComponent createStrategyPanel() { final JPanel labelPanel = new JPanel(new BorderLayout()); labelPanel.setBackground(myTree.getBackground()); diff --git a/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java b/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java index b33ed23537f5..932e5c38736d 100644 --- a/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java +++ b/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java @@ -27,18 +27,20 @@ import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.ValidationInfo; -import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.ListPopup; import com.intellij.openapi.ui.popup.PopupStep; import com.intellij.openapi.ui.popup.util.BaseListPopupStep; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VfsUtilCore; +import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.SimpleTextAttributes; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.components.JBLabel; +import com.intellij.ui.popup.list.ListPopupImpl; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.table.ComponentsListFocusTraversalPolicy; import git4idea.GitRemoteBranch; import git4idea.commands.Git; import git4idea.commands.GitCommandResult; @@ -51,6 +53,9 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import java.awt.*; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.InputEvent; import java.awt.event.MouseEvent; import java.text.ParseException; import java.util.Comparator; @@ -91,7 +96,10 @@ public class GitPushTargetPanel extends PushTargetPanel { showDefineRemoteDialog(); } else { - showRemoteSelector(event); + Component eventComponent = event.getComponent(); + if (eventComponent != null) { + showRemoteSelector(eventComponent, event.getPoint()); + } } } }); @@ -107,6 +115,21 @@ public class GitPushTargetPanel extends PushTargetPanel { add(myTargetEditor, BorderLayout.CENTER); updateComponents(defaultTarget); + + setFocusCycleRoot(true); + setFocusTraversalPolicyProvider(true); + myRemoteRenderer.setFocusable(true); + myTargetEditor.setFocusable(true); + setFocusTraversalPolicy(new MyGitTargetFocusTraversalPolicy()); + myRemoteRenderer.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + // show in edit mode only + if (myTargetEditor.isShowing()) { + showRemoteSelector(myRemoteRenderer, new Point(myRemoteRenderer.getLocation())); + } + } + }); } private void updateComponents(@Nullable GitPushTarget target) { @@ -205,23 +228,33 @@ public class GitPushTargetPanel extends PushTargetPanel { }); } - private void showRemoteSelector(@NotNull MouseEvent event) { + private void showRemoteSelector(@NotNull Component component, @NotNull Point point) { final List remotes = getRemotes(); if (remotes.size() <= 1) { return; } - - ListPopup popup = JBPopupFactory.getInstance().createListPopup(new BaseListPopupStep(null, remotes) { + ListPopup popup = new ListPopupImpl(new BaseListPopupStep(null, remotes) { @Override public PopupStep onChosen(String selectedValue, boolean finalChoice) { myRemoteRenderer.updateLinkText(selectedValue); - if (myFireOnChangeAction != null) { + if (myFireOnChangeAction != null && !myTargetEditor.isShowing()) { + //fireOnChange only when editing completed myFireOnChangeAction.run(); } return super.onChosen(selectedValue, finalChoice); } - }); - popup.show(new RelativePoint(event)); + }) { + @Override + public void cancel(InputEvent e) { + super.cancel(e); + if (myTargetEditor.isShowing()) { + //repaint and force move focus to target editor component + GitPushTargetPanel.this.repaint(); + IdeFocusManager.getInstance(myProject).requestFocus(myTargetEditor, true); + } + } + }; + popup.show(new RelativePoint(component, point)); } @NotNull @@ -363,4 +396,28 @@ public class GitPushTargetPanel extends PushTargetPanel { } }); } + + private class MyGitTargetFocusTraversalPolicy extends ComponentsListFocusTraversalPolicy { + @NotNull + @Override + protected List getOrderedComponents() { + return ContainerUtil.newArrayList(myTargetEditor.getFocusTarget(), myRemoteRenderer); + } + + @Override + public Component getComponentAfter(Container aContainer, Component aComponent) { + if (getRemotes().size() > 1) { + return super.getComponentAfter(aContainer, aComponent); + } + return aComponent; + } + + @Override + public Component getComponentBefore(Container aContainer, Component aComponent) { + if (getRemotes().size() > 1) { + return super.getComponentBefore(aContainer, aComponent); + } + return aComponent; + } + } } From 8239c21e4250210cc211e2a01157d2f7dc107ec3 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Tue, 17 Mar 2015 19:47:08 +0300 Subject: [PATCH 6/7] Internal action to log screen configuration --- .../DumpScreenConfigurationAction.java | 242 ++++++++++++++++++ .../src/com/intellij/ui/ScreenUtil.java | 11 +- resources/src/idea/RichPlatformActions.xml | 1 + 3 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 platform/lang-impl/src/com/intellij/internal/DumpScreenConfigurationAction.java diff --git a/platform/lang-impl/src/com/intellij/internal/DumpScreenConfigurationAction.java b/platform/lang-impl/src/com/intellij/internal/DumpScreenConfigurationAction.java new file mode 100644 index 000000000000..d3db8160a157 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/internal/DumpScreenConfigurationAction.java @@ -0,0 +1,242 @@ +/* + * Copyright 2000-2015 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.internal; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.ui.JBColor; +import com.intellij.ui.ScreenUtil; +import org.jetbrains.annotations.NotNull; + +import java.awt.*; +import java.util.ArrayList; +import javax.swing.Action; +import javax.swing.JComponent; + +/** + * @author Sergey.Malenkov + */ +public class DumpScreenConfigurationAction extends DumbAwareAction { + private static final Logger LOG = Logger.getInstance(DumpScreenConfigurationAction.class); + + @Override + public void actionPerformed(AnActionEvent event) { + new ScreenDialog(event).show(); + } + + private static Rectangle minimize(Rectangle bounds) { + return new Rectangle(bounds.x / 10, bounds.y / 10, bounds.width / 10, bounds.height / 10); + } + + private static void append(StringBuilder sb, GraphicsDevice device) { + append(sb, "id", device.getIDstring()); + append(sb, "type", getTypeName(device.getType())); + append(sb, device.getDisplayMode()); + GraphicsConfiguration configuration = device.getDefaultConfiguration(); + append(sb, "outer", configuration.getBounds()); + append(sb, "inner", ScreenUtil.getScreenRectangle(configuration)); + append(sb, "default image", configuration.getImageCapabilities()); + BufferCapabilities capabilities = configuration.getBufferCapabilities(); + append(sb, "front buffer image", capabilities.getFrontBufferCapabilities()); + append(sb, "back buffer image", capabilities.getBackBufferCapabilities()); + sb.append("page flipping: ").append(capabilities.getFlipContents()); + if (capabilities.isFullScreenRequired()) { + sb.append("; full-screen exclusive mode is required"); + } + if (capabilities.isMultiBufferAvailable()) { + sb.append("; more than two buffers can be used"); + } + sb.append("\n"); + } + + private static void append(StringBuilder sb, String name, String text) { + sb.append(name).append(": ").append(text).append("\n"); + } + + private static void append(StringBuilder sb, String name, Rectangle bounds) { + sb.append(name); + sb.append(": x=").append(bounds.x); + sb.append(", y=").append(bounds.x); + sb.append(", width=").append(bounds.width); + sb.append(", height=").append(bounds.height); + sb.append("\n"); + } + + private static void append(StringBuilder sb, DisplayMode mode) { + sb.append("mode: ").append(mode.getWidth()).append("x").append(mode.getHeight()); + sb.append("; bit depth=").append(mode.getBitDepth()); + sb.append("; refresh rate=").append(mode.getRefreshRate()); + sb.append("\n"); + } + + private static void append(StringBuilder sb, String name, ImageCapabilities capabilities) { + if (capabilities != null) { + sb.append(name).append(": accelerated=").append(capabilities.isAccelerated()); + if (capabilities.isTrueVolatile()) { + sb.append("; true volatile"); + } + sb.append("\n"); + } + } + + private static String getTypeName(int type) { + if (type == 0) return "raster screen"; + if (type == 1) return "printer"; + if (type == 2) return "image buffer"; + return "unknown: " + type; + } + + private static final class ScreenDialog extends DialogWrapper { + private ScreenDialog(AnActionEvent event) { + super(event.getProject()); + init(); + setOKButtonText("Dump"); + setTitle("Screen Configuration"); + } + + @Override + protected JComponent createCenterPanel() { + return new ScreenView(); + } + + @NotNull + @Override + protected Action[] createActions() { + return new Action[]{getOKAction(), getCancelAction()}; + } + + @Override + protected void doOKAction() { + StringBuilder sb = new StringBuilder(); + GraphicsDevice[] devices = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices(); + append(sb, "number of devices", Integer.toString(devices.length)); + for (GraphicsDevice device : devices) { + append(sb.append("\n"), device); + } + LOG.warn(sb.toString()); + } + } + + private static final class ScreenInfo { + private final Rectangle myOuterBounds = new Rectangle(); + private final Rectangle myInnerBounds = new Rectangle(); + + private boolean update(GraphicsConfiguration configuration) { + boolean updated = false; + Rectangle outer = minimize(configuration.getBounds()); + if (!myOuterBounds.equals(outer)) { + myOuterBounds.setBounds(outer); + updated = true; + } + Rectangle inner = minimize(ScreenUtil.getScreenRectangle(configuration)); + if (!myInnerBounds.equals(inner)) { + myInnerBounds.setBounds(inner); + updated = true; + } + return updated; + } + } + + private static final class ScreenView extends JComponent { + private final ArrayList myScreenList = new ArrayList(); + private final Rectangle myBounds = new Rectangle(); + + private boolean update() { + boolean updated = false; + GraphicsDevice[] devices = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices(); + while (devices.length > myScreenList.size()) { + myScreenList.add(new ScreenInfo()); + updated = true; + } + while (devices.length < myScreenList.size()) { + myScreenList.remove(devices.length); + updated = true; + } + for (int i = 0; i < devices.length; i++) { + if (myScreenList.get(i).update(devices[i].getDefaultConfiguration())) { + updated = true; + } + } + if (updated) { + int minX = 0; + int maxX = 0; + int minY = 0; + int maxY = 0; + for (ScreenInfo info : myScreenList) { + int x = info.myOuterBounds.x; + if (minX > x) { + minX = x; + } + x += info.myOuterBounds.width; + if (maxX < x) { + maxX = x; + } + int y = info.myOuterBounds.y; + if (minY > y) { + minY = y; + } + y += info.myOuterBounds.height; + if (maxY < y) { + maxY = y; + } + } + myBounds.setBounds(minX, minY, maxX - minX, maxY - minY); + } + return updated; + } + + @Override + protected void paintComponent(Graphics g) { + if (update()) { + setPreferredSize(myBounds.getSize()); + setMinimumSize(myBounds.getSize()); + revalidate(); + repaint(); + } + g = g.create(); + if (g instanceof Graphics2D) { + Graphics2D g2d = (Graphics2D)g; + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + } + for (int i = 0; i < myScreenList.size(); i++) { + ScreenInfo info = myScreenList.get(i); + + Rectangle bounds = info.myOuterBounds; + int x = bounds.x - myBounds.x + getX(); + int y = bounds.y - myBounds.y + getY(); + g.setColor(JBColor.BLUE); + g.fillRect(x, y, bounds.width, bounds.height); + + bounds = info.myInnerBounds; + x = bounds.x - myBounds.x + getX(); + y = bounds.y - myBounds.y + getY(); + g.setColor(JBColor.BLACK); + g.fillRect(x, y, bounds.width, bounds.height); + + String id = String.valueOf(i + 1); + g.setColor(JBColor.WHITE); + g.setFont(new Font("Monospaced", Font.BOLD, Math.min(bounds.width, bounds.height))); + FontMetrics fm = g.getFontMetrics(); + x += (bounds.width - fm.stringWidth(id)) / 2; + y += (bounds.height - fm.getHeight()) / 2; + g.drawString(id, x, y + bounds.height); + } + g.dispose(); + } + } +} diff --git a/platform/platform-api/src/com/intellij/ui/ScreenUtil.java b/platform/platform-api/src/com/intellij/ui/ScreenUtil.java index 2f3f2b1d9566..62ebc994c5c6 100644 --- a/platform/platform-api/src/com/intellij/ui/ScreenUtil.java +++ b/platform/platform-api/src/com/intellij/ui/ScreenUtil.java @@ -206,7 +206,16 @@ public class ScreenUtil { * @return a visible area rectangle */ private static Rectangle getScreenRectangle(GraphicsDevice device) { - GraphicsConfiguration configuration = device.getDefaultConfiguration(); + return getScreenRectangle(device.getDefaultConfiguration()); + } + + /** + * Returns a visible area for the specified graphics configuration. + * + * @param configuration one of available configurations + * @return a visible area rectangle + */ + public static Rectangle getScreenRectangle(GraphicsConfiguration configuration) { return applyInsets(configuration.getBounds(), getScreenInsets(configuration)); } diff --git a/resources/src/idea/RichPlatformActions.xml b/resources/src/idea/RichPlatformActions.xml index 3ba8f55e5aaa..17591405eaff 100644 --- a/resources/src/idea/RichPlatformActions.xml +++ b/resources/src/idea/RichPlatformActions.xml @@ -133,6 +133,7 @@ + From 18b57b20c19f80365e71a7a03891905f2bc5af67 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Tue, 17 Mar 2015 19:42:02 +0300 Subject: [PATCH 7/7] IDEA-137716 Do not return invisible combo box as preferred focus owner --- .../src/com/intellij/tasks/actions/CloseTaskDialog.java | 2 +- .../src/com/intellij/tasks/actions/OpenTaskDialog.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskDialog.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskDialog.java index 73d14d23435a..3fd1662b7852 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskDialog.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskDialog.java @@ -95,7 +95,7 @@ public class CloseTaskDialog extends DialogWrapper { @Nullable @Override public JComponent getPreferredFocusedComponent() { - return myStateCombo.getComboBox(); + return myStateCombo.isVisible() ? myStateCombo.getComboBox() : null; } @Nullable diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.java index 485161687d68..a00660449046 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.java @@ -274,9 +274,10 @@ public class OpenTaskDialog extends DialogWrapper { else if (myCreateChangelist.isSelected()) { return myChangelistName; } - else { + else if (myTaskStateCombo.isVisible()){ return myTaskStateCombo.getComboBox(); } + return null; } protected JComponent createCenterPanel() {