From c60015ed74fdc8841a786d67bbf4131f7b238279 Mon Sep 17 00:00:00 2001 From: Michael Estermann Date: Thu, 19 Dec 2019 22:35:25 +0100 Subject: [PATCH 01/19] Empty red settings page. --- .../java/com/layoutmanager/ui/settings.java | 40 +++++++++++++++++++ src/main/resources/META-INF/plugin.xml | 2 + 2 files changed, 42 insertions(+) create mode 100644 src/main/java/com/layoutmanager/ui/settings.java diff --git a/src/main/java/com/layoutmanager/ui/settings.java b/src/main/java/com/layoutmanager/ui/settings.java new file mode 100644 index 0000000..b093d46 --- /dev/null +++ b/src/main/java/com/layoutmanager/ui/settings.java @@ -0,0 +1,40 @@ +package com.layoutmanager.ui; + +import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.ConfigurationException; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; + +public class settings implements Configurable { + @Nls(capitalization = Nls.Capitalization.Title) + @Override + public String getDisplayName() { + return "Hello World"; + } + + @Nullable + @Override + public JComponent createComponent() { + JPanel panel = new JPanel(); + panel.setBackground(Color.red); + return panel; + } + + @Override + public boolean isModified() { + return false; + } + + @Override + public void apply() throws ConfigurationException { + + } + + @Override + public void reset() { + + } +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 2115989..73c8148 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -39,6 +39,8 @@ + + \ No newline at end of file From 6da05bdcf8594b84922a417ab0dcbb84252df5dd Mon Sep 17 00:00:00 2001 From: Michael Estermann Date: Fri, 20 Dec 2019 23:08:19 +0100 Subject: [PATCH 02/19] Introduced smart docking when storing a layout. --- .../delete}/DeleteLayoutAction.java | 6 +- .../restore}/RestoreLayoutAction.java | 6 +- .../store}/LayoutCreator.java | 31 +++++-- .../store/create}/NewLayoutAction.java | 16 ++-- .../overwrite}/OverwriteLayoutAction.java | 18 ++-- .../layout/store/smartdock/SmartDocker.java | 59 +++++++++++++ .../store/smartdock/SmartDockerFactory.java | 16 ++++ .../store/smartdock/ToolWindowDocking.java | 73 +++++++++++++++++ .../smartdock/dockers/ScreenBorderDocker.java | 82 +++++++++++++++++++ .../smartdock/dockers/ToolWindowDocker.java | 65 +++++++++++++++ .../dockers/ToolWindowToScreenShrinker.java | 26 ++++++ .../validation}/LayoutValidationHelper.java | 2 +- .../startup/PluginBootstrapper.java | 2 +- .../ui/{ => helpers}/NotificationHelper.java | 2 +- .../ui/helpers/ScreenSizeHelper.java | 35 ++++++++ .../ui/{ => helpers}/ToolWindowHelper.java | 2 +- .../{ => ui}/menu/WindowMenuService.java | 18 ++-- .../SettingsPage.java} | 4 +- src/main/resources/META-INF/plugin.xml | 4 +- 19 files changed, 427 insertions(+), 40 deletions(-) rename src/main/java/com/layoutmanager/{actions => layout/delete}/DeleteLayoutAction.java (88%) rename src/main/java/com/layoutmanager/{actions => layout/restore}/RestoreLayoutAction.java (92%) rename src/main/java/com/layoutmanager/{actions => layout/store}/LayoutCreator.java (73%) rename src/main/java/com/layoutmanager/{actions => layout/store/create}/NewLayoutAction.java (70%) rename src/main/java/com/layoutmanager/{actions => layout/store/overwrite}/OverwriteLayoutAction.java (75%) create mode 100644 src/main/java/com/layoutmanager/layout/store/smartdock/SmartDocker.java create mode 100644 src/main/java/com/layoutmanager/layout/store/smartdock/SmartDockerFactory.java create mode 100644 src/main/java/com/layoutmanager/layout/store/smartdock/ToolWindowDocking.java create mode 100644 src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ScreenBorderDocker.java create mode 100644 src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowDocker.java create mode 100644 src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowToScreenShrinker.java rename src/main/java/com/layoutmanager/{actions => layout/store/validation}/LayoutValidationHelper.java (92%) rename src/main/java/com/layoutmanager/ui/{ => helpers}/NotificationHelper.java (95%) create mode 100644 src/main/java/com/layoutmanager/ui/helpers/ScreenSizeHelper.java rename src/main/java/com/layoutmanager/ui/{ => helpers}/ToolWindowHelper.java (95%) rename src/main/java/com/layoutmanager/{ => ui}/menu/WindowMenuService.java (77%) rename src/main/java/com/layoutmanager/ui/{settings.java => settings/SettingsPage.java} (85%) diff --git a/src/main/java/com/layoutmanager/actions/DeleteLayoutAction.java b/src/main/java/com/layoutmanager/layout/delete/DeleteLayoutAction.java similarity index 88% rename from src/main/java/com/layoutmanager/actions/DeleteLayoutAction.java rename to src/main/java/com/layoutmanager/layout/delete/DeleteLayoutAction.java index 9249f7e..d69ea6c 100644 --- a/src/main/java/com/layoutmanager/actions/DeleteLayoutAction.java +++ b/src/main/java/com/layoutmanager/layout/delete/DeleteLayoutAction.java @@ -1,4 +1,4 @@ -package com.layoutmanager.actions; +package com.layoutmanager.layout.delete; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnAction; @@ -6,10 +6,10 @@ import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.components.ServiceManager; import com.layoutmanager.localization.MessagesHelper; -import com.layoutmanager.menu.WindowMenuService; +import com.layoutmanager.ui.menu.WindowMenuService; import com.layoutmanager.persistence.Layout; import com.layoutmanager.persistence.LayoutConfig; -import com.layoutmanager.ui.NotificationHelper; +import com.layoutmanager.ui.helpers.NotificationHelper; import org.jetbrains.annotations.NotNull; public class DeleteLayoutAction extends AnAction { diff --git a/src/main/java/com/layoutmanager/actions/RestoreLayoutAction.java b/src/main/java/com/layoutmanager/layout/restore/RestoreLayoutAction.java similarity index 92% rename from src/main/java/com/layoutmanager/actions/RestoreLayoutAction.java rename to src/main/java/com/layoutmanager/layout/restore/RestoreLayoutAction.java index a5a8e8d..aa8e7c9 100644 --- a/src/main/java/com/layoutmanager/actions/RestoreLayoutAction.java +++ b/src/main/java/com/layoutmanager/layout/restore/RestoreLayoutAction.java @@ -1,4 +1,4 @@ -package com.layoutmanager.actions; +package com.layoutmanager.layout.restore; import com.intellij.icons.AllIcons; import com.intellij.ide.ui.UISettings; @@ -12,8 +12,8 @@ import com.layoutmanager.localization.MessagesHelper; import com.layoutmanager.persistence.Layout; import com.layoutmanager.persistence.ToolWindowInfo; -import com.layoutmanager.ui.NotificationHelper; -import com.layoutmanager.ui.ToolWindowHelper; +import com.layoutmanager.ui.helpers.NotificationHelper; +import com.layoutmanager.ui.helpers.ToolWindowHelper; import org.jetbrains.annotations.NotNull; public class RestoreLayoutAction extends AnAction { diff --git a/src/main/java/com/layoutmanager/actions/LayoutCreator.java b/src/main/java/com/layoutmanager/layout/store/LayoutCreator.java similarity index 73% rename from src/main/java/com/layoutmanager/actions/LayoutCreator.java rename to src/main/java/com/layoutmanager/layout/store/LayoutCreator.java index 7c3ac74..faa0794 100644 --- a/src/main/java/com/layoutmanager/actions/LayoutCreator.java +++ b/src/main/java/com/layoutmanager/layout/store/LayoutCreator.java @@ -1,16 +1,18 @@ -package com.layoutmanager.actions; +package com.layoutmanager.layout.store; import com.intellij.icons.AllIcons; import com.intellij.ide.ui.UISettings; -import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.openapi.wm.impl.ToolWindowImpl; +import com.layoutmanager.layout.store.smartdock.SmartDocker; +import com.layoutmanager.layout.store.smartdock.SmartDockerFactory; +import com.layoutmanager.layout.store.validation.LayoutValidationHelper; import com.layoutmanager.localization.MessagesHelper; import com.layoutmanager.persistence.Layout; import com.layoutmanager.persistence.ToolWindowInfo; -import com.layoutmanager.ui.NotificationHelper; -import com.layoutmanager.ui.ToolWindowHelper; +import com.layoutmanager.ui.helpers.NotificationHelper; +import com.layoutmanager.ui.helpers.ToolWindowHelper; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -19,15 +21,21 @@ public class LayoutCreator { - public static Layout create(Project project, String defaultName) { + private final SmartDockerFactory smartDockerFactory; + + public LayoutCreator(SmartDockerFactory smartDockerFactory) { + this.smartDockerFactory = smartDockerFactory; + } + + public Layout create(ToolWindowManager toolWindowManager, String defaultName) { String name = getLayoutName(defaultName); return name != null ? - createLayout(ToolWindowManager.getInstance(project), name) : + createLayout(toolWindowManager, name) : null; } - private static String getLayoutName(String defaultName) { + private String getLayoutName(String defaultName) { String name; do { name = Messages.showInputDialog( @@ -41,12 +49,14 @@ private static String getLayoutName(String defaultName) { return name; } - private static Layout createLayout(ToolWindowManager toolWindowManager, String name) { + private Layout createLayout(ToolWindowManager toolWindowManager, String name) { List toolWindows = getToolWindows(toolWindowManager); Layout layout = new Layout( name, toolWindows.toArray(ToolWindowInfo[]::new), getEditorPlacement()); + + dock(toolWindowManager, layout); validateLayout(layout); return layout; @@ -72,6 +82,11 @@ private static List getToolWindows(ToolWindowManager toolWindowM return toolWindows; } + private void dock(ToolWindowManager toolWindowManager, Layout layout) { + SmartDocker smartDocker = smartDockerFactory.create(toolWindowManager); + smartDocker.dock(layout); + } + private static void validateLayout(Layout layout) { ToolWindowInfo[] invalidToolWindows = LayoutValidationHelper.retrieveToolWindowsOutsideOfScreen(layout); if (invalidToolWindows.length != 0) { diff --git a/src/main/java/com/layoutmanager/actions/NewLayoutAction.java b/src/main/java/com/layoutmanager/layout/store/create/NewLayoutAction.java similarity index 70% rename from src/main/java/com/layoutmanager/actions/NewLayoutAction.java rename to src/main/java/com/layoutmanager/layout/store/create/NewLayoutAction.java index 43c893b..7acb182 100644 --- a/src/main/java/com/layoutmanager/actions/NewLayoutAction.java +++ b/src/main/java/com/layoutmanager/layout/store/create/NewLayoutAction.java @@ -1,20 +1,25 @@ -package com.layoutmanager.actions; +package com.layoutmanager.layout.store.create; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.wm.ToolWindowManager; +import com.layoutmanager.layout.store.LayoutCreator; import com.layoutmanager.localization.MessagesHelper; -import com.layoutmanager.menu.WindowMenuService; +import com.layoutmanager.ui.menu.WindowMenuService; import com.layoutmanager.persistence.Layout; import com.layoutmanager.persistence.LayoutConfig; -import com.layoutmanager.ui.NotificationHelper; +import com.layoutmanager.ui.helpers.NotificationHelper; import org.jetbrains.annotations.NotNull; public class NewLayoutAction extends AnAction { - public NewLayoutAction() { + private final LayoutCreator layoutCreator; + + public NewLayoutAction(LayoutCreator layoutCreator) { + this.layoutCreator = layoutCreator; Presentation presentation = this.getTemplatePresentation(); presentation.setText(MessagesHelper.message("StoreLayout.New.Menu")); presentation.setIcon(AllIcons.Welcome.CreateNewProject); @@ -22,7 +27,8 @@ public NewLayoutAction() { @Override public void actionPerformed(@NotNull AnActionEvent event) { - Layout updatedLayout = LayoutCreator.create(event.getProject(), ""); + ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(event.getProject()); + Layout updatedLayout = layoutCreator.create(toolWindowManager, ""); if (updatedLayout != null) { this.storeLayout(updatedLayout); diff --git a/src/main/java/com/layoutmanager/actions/OverwriteLayoutAction.java b/src/main/java/com/layoutmanager/layout/store/overwrite/OverwriteLayoutAction.java similarity index 75% rename from src/main/java/com/layoutmanager/actions/OverwriteLayoutAction.java rename to src/main/java/com/layoutmanager/layout/store/overwrite/OverwriteLayoutAction.java index 6ae4712..7b868fe 100644 --- a/src/main/java/com/layoutmanager/actions/OverwriteLayoutAction.java +++ b/src/main/java/com/layoutmanager/layout/store/overwrite/OverwriteLayoutAction.java @@ -1,23 +1,28 @@ -package com.layoutmanager.actions; +package com.layoutmanager.layout.store.overwrite; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.wm.ToolWindowManager; +import com.layoutmanager.layout.store.LayoutCreator; import com.layoutmanager.localization.MessagesHelper; -import com.layoutmanager.menu.WindowMenuService; +import com.layoutmanager.ui.menu.WindowMenuService; import com.layoutmanager.persistence.Layout; import com.layoutmanager.persistence.LayoutConfig; -import com.layoutmanager.ui.NotificationHelper; +import com.layoutmanager.ui.helpers.NotificationHelper; import org.jetbrains.annotations.NotNull; public class OverwriteLayoutAction extends AnAction { + private final LayoutCreator layoutCreator; public final int number; - public OverwriteLayoutAction(int number) { - + public OverwriteLayoutAction( + LayoutCreator layoutCreator, + int number) { + this.layoutCreator = layoutCreator; this.number = number; Layout layout = LayoutConfig.getInstance().getLayout(number); @@ -36,7 +41,8 @@ public void update(AnActionEvent e) { @Override public void actionPerformed(@NotNull AnActionEvent event) { Layout previousLayout = LayoutConfig.getInstance().getLayout(number); - Layout updatedLayout = LayoutCreator.create(event.getProject(), previousLayout.getName()); + ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(event.getProject()); + Layout updatedLayout = layoutCreator.create(toolWindowManager, previousLayout.getName()); if (updatedLayout != null) { this.storeLayout(updatedLayout); diff --git a/src/main/java/com/layoutmanager/layout/store/smartdock/SmartDocker.java b/src/main/java/com/layoutmanager/layout/store/smartdock/SmartDocker.java new file mode 100644 index 0000000..9c02b6f --- /dev/null +++ b/src/main/java/com/layoutmanager/layout/store/smartdock/SmartDocker.java @@ -0,0 +1,59 @@ +package com.layoutmanager.layout.store.smartdock; + +import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.openapi.wm.ToolWindowType; +import com.intellij.openapi.wm.impl.ToolWindowImpl; +import com.layoutmanager.layout.store.smartdock.dockers.ScreenBorderDocker; +import com.layoutmanager.layout.store.smartdock.dockers.ToolWindowDocker; +import com.layoutmanager.layout.store.smartdock.dockers.ToolWindowToScreenShrinker; +import com.layoutmanager.persistence.Layout; +import com.layoutmanager.persistence.ToolWindowInfo; +import com.layoutmanager.ui.helpers.ScreenSizeHelper; + +import java.util.Arrays; + +public class SmartDocker { + private static final int THRESHOLD = 20; + + private final ToolWindowManager toolWindowManager; + private final ToolWindowToScreenShrinker shrinker; + private final ToolWindowDocker toolWindowDocker; + private final ScreenBorderDocker screenBorderDocker; + + public SmartDocker( + ToolWindowManager toolWindowManager, + ToolWindowToScreenShrinker shrinker, + ToolWindowDocker toolWindowDocker, + ScreenBorderDocker screenBorderDocker) { + this.toolWindowManager = toolWindowManager; + this.shrinker = shrinker; + this.toolWindowDocker = toolWindowDocker; + this.screenBorderDocker = screenBorderDocker; + } + + public void dock(Layout layout) { + ToolWindowDocking[] floatedOrWindowsToolWindows = getFloatedOrWindowsToolWindows(layout); + + shrinker.shrink(floatedOrWindowsToolWindows); + toolWindowDocker.dock(floatedOrWindowsToolWindows); + screenBorderDocker.dock(floatedOrWindowsToolWindows, THRESHOLD); + } + + + private ToolWindowDocking[] getFloatedOrWindowsToolWindows(Layout layout) { + return Arrays.stream(layout.getToolWindows()) + .filter(this::isFloatingOrWindowedToolWindow) + .map(x -> new ToolWindowDocking( + x, + (ToolWindowImpl)toolWindowManager.getToolWindow(x.getId()), + ScreenSizeHelper.getContainingScreenBounds(x), + THRESHOLD)) + .toArray(ToolWindowDocking[]::new); + } + + private boolean isFloatingOrWindowedToolWindow(ToolWindowInfo toolWindow) { + return toolWindowManager.getToolWindow(toolWindow.getId()) != null && + toolWindow.getType() == ToolWindowType.FLOATING || + toolWindow.getType() == ToolWindowType.WINDOWED; + } +} diff --git a/src/main/java/com/layoutmanager/layout/store/smartdock/SmartDockerFactory.java b/src/main/java/com/layoutmanager/layout/store/smartdock/SmartDockerFactory.java new file mode 100644 index 0000000..d1a1525 --- /dev/null +++ b/src/main/java/com/layoutmanager/layout/store/smartdock/SmartDockerFactory.java @@ -0,0 +1,16 @@ +package com.layoutmanager.layout.store.smartdock; + +import com.intellij.openapi.wm.ToolWindowManager; +import com.layoutmanager.layout.store.smartdock.dockers.ScreenBorderDocker; +import com.layoutmanager.layout.store.smartdock.dockers.ToolWindowDocker; +import com.layoutmanager.layout.store.smartdock.dockers.ToolWindowToScreenShrinker; + +public class SmartDockerFactory { + public SmartDocker create(ToolWindowManager toolWindowManager) { + return new SmartDocker( + toolWindowManager, + new ToolWindowToScreenShrinker(), + new ToolWindowDocker(), + new ScreenBorderDocker()); + } +} diff --git a/src/main/java/com/layoutmanager/layout/store/smartdock/ToolWindowDocking.java b/src/main/java/com/layoutmanager/layout/store/smartdock/ToolWindowDocking.java new file mode 100644 index 0000000..62f2122 --- /dev/null +++ b/src/main/java/com/layoutmanager/layout/store/smartdock/ToolWindowDocking.java @@ -0,0 +1,73 @@ +package com.layoutmanager.layout.store.smartdock; + +import com.intellij.openapi.wm.impl.ToolWindowImpl; +import com.layoutmanager.persistence.ToolWindowInfo; + +import java.awt.*; + +public class ToolWindowDocking { + + private final ToolWindowInfo toolWindowInfo; + private final ToolWindowImpl toolWindow; + private final Rectangle containingScreen; + private final int threshold; + + public ToolWindowDocking( + ToolWindowInfo toolWindowInfo, + ToolWindowImpl toolWindow, + Rectangle containingScreen, + int threshold) { + this.toolWindowInfo = toolWindowInfo; + this.toolWindow = toolWindow; + this.containingScreen = containingScreen; + this.threshold = threshold; + } + + public ToolWindowInfo getToolWindowInfo() { + return this.toolWindowInfo; + } + + public ToolWindowImpl getToolWindow() { + return toolWindow; + } + + public Rectangle getContainingScreen() { + return containingScreen; + } + + public Rectangle getBounds() { + return toolWindowInfo.getBounds(); + } + + public Rectangle getLeftDockingBounds() { + return new Rectangle( + (int) Math.max(0, toolWindowInfo.getBounds().getX() - threshold), + (int) toolWindowInfo.getBounds().getY(), + threshold * 2, + (int) toolWindowInfo.getBounds().getHeight()); + } + + public Rectangle getTopDockingBounds() { + return new Rectangle( + (int) toolWindowInfo.getBounds().getX(), + (int) Math.max(0, toolWindowInfo.getBounds().getY() - threshold), + (int) toolWindowInfo.getBounds().getWidth(), + threshold * 2); + } + + public Rectangle getRightDockingBounds() { + return new Rectangle( + (int) (toolWindowInfo.getBounds().getMaxX() - threshold), + (int) toolWindowInfo.getBounds().getY(), + (int) Math.min(threshold * 2, threshold + containingScreen.getMaxX() - toolWindowInfo.getBounds().getMaxX()), + (int) toolWindowInfo.getBounds().getHeight()); + } + + public Rectangle getBottomDockingBounds() { + return new Rectangle( + (int) toolWindowInfo.getBounds().getX(), + (int) toolWindowInfo.getBounds().getMaxY() - threshold, + (int) toolWindowInfo.getBounds().getWidth(), + (int) Math.min(threshold * 2, threshold + containingScreen.getMaxY() - toolWindowInfo.getBounds().getMaxY())); + } +} diff --git a/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ScreenBorderDocker.java b/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ScreenBorderDocker.java new file mode 100644 index 0000000..60ad0e7 --- /dev/null +++ b/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ScreenBorderDocker.java @@ -0,0 +1,82 @@ +package com.layoutmanager.layout.store.smartdock.dockers; + +import com.layoutmanager.layout.store.smartdock.ToolWindowDocking; + +import java.awt.*; +import java.util.function.BiFunction; +import java.util.function.Function; + +public class ScreenBorderDocker { + public void dock(ToolWindowDocking[] floatedOrWindowsToolWindows, int threshold) { + pinLeft(floatedOrWindowsToolWindows, threshold); + pinTop(floatedOrWindowsToolWindows, threshold); + pinRight(floatedOrWindowsToolWindows, threshold); + pinBottom(floatedOrWindowsToolWindows, threshold); + } + + private void pinLeft(ToolWindowDocking[] floatedOrWindowsToolWindows, int threshold) { + pinToScreenBorder( + floatedOrWindowsToolWindows, + threshold, + toolWindowDocking -> (int)(toolWindowDocking.getBounds().getX() - toolWindowDocking.getContainingScreen().getX()), + (toolWindowDocking, difference) -> new Rectangle( + (int)toolWindowDocking.getContainingScreen().getX(), + (int)toolWindowDocking.getBounds().getY(), + (int)(toolWindowDocking.getBounds().getWidth()+ difference), + (int)toolWindowDocking.getBounds().getHeight()) + ); + } + + private void pinTop(ToolWindowDocking[] floatedOrWindowsToolWindows, int threshold) { + pinToScreenBorder( + floatedOrWindowsToolWindows, + threshold, + x -> (int)(x.getBounds().getY() - x.getContainingScreen().getY()), + (toolWindowDocking, difference) -> new Rectangle( + (int)toolWindowDocking.getBounds().getX(), + (int)toolWindowDocking.getContainingScreen().getY(), + (int)toolWindowDocking.getBounds().getWidth(), + (int)(toolWindowDocking.getBounds().getHeight() + 5) + )); + } + + private void pinRight(ToolWindowDocking[] floatedOrWindowsToolWindows, int threshold) { + pinToScreenBorder( + floatedOrWindowsToolWindows, + threshold, + toolWindowDocking -> (int)(toolWindowDocking.getContainingScreen().getMaxX() - toolWindowDocking.getBounds().getMaxX()), + (toolWindowDocking, difference) -> new Rectangle( + (int)toolWindowDocking.getBounds().getX(), + (int)toolWindowDocking.getBounds().getY(), + (int)(toolWindowDocking.getBounds().getWidth() + difference), + (int)toolWindowDocking.getBounds().getHeight()) + ); + } + + private void pinBottom(ToolWindowDocking[] floatedOrWindowsToolWindows, int threshold) { + pinToScreenBorder( + floatedOrWindowsToolWindows, + threshold, + toolWindowDocking -> (int)(toolWindowDocking.getBounds().getY() - toolWindowDocking.getContainingScreen().getY()), + (toolWindowDocking, difference) -> new Rectangle( + (int)toolWindowDocking.getBounds().getX(), + (int)toolWindowDocking.getBounds().getY(), + (int)toolWindowDocking.getBounds().getWidth(), + (int)(toolWindowDocking.getBounds().getHeight() + difference)) + ); + } + + private void pinToScreenBorder( + ToolWindowDocking[] toolWindowDockings, + int threshold, + Function getDifference, + BiFunction calculateBounds) { + + for (ToolWindowDocking toolWindowDocking : toolWindowDockings) { + Integer difference = getDifference.apply(toolWindowDocking); + if (difference != 0 && difference < threshold) { + toolWindowDocking.getToolWindowInfo().setBounds(calculateBounds.apply(toolWindowDocking, difference)); + } + } + } +} diff --git a/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowDocker.java b/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowDocker.java new file mode 100644 index 0000000..c2ba892 --- /dev/null +++ b/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowDocker.java @@ -0,0 +1,65 @@ +package com.layoutmanager.layout.store.smartdock.dockers; + +import com.layoutmanager.layout.store.smartdock.ToolWindowDocking; + +import java.awt.*; +import java.util.Arrays; +import java.util.Comparator; + +public class ToolWindowDocker { + public void dock(ToolWindowDocking[] floatedOrWindowsToolWindows) { + dockLeft(floatedOrWindowsToolWindows); + dockTop(floatedOrWindowsToolWindows); + // TODO: Add bottom and left in a more generic way... + } + + private void dockLeft(ToolWindowDocking[] floatedOrWindowsToolWindows) { + ToolWindowDocking[] sortedByLeftPosition = Arrays.stream(floatedOrWindowsToolWindows) + .sorted((x, y) -> (int) (x.getBounds().getX() - y.getBounds().getX())) + .skip(1) + .toArray(ToolWindowDocking[]::new); + + for (ToolWindowDocking toolWindowDocking : sortedByLeftPosition) { + ToolWindowDocking[] intersectionToolWindows = Arrays.stream(floatedOrWindowsToolWindows) + .filter(x -> x.getToolWindowInfo().getId() != toolWindowDocking.getToolWindowInfo().getId() && x.getRightDockingBounds().intersects(toolWindowDocking.getLeftDockingBounds())) + .sorted(Comparator.comparingInt(x -> (int) x.getBounds().getY())) + .toArray(ToolWindowDocking[]::new); + + if (intersectionToolWindows.length > 0) { + int x = (int)toolWindowDocking.getBounds().getX(); + int newX = (int)intersectionToolWindows[0].getBounds().getMaxX(); + Rectangle newBounds = new Rectangle( + newX, + (int) toolWindowDocking.getBounds().getY(), + (int)(toolWindowDocking.getBounds().getWidth() + (x - newX)), + (int) toolWindowDocking.getBounds().getHeight()); + toolWindowDocking.getToolWindowInfo().setBounds(newBounds); + } + } + } + + private void dockTop(ToolWindowDocking[] floatedOrWindowsToolWindows) { + ToolWindowDocking[] sortedByTopPosition = Arrays.stream(floatedOrWindowsToolWindows) + .sorted((x, y) -> (int) (x.getBounds().getY() - y.getBounds().getY())) + .skip(1) + .toArray(ToolWindowDocking[]::new); + + for (ToolWindowDocking toolWindowDocking : sortedByTopPosition) { + ToolWindowDocking[] intersectionToolWindows = Arrays.stream(floatedOrWindowsToolWindows) + .filter(x -> x.getToolWindowInfo().getId() != toolWindowDocking.getToolWindowInfo().getId() && x.getBottomDockingBounds().intersects(toolWindowDocking.getTopDockingBounds())) + .sorted(Comparator.comparingInt(x -> (int) x.getBounds().getX())) + .toArray(ToolWindowDocking[]::new); + + if (intersectionToolWindows.length > 0) { + int y = (int)toolWindowDocking.getBounds().getY(); + int newY = (int)intersectionToolWindows[0].getBounds().getMaxY(); + Rectangle newBounds = new Rectangle( + (int) toolWindowDocking.getBounds().getX(), + newY, + (int) toolWindowDocking.getBounds().getWidth(), + (int)(toolWindowDocking.getBounds().getHeight() + (y - newY))); + toolWindowDocking.getToolWindowInfo().setBounds(newBounds); + } + } + } +} diff --git a/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowToScreenShrinker.java b/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowToScreenShrinker.java new file mode 100644 index 0000000..fa23787 --- /dev/null +++ b/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowToScreenShrinker.java @@ -0,0 +1,26 @@ +package com.layoutmanager.layout.store.smartdock.dockers; + +import com.layoutmanager.layout.store.smartdock.ToolWindowDocking; + +import java.awt.*; + +public class ToolWindowToScreenShrinker { + public void shrink(ToolWindowDocking[] floatedOrWindowsToolWindowDockings) { + for (ToolWindowDocking toolWindowDocking : floatedOrWindowsToolWindowDockings) { + Rectangle containingScreen = toolWindowDocking.getContainingScreen(); + Rectangle toolWindowBounds = toolWindowDocking.getBounds(); + + if (!containingScreen.contains(toolWindowBounds)) { + double x = Math.max(toolWindowBounds.getX(), containingScreen.getX()); + double y = Math.max(toolWindowBounds.getY(), containingScreen.getY()); + Rectangle newToolWindowBounds = new Rectangle( + (int)x, + (int)y, + (int)Math.min(toolWindowBounds.getWidth(), containingScreen.getMaxX() - x), + (int)Math.min(toolWindowBounds.getHeight(), containingScreen.getMaxY() - y)); + + toolWindowDocking.getToolWindowInfo().setBounds(newToolWindowBounds); + } + } + } +} diff --git a/src/main/java/com/layoutmanager/actions/LayoutValidationHelper.java b/src/main/java/com/layoutmanager/layout/store/validation/LayoutValidationHelper.java similarity index 92% rename from src/main/java/com/layoutmanager/actions/LayoutValidationHelper.java rename to src/main/java/com/layoutmanager/layout/store/validation/LayoutValidationHelper.java index 013be40..11dc049 100644 --- a/src/main/java/com/layoutmanager/actions/LayoutValidationHelper.java +++ b/src/main/java/com/layoutmanager/layout/store/validation/LayoutValidationHelper.java @@ -1,4 +1,4 @@ -package com.layoutmanager.actions; +package com.layoutmanager.layout.store.validation; import com.intellij.openapi.wm.ToolWindowType; import com.intellij.openapi.wm.WindowManager; diff --git a/src/main/java/com/layoutmanager/startup/PluginBootstrapper.java b/src/main/java/com/layoutmanager/startup/PluginBootstrapper.java index ce24aba..4cfe15f 100644 --- a/src/main/java/com/layoutmanager/startup/PluginBootstrapper.java +++ b/src/main/java/com/layoutmanager/startup/PluginBootstrapper.java @@ -4,7 +4,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupActivity; import com.layoutmanager.cleanup.EmptyLayoutRemoverService; -import com.layoutmanager.menu.WindowMenuService; +import com.layoutmanager.ui.menu.WindowMenuService; import org.jetbrains.annotations.NotNull; public class PluginBootstrapper implements StartupActivity { diff --git a/src/main/java/com/layoutmanager/ui/NotificationHelper.java b/src/main/java/com/layoutmanager/ui/helpers/NotificationHelper.java similarity index 95% rename from src/main/java/com/layoutmanager/ui/NotificationHelper.java rename to src/main/java/com/layoutmanager/ui/helpers/NotificationHelper.java index ffc8e10..aeecc74 100644 --- a/src/main/java/com/layoutmanager/ui/NotificationHelper.java +++ b/src/main/java/com/layoutmanager/ui/helpers/NotificationHelper.java @@ -1,4 +1,4 @@ -package com.layoutmanager.ui; +package com.layoutmanager.ui.helpers; import com.intellij.notification.Notification; import com.intellij.notification.NotificationDisplayType; diff --git a/src/main/java/com/layoutmanager/ui/helpers/ScreenSizeHelper.java b/src/main/java/com/layoutmanager/ui/helpers/ScreenSizeHelper.java new file mode 100644 index 0000000..89f999a --- /dev/null +++ b/src/main/java/com/layoutmanager/ui/helpers/ScreenSizeHelper.java @@ -0,0 +1,35 @@ +package com.layoutmanager.ui.helpers; + +import com.layoutmanager.persistence.ToolWindowInfo; +import sun.java2d.SunGraphicsEnvironment; + +import java.awt.*; +import java.util.Arrays; +import java.util.Comparator; + +public class ScreenSizeHelper { + public static Rectangle getContainingScreenBounds(ToolWindowInfo toolWindow) { + return Arrays + .stream(GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()) + .map(x -> getScreenRectangle(x)) + .sorted(Comparator.comparingInt(x -> 0 - getIntersectionSize(x, toolWindow.getBounds()))) + .findFirst() + .orElse(new Rectangle()); + } + + + + private static Rectangle getScreenRectangle(GraphicsDevice device) { + Rectangle defaultBounds = SunGraphicsEnvironment.getUsableBounds(device); + return new Rectangle( + (int)defaultBounds.getX(), + (int)defaultBounds.getY(), + (int)defaultBounds.getWidth(), + (int)defaultBounds.getHeight()); + } + + private static int getIntersectionSize(Rectangle screen, Rectangle window) { + return (int)(Math.max(0, Math.min(screen.getMaxX(), window.getMaxX()) - Math.max(screen.getX(), window.getX())) * + Math.max(0, Math.min(screen.getMaxY(), window.getMaxY()) - Math.max(screen.getY(), window.getY()))); + } +} diff --git a/src/main/java/com/layoutmanager/ui/ToolWindowHelper.java b/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java similarity index 95% rename from src/main/java/com/layoutmanager/ui/ToolWindowHelper.java rename to src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java index ed76b10..5d36e1f 100644 --- a/src/main/java/com/layoutmanager/ui/ToolWindowHelper.java +++ b/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java @@ -1,4 +1,4 @@ -package com.layoutmanager.ui; +package com.layoutmanager.ui.helpers; import com.intellij.openapi.wm.ToolWindowType; import com.intellij.openapi.wm.impl.FloatingDecorator; diff --git a/src/main/java/com/layoutmanager/menu/WindowMenuService.java b/src/main/java/com/layoutmanager/ui/menu/WindowMenuService.java similarity index 77% rename from src/main/java/com/layoutmanager/menu/WindowMenuService.java rename to src/main/java/com/layoutmanager/ui/menu/WindowMenuService.java index a5b984f..c633604 100644 --- a/src/main/java/com/layoutmanager/menu/WindowMenuService.java +++ b/src/main/java/com/layoutmanager/ui/menu/WindowMenuService.java @@ -1,11 +1,13 @@ -package com.layoutmanager.menu; +package com.layoutmanager.ui.menu; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.DefaultActionGroup; -import com.layoutmanager.actions.DeleteLayoutAction; -import com.layoutmanager.actions.NewLayoutAction; -import com.layoutmanager.actions.OverwriteLayoutAction; -import com.layoutmanager.actions.RestoreLayoutAction; +import com.layoutmanager.layout.delete.DeleteLayoutAction; +import com.layoutmanager.layout.store.LayoutCreator; +import com.layoutmanager.layout.store.create.NewLayoutAction; +import com.layoutmanager.layout.store.overwrite.OverwriteLayoutAction; +import com.layoutmanager.layout.restore.RestoreLayoutAction; +import com.layoutmanager.layout.store.smartdock.SmartDockerFactory; import com.layoutmanager.localization.MessagesHelper; import com.layoutmanager.persistence.Layout; import com.layoutmanager.persistence.LayoutConfig; @@ -53,15 +55,17 @@ private void createStoreRestoreActions() { } private void addStoreLayoutActions(LayoutConfig config) { + LayoutCreator layoutCreator = new LayoutCreator(new SmartDockerFactory()); + for (int index = 0; index < config.getLayoutCount(); index++) { - this.storeLayout.add(new OverwriteLayoutAction(index)); + this.storeLayout.add(new OverwriteLayoutAction(layoutCreator, index)); } if (config.getLayoutCount() > 0) { this.storeLayout.addSeparator(); } - this.storeLayout.add(new NewLayoutAction()); + this.storeLayout.add(new NewLayoutAction(layoutCreator)); } private void addRestoreLayoutActions(LayoutConfig config) { diff --git a/src/main/java/com/layoutmanager/ui/settings.java b/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java similarity index 85% rename from src/main/java/com/layoutmanager/ui/settings.java rename to src/main/java/com/layoutmanager/ui/settings/SettingsPage.java index b093d46..f21220b 100644 --- a/src/main/java/com/layoutmanager/ui/settings.java +++ b/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java @@ -1,4 +1,4 @@ -package com.layoutmanager.ui; +package com.layoutmanager.ui.settings; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; @@ -8,7 +8,7 @@ import javax.swing.*; import java.awt.*; -public class settings implements Configurable { +public class SettingsPage implements Configurable { @Nls(capitalization = Nls.Capitalization.Title) @Override public String getDisplayName() { diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 73c8148..916a5ee 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -36,10 +36,10 @@ - + - + From 5847bacd5f7db668ef3edc2207e194d87dd154ed Mon Sep 17 00:00:00 2001 From: Michael Estermann Date: Sat, 21 Dec 2019 22:23:32 +0100 Subject: [PATCH 03/19] Introduced checkstyle and fixed issues. --- build.gradle | 14 + config/checkstyle/checkstyle.xml | 257 ++++++++++++++++++ .../cleanup/EmptyLayoutRemoverService.java | 2 +- .../layout/delete/DeleteLayoutAction.java | 10 +- .../layout/restore/RestoreLayoutAction.java | 11 +- .../layout/store/LayoutCreator.java | 12 +- .../layout/store/create/NewLayoutAction.java | 10 +- .../overwrite/OverwriteLayoutAction.java | 14 +- .../layout/store/smartdock/SmartDocker.java | 12 +- .../store/smartdock/ToolWindowDocking.java | 40 +-- .../smartdock/dockers/ScreenBorderDocker.java | 80 +++--- .../smartdock/dockers/ToolWindowDocker.java | 15 +- .../dockers/ToolWindowToScreenShrinker.java | 2 +- .../validation/LayoutValidationHelper.java | 4 +- .../localization/MessagesHelper.java | 8 +- .../com/layoutmanager/persistence/Layout.java | 11 +- .../persistence/LayoutConfig.java | 6 +- .../persistence/ToolWindowInfo.java | 4 +- .../ui/helpers/NotificationHelper.java | 2 +- .../ui/helpers/ScreenSizeHelper.java | 13 +- .../ui/helpers/ToolWindowHelper.java | 9 +- .../ui/menu/WindowMenuService.java | 25 +- .../ui/settings/SettingsPage.java | 13 +- 23 files changed, 432 insertions(+), 142 deletions(-) create mode 100644 config/checkstyle/checkstyle.xml diff --git a/build.gradle b/build.gradle index 09bb3e2..3fe1e6f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,7 @@ plugins { id 'java' id 'org.jetbrains.intellij' version '0.4.15' + id 'checkstyle' } group 'com.layoutmanager' @@ -10,6 +11,11 @@ sourceCompatibility = 1.8 buildSearchableOptions.enabled = false +repositories { + mavenLocal() + mavenCentral() +} + intellij { type = 'RD' version = "2020.1-SNAPSHOT" @@ -23,4 +29,12 @@ publishPlugin { wrapper { gradleVersion = '6.0.1' distributionUrl = "https://cache-redirector.jetbrains.com/services.gradle.org/distributions/gradle-${gradleVersion}-all.zip" +} + +checkstyle { + project.ext.checkstyleVersion = '8.27' +} + +checkstyleMain { + source ='src/main/java' } \ No newline at end of file diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 0000000..0dec546 --- /dev/null +++ b/config/checkstyle/checkstyle.xml @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/layoutmanager/cleanup/EmptyLayoutRemoverService.java b/src/main/java/com/layoutmanager/cleanup/EmptyLayoutRemoverService.java index 7f1d62f..e607fc7 100644 --- a/src/main/java/com/layoutmanager/cleanup/EmptyLayoutRemoverService.java +++ b/src/main/java/com/layoutmanager/cleanup/EmptyLayoutRemoverService.java @@ -9,7 +9,7 @@ public void execute() { LayoutConfig layoutConfig = ServiceManager.getService(LayoutConfig.class); for (Layout layout : layoutConfig.getLayouts()) { - if (isEmpty(layout)) { + if (this.isEmpty(layout)) { layoutConfig.removeLayout(layout); } } diff --git a/src/main/java/com/layoutmanager/layout/delete/DeleteLayoutAction.java b/src/main/java/com/layoutmanager/layout/delete/DeleteLayoutAction.java index d69ea6c..bd708a9 100644 --- a/src/main/java/com/layoutmanager/layout/delete/DeleteLayoutAction.java +++ b/src/main/java/com/layoutmanager/layout/delete/DeleteLayoutAction.java @@ -5,11 +5,13 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.components.ServiceManager; + import com.layoutmanager.localization.MessagesHelper; -import com.layoutmanager.ui.menu.WindowMenuService; import com.layoutmanager.persistence.Layout; import com.layoutmanager.persistence.LayoutConfig; import com.layoutmanager.ui.helpers.NotificationHelper; +import com.layoutmanager.ui.menu.WindowMenuService; + import org.jetbrains.annotations.NotNull; public class DeleteLayoutAction extends AnAction { @@ -25,9 +27,9 @@ public DeleteLayoutAction(Layout layout) { @Override public void actionPerformed(@NotNull AnActionEvent event) { - deleteLayout(); - updateWindowMenuItems(); - showNotification(); + this.deleteLayout(); + this.updateWindowMenuItems(); + this.showNotification(); } private void deleteLayout() { diff --git a/src/main/java/com/layoutmanager/layout/restore/RestoreLayoutAction.java b/src/main/java/com/layoutmanager/layout/restore/RestoreLayoutAction.java index aa8e7c9..f6a1c39 100644 --- a/src/main/java/com/layoutmanager/layout/restore/RestoreLayoutAction.java +++ b/src/main/java/com/layoutmanager/layout/restore/RestoreLayoutAction.java @@ -38,15 +38,15 @@ public void update(AnActionEvent e) { @Override public void actionPerformed(@NotNull AnActionEvent event) { - applyLayout(event, this.layout); - showNotification(this.layout); + this.applyLayout(event, this.layout); + this.showNotification(this.layout); } private void applyLayout(AnActionEvent event, Layout layout) { - applyEditorTabPlacement(layout); - ToolWindowManager toolWindowManager = getToolWindowManager(event); + this.applyEditorTabPlacement(layout); + ToolWindowManager toolWindowManager = this.getToolWindowManager(event); for (ToolWindowInfo toolWindow : layout.getToolWindows()) { - applyToolWindowLayout(toolWindowManager, toolWindow); + this.applyToolWindowLayout(toolWindowManager, toolWindow); } } @@ -81,6 +81,7 @@ private ToolWindowManager getToolWindowManager(AnActionEvent event) { Project project = event.getProject(); return ToolWindowManager.getInstance(project); } + private void showNotification(Layout updatedLayout) { NotificationHelper.info( MessagesHelper.message("RestoreLayout.Notification.Title"), diff --git a/src/main/java/com/layoutmanager/layout/store/LayoutCreator.java b/src/main/java/com/layoutmanager/layout/store/LayoutCreator.java index faa0794..350475a 100644 --- a/src/main/java/com/layoutmanager/layout/store/LayoutCreator.java +++ b/src/main/java/com/layoutmanager/layout/store/LayoutCreator.java @@ -5,6 +5,7 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.openapi.wm.impl.ToolWindowImpl; + import com.layoutmanager.layout.store.smartdock.SmartDocker; import com.layoutmanager.layout.store.smartdock.SmartDockerFactory; import com.layoutmanager.layout.store.validation.LayoutValidationHelper; @@ -13,12 +14,13 @@ import com.layoutmanager.persistence.ToolWindowInfo; import com.layoutmanager.ui.helpers.NotificationHelper; import com.layoutmanager.ui.helpers.ToolWindowHelper; -import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; +import org.jetbrains.annotations.NotNull; + public class LayoutCreator { private final SmartDockerFactory smartDockerFactory; @@ -29,9 +31,9 @@ public LayoutCreator(SmartDockerFactory smartDockerFactory) { public Layout create(ToolWindowManager toolWindowManager, String defaultName) { - String name = getLayoutName(defaultName); + String name = this.getLayoutName(defaultName); return name != null ? - createLayout(toolWindowManager, name) : + this.createLayout(toolWindowManager, name) : null; } @@ -56,7 +58,7 @@ private Layout createLayout(ToolWindowManager toolWindowManager, String name) { toolWindows.toArray(ToolWindowInfo[]::new), getEditorPlacement()); - dock(toolWindowManager, layout); + this.dock(toolWindowManager, layout); validateLayout(layout); return layout; @@ -83,7 +85,7 @@ private static List getToolWindows(ToolWindowManager toolWindowM } private void dock(ToolWindowManager toolWindowManager, Layout layout) { - SmartDocker smartDocker = smartDockerFactory.create(toolWindowManager); + SmartDocker smartDocker = this.smartDockerFactory.create(toolWindowManager); smartDocker.dock(layout); } diff --git a/src/main/java/com/layoutmanager/layout/store/create/NewLayoutAction.java b/src/main/java/com/layoutmanager/layout/store/create/NewLayoutAction.java index 7acb182..2e8d3b0 100644 --- a/src/main/java/com/layoutmanager/layout/store/create/NewLayoutAction.java +++ b/src/main/java/com/layoutmanager/layout/store/create/NewLayoutAction.java @@ -6,12 +6,14 @@ import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.wm.ToolWindowManager; + import com.layoutmanager.layout.store.LayoutCreator; import com.layoutmanager.localization.MessagesHelper; -import com.layoutmanager.ui.menu.WindowMenuService; import com.layoutmanager.persistence.Layout; import com.layoutmanager.persistence.LayoutConfig; import com.layoutmanager.ui.helpers.NotificationHelper; +import com.layoutmanager.ui.menu.WindowMenuService; + import org.jetbrains.annotations.NotNull; public class NewLayoutAction extends AnAction { @@ -28,12 +30,12 @@ public NewLayoutAction(LayoutCreator layoutCreator) { @Override public void actionPerformed(@NotNull AnActionEvent event) { ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(event.getProject()); - Layout updatedLayout = layoutCreator.create(toolWindowManager, ""); + Layout updatedLayout = this.layoutCreator.create(toolWindowManager, ""); if (updatedLayout != null) { this.storeLayout(updatedLayout); - updateWindowMenuItems(); - showNotification(updatedLayout); + this.updateWindowMenuItems(); + this.showNotification(updatedLayout); } } diff --git a/src/main/java/com/layoutmanager/layout/store/overwrite/OverwriteLayoutAction.java b/src/main/java/com/layoutmanager/layout/store/overwrite/OverwriteLayoutAction.java index 7b868fe..8502b42 100644 --- a/src/main/java/com/layoutmanager/layout/store/overwrite/OverwriteLayoutAction.java +++ b/src/main/java/com/layoutmanager/layout/store/overwrite/OverwriteLayoutAction.java @@ -6,12 +6,14 @@ import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.wm.ToolWindowManager; + import com.layoutmanager.layout.store.LayoutCreator; import com.layoutmanager.localization.MessagesHelper; -import com.layoutmanager.ui.menu.WindowMenuService; import com.layoutmanager.persistence.Layout; import com.layoutmanager.persistence.LayoutConfig; import com.layoutmanager.ui.helpers.NotificationHelper; +import com.layoutmanager.ui.menu.WindowMenuService; + import org.jetbrains.annotations.NotNull; public class OverwriteLayoutAction extends AnAction { @@ -33,21 +35,21 @@ public OverwriteLayoutAction( @Override public void update(AnActionEvent e) { - Layout layout = LayoutConfig.getInstance().getLayout(number); + Layout layout = LayoutConfig.getInstance().getLayout(this.number); e.getPresentation().setText(layout.getName()); super.update(e); } @Override public void actionPerformed(@NotNull AnActionEvent event) { - Layout previousLayout = LayoutConfig.getInstance().getLayout(number); + Layout previousLayout = LayoutConfig.getInstance().getLayout(this.number); ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(event.getProject()); - Layout updatedLayout = layoutCreator.create(toolWindowManager, previousLayout.getName()); + Layout updatedLayout = this.layoutCreator.create(toolWindowManager, previousLayout.getName()); if (updatedLayout != null) { this.storeLayout(updatedLayout); - updateWindowMenuItems(); - showNotification(updatedLayout, previousLayout); + this.updateWindowMenuItems(); + this.showNotification(updatedLayout, previousLayout); } } diff --git a/src/main/java/com/layoutmanager/layout/store/smartdock/SmartDocker.java b/src/main/java/com/layoutmanager/layout/store/smartdock/SmartDocker.java index 9c02b6f..7f34382 100644 --- a/src/main/java/com/layoutmanager/layout/store/smartdock/SmartDocker.java +++ b/src/main/java/com/layoutmanager/layout/store/smartdock/SmartDocker.java @@ -32,11 +32,11 @@ public SmartDocker( } public void dock(Layout layout) { - ToolWindowDocking[] floatedOrWindowsToolWindows = getFloatedOrWindowsToolWindows(layout); + ToolWindowDocking[] floatedOrWindowsToolWindows = this.getFloatedOrWindowsToolWindows(layout); - shrinker.shrink(floatedOrWindowsToolWindows); - toolWindowDocker.dock(floatedOrWindowsToolWindows); - screenBorderDocker.dock(floatedOrWindowsToolWindows, THRESHOLD); + this.shrinker.shrink(floatedOrWindowsToolWindows); + this.toolWindowDocker.dock(floatedOrWindowsToolWindows); + this.screenBorderDocker.dock(floatedOrWindowsToolWindows, THRESHOLD); } @@ -45,14 +45,14 @@ private ToolWindowDocking[] getFloatedOrWindowsToolWindows(Layout layout) { .filter(this::isFloatingOrWindowedToolWindow) .map(x -> new ToolWindowDocking( x, - (ToolWindowImpl)toolWindowManager.getToolWindow(x.getId()), + (ToolWindowImpl)this.toolWindowManager.getToolWindow(x.getId()), ScreenSizeHelper.getContainingScreenBounds(x), THRESHOLD)) .toArray(ToolWindowDocking[]::new); } private boolean isFloatingOrWindowedToolWindow(ToolWindowInfo toolWindow) { - return toolWindowManager.getToolWindow(toolWindow.getId()) != null && + return this.toolWindowManager.getToolWindow(toolWindow.getId()) != null && toolWindow.getType() == ToolWindowType.FLOATING || toolWindow.getType() == ToolWindowType.WINDOWED; } diff --git a/src/main/java/com/layoutmanager/layout/store/smartdock/ToolWindowDocking.java b/src/main/java/com/layoutmanager/layout/store/smartdock/ToolWindowDocking.java index 62f2122..428f0fc 100644 --- a/src/main/java/com/layoutmanager/layout/store/smartdock/ToolWindowDocking.java +++ b/src/main/java/com/layoutmanager/layout/store/smartdock/ToolWindowDocking.java @@ -3,7 +3,7 @@ import com.intellij.openapi.wm.impl.ToolWindowImpl; import com.layoutmanager.persistence.ToolWindowInfo; -import java.awt.*; +import java.awt.Rectangle; public class ToolWindowDocking { @@ -28,46 +28,46 @@ public ToolWindowInfo getToolWindowInfo() { } public ToolWindowImpl getToolWindow() { - return toolWindow; + return this.toolWindow; } public Rectangle getContainingScreen() { - return containingScreen; + return this.containingScreen; } public Rectangle getBounds() { - return toolWindowInfo.getBounds(); + return this.toolWindowInfo.getBounds(); } public Rectangle getLeftDockingBounds() { return new Rectangle( - (int) Math.max(0, toolWindowInfo.getBounds().getX() - threshold), - (int) toolWindowInfo.getBounds().getY(), - threshold * 2, - (int) toolWindowInfo.getBounds().getHeight()); + (int) Math.max(0, this.toolWindowInfo.getBounds().getX() - threshold), + (int) this.toolWindowInfo.getBounds().getY(), + this.threshold * 2, + (int) this.toolWindowInfo.getBounds().getHeight()); } public Rectangle getTopDockingBounds() { return new Rectangle( - (int) toolWindowInfo.getBounds().getX(), - (int) Math.max(0, toolWindowInfo.getBounds().getY() - threshold), - (int) toolWindowInfo.getBounds().getWidth(), - threshold * 2); + (int) this.toolWindowInfo.getBounds().getX(), + (int) Math.max(0, this.toolWindowInfo.getBounds().getY() - threshold), + (int) this.toolWindowInfo.getBounds().getWidth(), + this.threshold * 2); } public Rectangle getRightDockingBounds() { return new Rectangle( - (int) (toolWindowInfo.getBounds().getMaxX() - threshold), - (int) toolWindowInfo.getBounds().getY(), - (int) Math.min(threshold * 2, threshold + containingScreen.getMaxX() - toolWindowInfo.getBounds().getMaxX()), - (int) toolWindowInfo.getBounds().getHeight()); + (int) (this.toolWindowInfo.getBounds().getMaxX() - threshold), + (int) this.toolWindowInfo.getBounds().getY(), + (int) Math.min(this.threshold * 2, this.threshold + this.containingScreen.getMaxX() - this.toolWindowInfo.getBounds().getMaxX()), + (int) this.toolWindowInfo.getBounds().getHeight()); } public Rectangle getBottomDockingBounds() { return new Rectangle( - (int) toolWindowInfo.getBounds().getX(), - (int) toolWindowInfo.getBounds().getMaxY() - threshold, - (int) toolWindowInfo.getBounds().getWidth(), - (int) Math.min(threshold * 2, threshold + containingScreen.getMaxY() - toolWindowInfo.getBounds().getMaxY())); + (int) this.toolWindowInfo.getBounds().getX(), + (int) this.toolWindowInfo.getBounds().getMaxY() - threshold, + (int) this.toolWindowInfo.getBounds().getWidth(), + (int) Math.min(this.threshold * 2, this.threshold + this.containingScreen.getMaxY() - this.toolWindowInfo.getBounds().getMaxY())); } } diff --git a/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ScreenBorderDocker.java b/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ScreenBorderDocker.java index 60ad0e7..8cad370 100644 --- a/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ScreenBorderDocker.java +++ b/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ScreenBorderDocker.java @@ -2,68 +2,64 @@ import com.layoutmanager.layout.store.smartdock.ToolWindowDocking; -import java.awt.*; +import java.awt.Rectangle; import java.util.function.BiFunction; import java.util.function.Function; public class ScreenBorderDocker { public void dock(ToolWindowDocking[] floatedOrWindowsToolWindows, int threshold) { - pinLeft(floatedOrWindowsToolWindows, threshold); - pinTop(floatedOrWindowsToolWindows, threshold); - pinRight(floatedOrWindowsToolWindows, threshold); - pinBottom(floatedOrWindowsToolWindows, threshold); + this.pinLeft(floatedOrWindowsToolWindows, threshold); + this.pinTop(floatedOrWindowsToolWindows, threshold); + this.pinRight(floatedOrWindowsToolWindows, threshold); + this.pinBottom(floatedOrWindowsToolWindows, threshold); } private void pinLeft(ToolWindowDocking[] floatedOrWindowsToolWindows, int threshold) { - pinToScreenBorder( - floatedOrWindowsToolWindows, - threshold, - toolWindowDocking -> (int)(toolWindowDocking.getBounds().getX() - toolWindowDocking.getContainingScreen().getX()), - (toolWindowDocking, difference) -> new Rectangle( - (int)toolWindowDocking.getContainingScreen().getX(), - (int)toolWindowDocking.getBounds().getY(), - (int)(toolWindowDocking.getBounds().getWidth()+ difference), - (int)toolWindowDocking.getBounds().getHeight()) - ); + this.pinToScreenBorder( + floatedOrWindowsToolWindows, + threshold, + toolWindowDocking -> (int)(toolWindowDocking.getBounds().getX() - toolWindowDocking.getContainingScreen().getX()), + (toolWindowDocking, difference) -> new Rectangle( + (int)toolWindowDocking.getContainingScreen().getX(), + (int)toolWindowDocking.getBounds().getY(), + (int)(toolWindowDocking.getBounds().getWidth() + difference), + (int)toolWindowDocking.getBounds().getHeight())); } private void pinTop(ToolWindowDocking[] floatedOrWindowsToolWindows, int threshold) { - pinToScreenBorder( - floatedOrWindowsToolWindows, - threshold, - x -> (int)(x.getBounds().getY() - x.getContainingScreen().getY()), - (toolWindowDocking, difference) -> new Rectangle( - (int)toolWindowDocking.getBounds().getX(), - (int)toolWindowDocking.getContainingScreen().getY(), - (int)toolWindowDocking.getBounds().getWidth(), - (int)(toolWindowDocking.getBounds().getHeight() + 5) - )); + this.pinToScreenBorder( + floatedOrWindowsToolWindows, + threshold, + x -> (int)(x.getBounds().getY() - x.getContainingScreen().getY()), + (toolWindowDocking, difference) -> new Rectangle( + (int)toolWindowDocking.getBounds().getX(), + (int)toolWindowDocking.getContainingScreen().getY(), + (int)toolWindowDocking.getBounds().getWidth(), + (int)(toolWindowDocking.getBounds().getHeight() + 5))); } private void pinRight(ToolWindowDocking[] floatedOrWindowsToolWindows, int threshold) { - pinToScreenBorder( - floatedOrWindowsToolWindows, - threshold, - toolWindowDocking -> (int)(toolWindowDocking.getContainingScreen().getMaxX() - toolWindowDocking.getBounds().getMaxX()), - (toolWindowDocking, difference) -> new Rectangle( - (int)toolWindowDocking.getBounds().getX(), - (int)toolWindowDocking.getBounds().getY(), - (int)(toolWindowDocking.getBounds().getWidth() + difference), - (int)toolWindowDocking.getBounds().getHeight()) - ); + this.pinToScreenBorder( + floatedOrWindowsToolWindows, + threshold, + toolWindowDocking -> (int)(toolWindowDocking.getContainingScreen().getMaxX() - toolWindowDocking.getBounds().getMaxX()), + (toolWindowDocking, difference) -> new Rectangle( + (int)toolWindowDocking.getBounds().getX(), + (int)toolWindowDocking.getBounds().getY(), + (int)(toolWindowDocking.getBounds().getWidth() + difference), + (int)toolWindowDocking.getBounds().getHeight())); } private void pinBottom(ToolWindowDocking[] floatedOrWindowsToolWindows, int threshold) { - pinToScreenBorder( - floatedOrWindowsToolWindows, - threshold, - toolWindowDocking -> (int)(toolWindowDocking.getBounds().getY() - toolWindowDocking.getContainingScreen().getY()), - (toolWindowDocking, difference) -> new Rectangle( + this.pinToScreenBorder( + floatedOrWindowsToolWindows, + threshold, + toolWindowDocking -> (int)(toolWindowDocking.getBounds().getY() - toolWindowDocking.getContainingScreen().getY()), + (toolWindowDocking, difference) -> new Rectangle( (int)toolWindowDocking.getBounds().getX(), (int)toolWindowDocking.getBounds().getY(), (int)toolWindowDocking.getBounds().getWidth(), - (int)(toolWindowDocking.getBounds().getHeight() + difference)) - ); + (int)(toolWindowDocking.getBounds().getHeight() + difference))); } private void pinToScreenBorder( diff --git a/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowDocker.java b/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowDocker.java index c2ba892..432be3f 100644 --- a/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowDocker.java +++ b/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowDocker.java @@ -2,15 +2,16 @@ import com.layoutmanager.layout.store.smartdock.ToolWindowDocking; -import java.awt.*; +import java.awt.Rectangle; import java.util.Arrays; import java.util.Comparator; public class ToolWindowDocker { public void dock(ToolWindowDocking[] floatedOrWindowsToolWindows) { - dockLeft(floatedOrWindowsToolWindows); - dockTop(floatedOrWindowsToolWindows); + this.dockLeft(floatedOrWindowsToolWindows); + this.dockTop(floatedOrWindowsToolWindows); // TODO: Add bottom and left in a more generic way... + // Idea: Introduce class DockingBounds and use this in the ToolWindowDocking } private void dockLeft(ToolWindowDocking[] floatedOrWindowsToolWindows) { @@ -21,7 +22,9 @@ private void dockLeft(ToolWindowDocking[] floatedOrWindowsToolWindows) { for (ToolWindowDocking toolWindowDocking : sortedByLeftPosition) { ToolWindowDocking[] intersectionToolWindows = Arrays.stream(floatedOrWindowsToolWindows) - .filter(x -> x.getToolWindowInfo().getId() != toolWindowDocking.getToolWindowInfo().getId() && x.getRightDockingBounds().intersects(toolWindowDocking.getLeftDockingBounds())) + .filter(x -> + !x.getToolWindowInfo().getId().equals(toolWindowDocking.getToolWindowInfo().getId()) && + x.getRightDockingBounds().intersects(toolWindowDocking.getLeftDockingBounds())) .sorted(Comparator.comparingInt(x -> (int) x.getBounds().getY())) .toArray(ToolWindowDocking[]::new); @@ -46,7 +49,9 @@ private void dockTop(ToolWindowDocking[] floatedOrWindowsToolWindows) { for (ToolWindowDocking toolWindowDocking : sortedByTopPosition) { ToolWindowDocking[] intersectionToolWindows = Arrays.stream(floatedOrWindowsToolWindows) - .filter(x -> x.getToolWindowInfo().getId() != toolWindowDocking.getToolWindowInfo().getId() && x.getBottomDockingBounds().intersects(toolWindowDocking.getTopDockingBounds())) + .filter(x -> + !x.getToolWindowInfo().getId().equals(toolWindowDocking.getToolWindowInfo().getId()) && + x.getBottomDockingBounds().intersects(toolWindowDocking.getTopDockingBounds())) .sorted(Comparator.comparingInt(x -> (int) x.getBounds().getX())) .toArray(ToolWindowDocking[]::new); diff --git a/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowToScreenShrinker.java b/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowToScreenShrinker.java index fa23787..7a490f5 100644 --- a/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowToScreenShrinker.java +++ b/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowToScreenShrinker.java @@ -2,7 +2,7 @@ import com.layoutmanager.layout.store.smartdock.ToolWindowDocking; -import java.awt.*; +import java.awt.Rectangle; public class ToolWindowToScreenShrinker { public void shrink(ToolWindowDocking[] floatedOrWindowsToolWindowDockings) { diff --git a/src/main/java/com/layoutmanager/layout/store/validation/LayoutValidationHelper.java b/src/main/java/com/layoutmanager/layout/store/validation/LayoutValidationHelper.java index 11dc049..4e0e658 100644 --- a/src/main/java/com/layoutmanager/layout/store/validation/LayoutValidationHelper.java +++ b/src/main/java/com/layoutmanager/layout/store/validation/LayoutValidationHelper.java @@ -5,11 +5,11 @@ import com.layoutmanager.persistence.Layout; import com.layoutmanager.persistence.ToolWindowInfo; -import java.awt.*; +import java.awt.Rectangle; import java.util.stream.Stream; public class LayoutValidationHelper { - public static ToolWindowInfo[] retrieveToolWindowsOutsideOfScreen(Layout layout){ + public static ToolWindowInfo[] retrieveToolWindowsOutsideOfScreen(Layout layout) { return Stream .of(layout.getToolWindows()) .filter(x -> x.isVisible() && isWindowType(x) && !isValid(x)) diff --git a/src/main/java/com/layoutmanager/localization/MessagesHelper.java b/src/main/java/com/layoutmanager/localization/MessagesHelper.java index 46d402c..c7f9412 100644 --- a/src/main/java/com/layoutmanager/localization/MessagesHelper.java +++ b/src/main/java/com/layoutmanager/localization/MessagesHelper.java @@ -1,17 +1,17 @@ package com.layoutmanager.localization; - import com.intellij.CommonBundle; import com.intellij.reference.SoftReference; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.PropertyKey; import java.lang.ref.Reference; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.PropertyKey; + public class MessagesHelper { @NonNls public static final String BUNDLE_NAME = "com.layoutmanager.ui.messages"; diff --git a/src/main/java/com/layoutmanager/persistence/Layout.java b/src/main/java/com/layoutmanager/persistence/Layout.java index c2d716d..fc031b1 100644 --- a/src/main/java/com/layoutmanager/persistence/Layout.java +++ b/src/main/java/com/layoutmanager/persistence/Layout.java @@ -6,10 +6,11 @@ public class Layout { private int editorTabPlacement; private ToolWindowInfo[] toolWindows; + @SuppressWarnings({"unused", "Used for serialization."}) public Layout() { - name = ""; - toolWindows = new ToolWindowInfo[0]; - editorTabPlacement = -1; + this.name = ""; + this.toolWindows = new ToolWindowInfo[0]; + this.editorTabPlacement = -1; } public Layout(String name, ToolWindowInfo[] toolWindows, int editorTabPlacement) { @@ -28,7 +29,7 @@ public void setName(String name) { } public int getEditorPlacement() { - return editorTabPlacement; + return this.editorTabPlacement; } @SuppressWarnings({"unused", "Used for serialization."}) @@ -37,7 +38,7 @@ public void setEditorPlacement(int editorTabPlacement) { } public ToolWindowInfo[] getToolWindows() { - return toolWindows; + return this.toolWindows; } @SuppressWarnings({"unused", "Used for serialization."}) diff --git a/src/main/java/com/layoutmanager/persistence/LayoutConfig.java b/src/main/java/com/layoutmanager/persistence/LayoutConfig.java index f0c993c..dc9831b 100644 --- a/src/main/java/com/layoutmanager/persistence/LayoutConfig.java +++ b/src/main/java/com/layoutmanager/persistence/LayoutConfig.java @@ -6,13 +6,13 @@ import com.intellij.openapi.components.Storage; import com.intellij.util.xmlb.XmlSerializerUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + @State( name = "Layout", storages = { diff --git a/src/main/java/com/layoutmanager/persistence/ToolWindowInfo.java b/src/main/java/com/layoutmanager/persistence/ToolWindowInfo.java index cc2eec5..8f04ef7 100644 --- a/src/main/java/com/layoutmanager/persistence/ToolWindowInfo.java +++ b/src/main/java/com/layoutmanager/persistence/ToolWindowInfo.java @@ -2,7 +2,7 @@ import com.intellij.openapi.wm.ToolWindowType; -import java.awt.*; +import java.awt.Rectangle; public class ToolWindowInfo { private String id; @@ -87,7 +87,7 @@ public void setVisible(boolean visible) { } @SuppressWarnings({"unused", "Used for serialization."}) - public void setIsToolWindow(boolean isSplit) { + public void setIsToolWindow(boolean isToolWindow) { this.isToolWindow = isToolWindow; } } diff --git a/src/main/java/com/layoutmanager/ui/helpers/NotificationHelper.java b/src/main/java/com/layoutmanager/ui/helpers/NotificationHelper.java index aeecc74..f82743c 100644 --- a/src/main/java/com/layoutmanager/ui/helpers/NotificationHelper.java +++ b/src/main/java/com/layoutmanager/ui/helpers/NotificationHelper.java @@ -3,8 +3,8 @@ import com.intellij.notification.Notification; import com.intellij.notification.NotificationDisplayType; import com.intellij.notification.NotificationGroup; -import com.intellij.notification.Notifications; import com.intellij.notification.NotificationType; +import com.intellij.notification.Notifications; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; diff --git a/src/main/java/com/layoutmanager/ui/helpers/ScreenSizeHelper.java b/src/main/java/com/layoutmanager/ui/helpers/ScreenSizeHelper.java index 89f999a..8524fc2 100644 --- a/src/main/java/com/layoutmanager/ui/helpers/ScreenSizeHelper.java +++ b/src/main/java/com/layoutmanager/ui/helpers/ScreenSizeHelper.java @@ -1,19 +1,22 @@ package com.layoutmanager.ui.helpers; import com.layoutmanager.persistence.ToolWindowInfo; -import sun.java2d.SunGraphicsEnvironment; -import java.awt.*; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Rectangle; + import java.util.Arrays; import java.util.Comparator; +import sun.java2d.SunGraphicsEnvironment; + public class ScreenSizeHelper { public static Rectangle getContainingScreenBounds(ToolWindowInfo toolWindow) { return Arrays .stream(GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()) - .map(x -> getScreenRectangle(x)) - .sorted(Comparator.comparingInt(x -> 0 - getIntersectionSize(x, toolWindow.getBounds()))) - .findFirst() + .map(ScreenSizeHelper::getScreenRectangle) + .min(Comparator.comparingInt(x -> -getIntersectionSize(x, toolWindow.getBounds()))) .orElse(new Rectangle()); } diff --git a/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java b/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java index 5d36e1f..1e86917 100644 --- a/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java +++ b/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java @@ -5,10 +5,13 @@ import com.intellij.openapi.wm.impl.InternalDecorator; import com.intellij.openapi.wm.impl.ToolWindowImpl; import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.Nullable; -import javax.swing.*; -import java.awt.*; +import java.awt.Rectangle; +import java.awt.Window; +import javax.swing.JComponent; +import javax.swing.SwingUtilities; + +import org.jetbrains.annotations.Nullable; public class ToolWindowHelper { public static Rectangle getBounds(ToolWindowImpl toolWindow) { diff --git a/src/main/java/com/layoutmanager/ui/menu/WindowMenuService.java b/src/main/java/com/layoutmanager/ui/menu/WindowMenuService.java index c633604..aa4ea27 100644 --- a/src/main/java/com/layoutmanager/ui/menu/WindowMenuService.java +++ b/src/main/java/com/layoutmanager/ui/menu/WindowMenuService.java @@ -2,11 +2,12 @@ import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.DefaultActionGroup; + import com.layoutmanager.layout.delete.DeleteLayoutAction; +import com.layoutmanager.layout.restore.RestoreLayoutAction; import com.layoutmanager.layout.store.LayoutCreator; import com.layoutmanager.layout.store.create.NewLayoutAction; import com.layoutmanager.layout.store.overwrite.OverwriteLayoutAction; -import com.layoutmanager.layout.restore.RestoreLayoutAction; import com.layoutmanager.layout.store.smartdock.SmartDockerFactory; import com.layoutmanager.localization.MessagesHelper; import com.layoutmanager.persistence.Layout; @@ -18,12 +19,12 @@ public class WindowMenuService { private DefaultActionGroup deleteLayout; public void create() { - if (storeLayout != null) { + if (this.storeLayout != null) { throw new IllegalStateException("Menu items already created"); } - createMainActions( (DefaultActionGroup) ActionManager.getInstance().getAction("WindowMenu")); - createStoreRestoreActions(); + this.createMainActions((DefaultActionGroup) ActionManager.getInstance().getAction("WindowMenu")); + this.createStoreRestoreActions(); } public void recreate() { @@ -31,16 +32,16 @@ public void recreate() { this.storeLayout.removeAll(); this.deleteLayout.removeAll(); - createStoreRestoreActions(); + this.createStoreRestoreActions(); } private void createMainActions(DefaultActionGroup windowMenu) { - this.storeLayout = createMainAction(MessagesHelper.message("StoreLayout.Menu"), windowMenu); - this.restoreLayout = createMainAction(MessagesHelper.message("RestoreLayout.Menu"), windowMenu); - this.deleteLayout = createMainAction(MessagesHelper.message("DeleteLayout.Menu"), windowMenu); + this.storeLayout = this.createMainAction(MessagesHelper.message("StoreLayout.Menu"), windowMenu); + this.restoreLayout = this.createMainAction(MessagesHelper.message("RestoreLayout.Menu"), windowMenu); + this.deleteLayout = this.createMainAction(MessagesHelper.message("DeleteLayout.Menu"), windowMenu); } - private DefaultActionGroup createMainAction(String name, DefaultActionGroup windowMenu){ + private DefaultActionGroup createMainAction(String name, DefaultActionGroup windowMenu) { DefaultActionGroup windowMenuItem = new DefaultActionGroup(name, true); windowMenu.add(windowMenuItem); @@ -49,9 +50,9 @@ private DefaultActionGroup createMainAction(String name, DefaultActionGroup wind private void createStoreRestoreActions() { LayoutConfig config = LayoutConfig.getInstance(); - addStoreLayoutActions(config); - addRestoreLayoutActions(config); - addDeleteLayoutActions(config); + this.addStoreLayoutActions(config); + this.addRestoreLayoutActions(config); + this.addDeleteLayoutActions(config); } private void addStoreLayoutActions(LayoutConfig config) { diff --git a/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java b/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java index f21220b..84cfe81 100644 --- a/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java +++ b/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java @@ -1,13 +1,14 @@ package com.layoutmanager.ui.settings; import com.intellij.openapi.options.Configurable; -import com.intellij.openapi.options.ConfigurationException; +import com.intellij.ui.JBColor; + +import javax.swing.JComponent; +import javax.swing.JPanel; + import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.Nullable; -import javax.swing.*; -import java.awt.*; - public class SettingsPage implements Configurable { @Nls(capitalization = Nls.Capitalization.Title) @Override @@ -19,7 +20,7 @@ public String getDisplayName() { @Override public JComponent createComponent() { JPanel panel = new JPanel(); - panel.setBackground(Color.red); + panel.setBackground(JBColor.red); return panel; } @@ -29,7 +30,7 @@ public boolean isModified() { } @Override - public void apply() throws ConfigurationException { + public void apply() { } From 0bbb2bb17e073bcce56effb443827a2bb558cb35 Mon Sep 17 00:00:00 2001 From: Michael Estermann Date: Sat, 21 Dec 2019 23:24:30 +0100 Subject: [PATCH 04/19] Tool window docking extended. --- .../smartdock/dockers/ToolWindowDocker.java | 119 +++++++++++------- 1 file changed, 77 insertions(+), 42 deletions(-) diff --git a/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowDocker.java b/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowDocker.java index 432be3f..1f4c035 100644 --- a/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowDocker.java +++ b/src/main/java/com/layoutmanager/layout/store/smartdock/dockers/ToolWindowDocker.java @@ -5,64 +5,99 @@ import java.awt.Rectangle; import java.util.Arrays; import java.util.Comparator; +import java.util.function.BiFunction; +import java.util.function.BiPredicate; public class ToolWindowDocker { public void dock(ToolWindowDocking[] floatedOrWindowsToolWindows) { this.dockLeft(floatedOrWindowsToolWindows); this.dockTop(floatedOrWindowsToolWindows); - // TODO: Add bottom and left in a more generic way... - // Idea: Introduce class DockingBounds and use this in the ToolWindowDocking + this.dockRight(floatedOrWindowsToolWindows); + this.dockBottom(floatedOrWindowsToolWindows); } private void dockLeft(ToolWindowDocking[] floatedOrWindowsToolWindows) { - ToolWindowDocking[] sortedByLeftPosition = Arrays.stream(floatedOrWindowsToolWindows) - .sorted((x, y) -> (int) (x.getBounds().getX() - y.getBounds().getX())) - .skip(1) - .toArray(ToolWindowDocking[]::new); + this.dockToolWindow( + floatedOrWindowsToolWindows, + (x, y) -> (int) (x.getBounds().getX() - y.getBounds().getX()), + (x, y) -> x.getRightDockingBounds().intersects(y.getLeftDockingBounds()), + Comparator.comparingInt(x -> (int) x.getBounds().getY()), + (toolWindow, boundsToDock) -> { + int x = (int) toolWindow.getBounds().getX(); + int newX = (int) boundsToDock.getMaxX(); + return new Rectangle( + newX, + (int) toolWindow.getBounds().getY(), + (int) (toolWindow.getBounds().getWidth() + (x - newX)), + (int) toolWindow.getBounds().getHeight()); + }); + } - for (ToolWindowDocking toolWindowDocking : sortedByLeftPosition) { - ToolWindowDocking[] intersectionToolWindows = Arrays.stream(floatedOrWindowsToolWindows) - .filter(x -> - !x.getToolWindowInfo().getId().equals(toolWindowDocking.getToolWindowInfo().getId()) && - x.getRightDockingBounds().intersects(toolWindowDocking.getLeftDockingBounds())) - .sorted(Comparator.comparingInt(x -> (int) x.getBounds().getY())) - .toArray(ToolWindowDocking[]::new); + private void dockTop(ToolWindowDocking[] floatedOrWindowsToolWindows) { + this.dockToolWindow( + floatedOrWindowsToolWindows, + (x, y) -> (int) (x.getBounds().getY() - y.getBounds().getY()), + (x, y) -> x.getBottomDockingBounds().intersects(y.getTopDockingBounds()), + Comparator.comparingInt(x -> (int) x.getBounds().getX()), + (toolWindow, boundsToDock) -> { + int y = (int) toolWindow.getBounds().getY(); + int newY = (int) boundsToDock.getMaxY(); + return new Rectangle( + (int) toolWindow.getBounds().getX(), + newY, + (int) toolWindow.getBounds().getWidth(), + (int) (toolWindow.getBounds().getHeight() + (y - newY))); + }); + } - if (intersectionToolWindows.length > 0) { - int x = (int)toolWindowDocking.getBounds().getX(); - int newX = (int)intersectionToolWindows[0].getBounds().getMaxX(); - Rectangle newBounds = new Rectangle( - newX, - (int) toolWindowDocking.getBounds().getY(), - (int)(toolWindowDocking.getBounds().getWidth() + (x - newX)), - (int) toolWindowDocking.getBounds().getHeight()); - toolWindowDocking.getToolWindowInfo().setBounds(newBounds); - } - } + private void dockRight(ToolWindowDocking[] floatedOrWindowsToolWindows) { + this.dockToolWindow( + floatedOrWindowsToolWindows, + (x, y) -> (int) (x.getBounds().getMaxX() - y.getBounds().getMaxX()), + (x, y) -> x.getLeftDockingBounds().intersects(y.getRightDockingBounds()), + Comparator.comparingInt(x -> (int) x.getBounds().getY()), + (toolWindow, boundsToDock) -> new Rectangle( + (int) toolWindow.getBounds().getX(), + (int) toolWindow.getBounds().getY(), + (int) (boundsToDock.getX() - toolWindow.getBounds().getX()), + (int) toolWindow.getBounds().getHeight())); } - private void dockTop(ToolWindowDocking[] floatedOrWindowsToolWindows) { - ToolWindowDocking[] sortedByTopPosition = Arrays.stream(floatedOrWindowsToolWindows) - .sorted((x, y) -> (int) (x.getBounds().getY() - y.getBounds().getY())) + private void dockBottom(ToolWindowDocking[] floatedOrWindowsToolWindows) { + this.dockToolWindow( + floatedOrWindowsToolWindows, + (x, y) -> (int) (x.getBounds().getMaxY() - y.getBounds().getMaxY()), + (x, y) -> x.getTopDockingBounds().intersects(y.getBottomDockingBounds()), + Comparator.comparingInt(x -> (int) x.getBounds().getY()), + (toolWindow, boundsToDock) -> new Rectangle( + (int) toolWindow.getBounds().getX(), + (int) toolWindow.getBounds().getY(), + (int) toolWindow.getBounds().getWidth(), + (int) (boundsToDock.getY() - toolWindow.getBounds().getY()))); + } + + private void dockToolWindow( + ToolWindowDocking[] floatedOrWindowsToolWindows, + Comparator sortForProcessing, + BiPredicate isIntersecting, + Comparator sortForClosestToDock, + BiFunction calculateNewBounds) { + + ToolWindowDocking[] sortedByLeftPosition = Arrays.stream(floatedOrWindowsToolWindows) + .sorted(sortForProcessing) .skip(1) .toArray(ToolWindowDocking[]::new); - for (ToolWindowDocking toolWindowDocking : sortedByTopPosition) { - ToolWindowDocking[] intersectionToolWindows = Arrays.stream(floatedOrWindowsToolWindows) - .filter(x -> - !x.getToolWindowInfo().getId().equals(toolWindowDocking.getToolWindowInfo().getId()) && - x.getBottomDockingBounds().intersects(toolWindowDocking.getTopDockingBounds())) - .sorted(Comparator.comparingInt(x -> (int) x.getBounds().getX())) - .toArray(ToolWindowDocking[]::new); + for (ToolWindowDocking toolWindowDocking : sortedByLeftPosition) { + ToolWindowDocking dockingTarget = Arrays.stream(floatedOrWindowsToolWindows) + .filter(x -> + !x.getToolWindowInfo().getId().equals(toolWindowDocking.getToolWindowInfo().getId()) && + isIntersecting.test(x, toolWindowDocking)) + .min(sortForClosestToDock) + .orElse(null); - if (intersectionToolWindows.length > 0) { - int y = (int)toolWindowDocking.getBounds().getY(); - int newY = (int)intersectionToolWindows[0].getBounds().getMaxY(); - Rectangle newBounds = new Rectangle( - (int) toolWindowDocking.getBounds().getX(), - newY, - (int) toolWindowDocking.getBounds().getWidth(), - (int)(toolWindowDocking.getBounds().getHeight() + (y - newY))); + if (dockingTarget != null) { + Rectangle newBounds = calculateNewBounds.apply(toolWindowDocking, dockingTarget.getBounds()); toolWindowDocking.getToolWindowInfo().setBounds(newBounds); } } From 40b3349d77f8c42d25daa14a03aa7511f5e7a6aa Mon Sep 17 00:00:00 2001 From: Michael Estermann <14977799+michaelestermann@users.noreply.github.com> Date: Wed, 26 Feb 2020 09:41:54 +0100 Subject: [PATCH 05/19] Added todo --- .../layout/store/create/NewLayoutAction.java | 12 ++++++------ .../layoutmanager/ui/helpers/ToolWindowHelper.java | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/layoutmanager/layout/store/create/NewLayoutAction.java b/src/main/java/com/layoutmanager/layout/store/create/NewLayoutAction.java index 2e8d3b0..99d6d9c 100644 --- a/src/main/java/com/layoutmanager/layout/store/create/NewLayoutAction.java +++ b/src/main/java/com/layoutmanager/layout/store/create/NewLayoutAction.java @@ -30,12 +30,12 @@ public NewLayoutAction(LayoutCreator layoutCreator) { @Override public void actionPerformed(@NotNull AnActionEvent event) { ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(event.getProject()); - Layout updatedLayout = this.layoutCreator.create(toolWindowManager, ""); + Layout newLayout = this.layoutCreator.create(toolWindowManager, ""); - if (updatedLayout != null) { - this.storeLayout(updatedLayout); + if (newLayout != null) { + this.storeLayout(newLayout); this.updateWindowMenuItems(); - this.showNotification(updatedLayout); + this.showNotification(newLayout); } } @@ -48,9 +48,9 @@ private void updateWindowMenuItems() { windowMenuService.recreate(); } - private void showNotification(Layout updatedLayout) { + private void showNotification(Layout newLayout) { NotificationHelper.info( MessagesHelper.message("StoreLayout.New.Notification.Title"), - MessagesHelper.message("StoreLayout.New.Notification.Content", updatedLayout.getName())); + MessagesHelper.message("StoreLayout.New.Notification.Content", newLayout.getName())); } } diff --git a/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java b/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java index 1e86917..3b48cca 100644 --- a/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java +++ b/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java @@ -13,6 +13,7 @@ import org.jetbrains.annotations.Nullable; +// TODO: Add fix when window is not visible... public class ToolWindowHelper { public static Rectangle getBounds(ToolWindowImpl toolWindow) { if (toolWindow.getType() == ToolWindowType.FLOATING) { From dba29fb20e066a282a6825aa066906141b4e8d43 Mon Sep 17 00:00:00 2001 From: Michael Estermann <14977799+michaelestermann@users.noreply.github.com> Date: Thu, 26 Mar 2020 13:16:31 +0100 Subject: [PATCH 06/19] fi master. --- build.gradle | 2 +- .../layout/restore/RestoreLayoutAction.java | 41 ++++++++++++++----- .../layout/store/LayoutCreator.java | 4 +- .../persistence/LayoutConfig.java | 4 +- .../ui/helpers/ToolWindowHelper.java | 29 +++++++------ .../ui/menu/WindowMenuService.java | 2 +- src/main/resources/META-INF/plugin.xml | 8 ++++ .../layoutmanager/ui/messages_de.properties | 18 -------- 8 files changed, 63 insertions(+), 45 deletions(-) delete mode 100644 src/main/resources/com/layoutmanager/ui/messages_de.properties diff --git a/build.gradle b/build.gradle index 3fe1e6f..20d0222 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'com.layoutmanager' -version '1.3.0' +version '1.4.0' sourceCompatibility = 1.8 diff --git a/src/main/java/com/layoutmanager/layout/restore/RestoreLayoutAction.java b/src/main/java/com/layoutmanager/layout/restore/RestoreLayoutAction.java index f6a1c39..5dd3a15 100644 --- a/src/main/java/com/layoutmanager/layout/restore/RestoreLayoutAction.java +++ b/src/main/java/com/layoutmanager/layout/restore/RestoreLayoutAction.java @@ -6,6 +6,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.wm.ToolWindowAnchor; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.openapi.wm.impl.ToolWindowImpl; @@ -16,6 +17,10 @@ import com.layoutmanager.ui.helpers.ToolWindowHelper; import org.jetbrains.annotations.NotNull; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + public class RestoreLayoutAction extends AnAction { private final Layout layout; @@ -43,11 +48,19 @@ public void actionPerformed(@NotNull AnActionEvent event) { } private void applyLayout(AnActionEvent event, Layout layout) { - this.applyEditorTabPlacement(layout); - ToolWindowManager toolWindowManager = this.getToolWindowManager(event); - for (ToolWindowInfo toolWindow : layout.getToolWindows()) { - this.applyToolWindowLayout(toolWindowManager, toolWindow); - } + applyEditorTabPlacement(layout); + ToolWindowManager toolWindowManager = getToolWindowManager(event); + + Map toolWindows = getToolWindows(toolWindowManager, layout.getToolWindows()); + hideAllToolWindows(toolWindows); + applyToolWindowLayout(toolWindows); + } + + private Map getToolWindows(ToolWindowManager toolWindowManager, ToolWindowInfo[] toolWindows) { + return Stream.of(toolWindows) + .map(x -> new Pair(x, (ToolWindowImpl)toolWindowManager.getToolWindow(x.getId()))) + .filter(x -> x.second != null) + .collect(Collectors.toMap(x -> x.first, x -> x.second)); } private void applyEditorTabPlacement(Layout layout) { @@ -59,11 +72,19 @@ private void applyEditorTabPlacement(Layout layout) { } } - private void applyToolWindowLayout(ToolWindowManager toolWindowManager, ToolWindowInfo info) { - ToolWindowImpl toolWindow = (ToolWindowImpl)toolWindowManager.getToolWindow(info.getId()); - - if (toolWindow != null) { + private void hideAllToolWindows(Map toolWindows) { + toolWindows.forEach((info, toolWindow) -> { toolWindow.hide(null); + }); + } + + private void applyToolWindowLayout(Map toolWindows) { + + toolWindows.forEach((info, toolWindow) -> { + // !! Workaround !! + // decorator is not set and throws exception. When calling this method, the content manager lazy variable will be loaded and therefor also the decorator... + // See: https://github.com/JetBrains/intellij-community/blob/a63286c3b29fe467399fb353c71ed15cd65db8dd/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.kt + toolWindow.getComponent(); toolWindow.setAnchor(ToolWindowAnchor.fromText(info.getAnchor()), null); toolWindow.setType(info.getType(), null); @@ -74,7 +95,7 @@ private void applyToolWindowLayout(ToolWindowManager toolWindowManager, ToolWind } ToolWindowHelper.setBounds(toolWindow, info.getBounds()); - } + }); } private ToolWindowManager getToolWindowManager(AnActionEvent event) { diff --git a/src/main/java/com/layoutmanager/layout/store/LayoutCreator.java b/src/main/java/com/layoutmanager/layout/store/LayoutCreator.java index 350475a..c32c3f0 100644 --- a/src/main/java/com/layoutmanager/layout/store/LayoutCreator.java +++ b/src/main/java/com/layoutmanager/layout/store/LayoutCreator.java @@ -55,7 +55,9 @@ private Layout createLayout(ToolWindowManager toolWindowManager, String name) { List toolWindows = getToolWindows(toolWindowManager); Layout layout = new Layout( name, - toolWindows.toArray(ToolWindowInfo[]::new), + toolWindows + .stream() + .toArray(ToolWindowInfo[]::new), getEditorPlacement()); this.dock(toolWindowManager, layout); diff --git a/src/main/java/com/layoutmanager/persistence/LayoutConfig.java b/src/main/java/com/layoutmanager/persistence/LayoutConfig.java index dc9831b..0f898f7 100644 --- a/src/main/java/com/layoutmanager/persistence/LayoutConfig.java +++ b/src/main/java/com/layoutmanager/persistence/LayoutConfig.java @@ -39,7 +39,9 @@ public Layout getLayout(int number) { @SuppressWarnings({"unused", "Used for serialization."}) public Layout[] getLayouts() { - return this.layouts.toArray(Layout[]::new); + return this.layouts + .stream() + .toArray(Layout[]::new); } public int getLayoutCount() { diff --git a/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java b/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java index 3b48cca..7fdcb09 100644 --- a/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java +++ b/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java @@ -13,27 +13,30 @@ import org.jetbrains.annotations.Nullable; -// TODO: Add fix when window is not visible... public class ToolWindowHelper { public static Rectangle getBounds(ToolWindowImpl toolWindow) { - if (toolWindow.getType() == ToolWindowType.FLOATING) { - FloatingDecorator floatingDecorator = getFloatingDecorator(toolWindow); - return floatingDecorator.getBounds(); - } else if (toolWindow.getType() == ToolWindowType.WINDOWED) { - Window window = getWindow(toolWindow); - return window.getBounds(); + if (toolWindow.isVisible()) { + if (toolWindow.getType() == ToolWindowType.FLOATING) { + FloatingDecorator floatingDecorator = getFloatingDecorator(toolWindow); + return floatingDecorator.getBounds(); + } else if (toolWindow.getType() == ToolWindowType.WINDOWED) { + Window window = getWindow(toolWindow); + return window.getBounds(); + } } return new Rectangle(0, 0, 0, 0); } public static void setBounds(ToolWindowImpl toolWindow, Rectangle bounds) { - if (toolWindow.getType() == ToolWindowType.FLOATING) { - FloatingDecorator floatingDecorator = getFloatingDecorator(toolWindow); - floatingDecorator.setBounds(bounds); - } else if (toolWindow.getType() == ToolWindowType.WINDOWED) { - Window window = getWindow(toolWindow); - window.setBounds(bounds); + if (toolWindow.isVisible()) { + if (toolWindow.getType() == ToolWindowType.FLOATING) { + FloatingDecorator floatingDecorator = getFloatingDecorator(toolWindow); + floatingDecorator.setBounds(bounds); + } else if (toolWindow.getType() == ToolWindowType.WINDOWED) { + Window window = getWindow(toolWindow); + window.setBounds(bounds); + } } } diff --git a/src/main/java/com/layoutmanager/ui/menu/WindowMenuService.java b/src/main/java/com/layoutmanager/ui/menu/WindowMenuService.java index aa4ea27..0c9b880 100644 --- a/src/main/java/com/layoutmanager/ui/menu/WindowMenuService.java +++ b/src/main/java/com/layoutmanager/ui/menu/WindowMenuService.java @@ -20,7 +20,7 @@ public class WindowMenuService { public void create() { if (this.storeLayout != null) { - throw new IllegalStateException("Menu items already created"); + return; } this.createMainActions((DefaultActionGroup) ActionManager.getInstance().getAction("WindowMenu")); diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 916a5ee..49b43ba 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -25,6 +25,14 @@
  • Dec 11, 2019 (ver 1.2.2) - Support of the latest IDE versions 2019.3
  • Dec 11, 2019 (ver 1.2.3) - Various bug fixes
  • Dec 19, 2019 (ver 1.3.0) - Store placement of editor tabs and tool window labels.
  • +
  • Dec 26, 2019 (ver 1.3.1) - Fix support of Java 8.
  • +
  • Jan 07, 2020 (ver 1.3.2) - Minor bugfixes.
  • +
  • Feb 25, 2020 (ver 1.3.3) - Issues when storing and restoring invisible windows fixed.
  • +
  • + Mar 26, 2020 (ver 1.4.0) + - Introduced settings page. + - Introduced smart docking when saving a layout (Configurable). +
  • ]]> diff --git a/src/main/resources/com/layoutmanager/ui/messages_de.properties b/src/main/resources/com/layoutmanager/ui/messages_de.properties deleted file mode 100644 index d5740a1..0000000 --- a/src/main/resources/com/layoutmanager/ui/messages_de.properties +++ /dev/null @@ -1,18 +0,0 @@ -RestoreLayout.Menu=Fensterlayout anwenden -RestoreLayout.Notification.Title=Fensterlayout angewendet -RestoreLayout.Notification.Content=Das Fensterlayout ''{0}'' wurde erfolgreich angewendet. - -StoreLayout.Menu=Fensterlayout speichern -StoreLayout.Dialog.Title=Fensterlayout -StoreLayout.Dialog.Content=Name des Fensterlayouts eingeben -StoreLayout.Validation.ToolWindowOutOfScreen.Title=Invalide Konfiguration des Fensterlayouts -StoreLayout.Validation.ToolWindowOutOfScreen.Content=Die Fenster ''{0}'' befinden sich (teilweise)ausserhalb des Bildschirmes. Wenn das Projekt erneut geöffnet wird in der IDE, werden diese Fenster in der Mitte des Hauptfenster platziert. Um dies zu verhindern, muss die Konfiguration nochmals angepasst werden oder andernfalls muss das Fensterlayout nochmals angewendet werden nach dem öffnen des Projektes. -StoreLayout.New.Menu=Neues Fensterlayout -StoreLayout.New.Notification.Title=Fensterlayout gespeichert -StoreLayout.New.Notification.Content=Das Fensterlayout''{0}'' wurde erfolgreich gespeichert. -StoreLayout.Overwrite.Notification.Title=Fensterlayout überschrieben -StoreLayout.Overwrite.Notification.Content=Das Fensterlayout ''{0}'' wurde erfolgreich überschrieben mit ''{1}''. - -DeleteLayout.Menu=Fensterlayout löschen -DeleteLayout.Notification.Title=Fensterlayout gelöscht -DeleteLayout.Notification.Content=Das Fensterlayout ''{0}'' wurde erfolgreich gelöscht. From d11b10bf06a14561a72c8b89d58089e443af96c1 Mon Sep 17 00:00:00 2001 From: Michael Estermann <14977799+michaelestermann@users.noreply.github.com> Date: Thu, 26 Mar 2020 17:04:33 +0100 Subject: [PATCH 07/19] Settings page without logic. --- .../persistence/LayoutConfig.java | 19 ++- .../persistence/LayoutSettings.java | 13 ++ .../settings/LayoutManagerSettingsPanel.form | 122 ++++++++++++++++++ .../settings/LayoutManagerSettingsPanel.java | 113 ++++++++++++++++ .../ui/settings/SettingsPage.java | 8 +- 5 files changed, 265 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/layoutmanager/persistence/LayoutSettings.java create mode 100644 src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.form create mode 100644 src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java diff --git a/src/main/java/com/layoutmanager/persistence/LayoutConfig.java b/src/main/java/com/layoutmanager/persistence/LayoutConfig.java index 0f898f7..625b822 100644 --- a/src/main/java/com/layoutmanager/persistence/LayoutConfig.java +++ b/src/main/java/com/layoutmanager/persistence/LayoutConfig.java @@ -21,6 +21,7 @@ ) public class LayoutConfig implements PersistentStateComponent { private List layouts = new ArrayList<>(); + private LayoutSettings settings = new LayoutSettings(); @Nullable @Override @@ -44,6 +45,19 @@ public Layout[] getLayouts() { .toArray(Layout[]::new); } + @SuppressWarnings({"unused", "Used for serialization."}) + public void setLayouts(Layout[] layouts) { + this.layouts = new ArrayList<>(Arrays.asList(layouts)); + } + + public LayoutSettings getSettings() { + return this.settings; + } + + public void setSettings(LayoutSettings settings) { + this.settings = settings; + } + public int getLayoutCount() { return this.layouts.size(); } @@ -64,10 +78,5 @@ public void removeLayout(Layout layout) { public static LayoutConfig getInstance() { return ServiceManager.getService(LayoutConfig.class); } - - @SuppressWarnings({"unused", "Used for serialization."}) - public void setLayouts(Layout[] layouts) { - this.layouts = new ArrayList<>(Arrays.asList(layouts)); - } } diff --git a/src/main/java/com/layoutmanager/persistence/LayoutSettings.java b/src/main/java/com/layoutmanager/persistence/LayoutSettings.java new file mode 100644 index 0000000..3e32356 --- /dev/null +++ b/src/main/java/com/layoutmanager/persistence/LayoutSettings.java @@ -0,0 +1,13 @@ +package com.layoutmanager.persistence; + +public class LayoutSettings { + private boolean useSmartDock = true; + + public boolean getUseSmartDock() { + return this.useSmartDock; + } + + public void setUseSmartDock(boolean useSmartDock) { + this.useSmartDock = useSmartDock; + } +} diff --git a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.form b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.form new file mode 100644 index 0000000..0489e1e --- /dev/null +++ b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.form @@ -0,0 +1,122 @@ + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    diff --git a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java new file mode 100644 index 0000000..d01a096 --- /dev/null +++ b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java @@ -0,0 +1,113 @@ +package com.layoutmanager.ui.settings; + +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import com.intellij.uiDesigner.core.Spacer; +import com.layoutmanager.persistence.Layout; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import javax.swing.table.DefaultTableModel; +import java.awt.*; + +public class LayoutManagerSettingsPanel { + private JCheckBox useSmartDockingCheckbox; + private JButton deleteButton; + private JButton renameButton; + private JButton exportButton; + private JButton buttonImport; + private JPanel settingsPanel; + private JTable tableLayouts; + + { +// GUI initializer generated by IntelliJ IDEA GUI Designer +// >>> IMPORTANT!! <<< +// DO NOT EDIT OR ADD ANY CODE HERE! + $$$setupUI$$$(); + } + + public LayoutManagerSettingsPanel(Layout[] layouts) { + DefaultTableModel table = createTableContent(layouts); + this.tableLayouts.setModel(table); + } + + @NotNull + private DefaultTableModel createTableContent(Layout[] layouts) { + DefaultTableModel model = new DefaultTableModel(new String[] { "Name", "Configured Windows" }, 0) { + + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + }; + + for (Layout layout : layouts) { + model.addRow(new Object[] {layout.getName(), layout.getToolWindows().length }); + } + + return model; + } + + public JPanel getPanel() { + return this.settingsPanel; + } + + /** + * Method generated by IntelliJ IDEA GUI Designer + * >>> IMPORTANT!! <<< + * DO NOT edit this method OR call it in your code! + * + * @noinspection ALL + */ + private void $$$setupUI$$$() { + settingsPanel = new JPanel(); + settingsPanel.setLayout(new GridLayoutManager(5, 1, new Insets(0, 0, 0, 0), -1, -1)); + final JLabel label1 = new JLabel(); + label1.setText("Docking"); + settingsPanel.add(label1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + useSmartDockingCheckbox = new JCheckBox(); + useSmartDockingCheckbox.setText("Use smart docking when storing a layout"); + settingsPanel.add(useSmartDockingCheckbox, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JLabel label2 = new JLabel(); + label2.setText("Layouts"); + settingsPanel.add(label2, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + tableLayouts = new JTable(); + settingsPanel.add(tableLayouts, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_WANT_GROW, null, new Dimension(150, 50), null, 0, false)); + final JPanel panel1 = new JPanel(); + panel1.setLayout(new GridLayoutManager(1, 5, new Insets(0, 0, 0, 0), -1, -1)); + settingsPanel.add(panel1, new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + deleteButton = new JButton(); + deleteButton.setEnabled(false); + deleteButton.setText("Delete"); + deleteButton.setMnemonic('D'); + deleteButton.setDisplayedMnemonicIndex(0); + panel1.add(deleteButton, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + renameButton = new JButton(); + renameButton.setEnabled(false); + renameButton.setText("Rename"); + renameButton.setMnemonic('R'); + renameButton.setDisplayedMnemonicIndex(0); + panel1.add(renameButton, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + exportButton = new JButton(); + exportButton.setEnabled(false); + exportButton.setText("Export"); + exportButton.setMnemonic('E'); + exportButton.setDisplayedMnemonicIndex(0); + panel1.add(exportButton, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + buttonImport = new JButton(); + buttonImport.setEnabled(false); + buttonImport.setText("Import"); + buttonImport.setMnemonic('I'); + buttonImport.setDisplayedMnemonicIndex(0); + panel1.add(buttonImport, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final Spacer spacer1 = new Spacer(); + panel1.add(spacer1, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false)); + } + + /** + * @noinspection ALL + */ + public JComponent $$$getRootComponent$$$() { + return settingsPanel; + } +} diff --git a/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java b/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java index 84cfe81..5b4e6b0 100644 --- a/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java +++ b/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java @@ -1,11 +1,10 @@ package com.layoutmanager.ui.settings; import com.intellij.openapi.options.Configurable; -import com.intellij.ui.JBColor; import javax.swing.JComponent; -import javax.swing.JPanel; +import com.layoutmanager.persistence.LayoutConfig; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.Nullable; @@ -19,9 +18,8 @@ public String getDisplayName() { @Nullable @Override public JComponent createComponent() { - JPanel panel = new JPanel(); - panel.setBackground(JBColor.red); - return panel; + return new LayoutManagerSettingsPanel(LayoutConfig.getInstance().getLayouts()) + .getPanel(); } @Override From c910be1513848fb1219679199baadf7781f47465 Mon Sep 17 00:00:00 2001 From: Michael Estermann <14977799+michaelestermann@users.noreply.github.com> Date: Thu, 26 Mar 2020 19:05:47 +0100 Subject: [PATCH 08/19] Store docket window sizes. --- .../ui/helpers/ToolWindowHelper.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java b/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java index 7fdcb09..53d35c9 100644 --- a/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java +++ b/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java @@ -1,9 +1,8 @@ package com.layoutmanager.ui.helpers; +import com.intellij.openapi.wm.ToolWindowAnchor; import com.intellij.openapi.wm.ToolWindowType; -import com.intellij.openapi.wm.impl.FloatingDecorator; -import com.intellij.openapi.wm.impl.InternalDecorator; -import com.intellij.openapi.wm.impl.ToolWindowImpl; +import com.intellij.openapi.wm.impl.*; import com.intellij.util.ui.UIUtil; import java.awt.Rectangle; @@ -22,6 +21,9 @@ public static Rectangle getBounds(ToolWindowImpl toolWindow) { } else if (toolWindow.getType() == ToolWindowType.WINDOWED) { Window window = getWindow(toolWindow); return window.getBounds(); + } else { + InternalDecorator decorator = toolWindow.getDecorator(); + return decorator.getBounds(); } } @@ -36,6 +38,13 @@ public static void setBounds(ToolWindowImpl toolWindow, Rectangle bounds) { } else if (toolWindow.getType() == ToolWindowType.WINDOWED) { Window window = getWindow(toolWindow); window.setBounds(bounds); + } else { + Rectangle currentBounds = toolWindow.getDecorator().getBounds(); + if (toolWindow.getAnchor() == ToolWindowAnchor.TOP || toolWindow.getAnchor() == ToolWindowAnchor.BOTTOM) { + toolWindow.stretchHeight(bounds.height - currentBounds.height); + } else { + toolWindow.stretchWidth(bounds.width - currentBounds.width); + } } } } From 31f13bfc2100eb386632dd8434c10f65267f6e25 Mon Sep 17 00:00:00 2001 From: Michael Estermann <14977799+michaelestermann@users.noreply.github.com> Date: Thu, 26 Mar 2020 21:06:00 +0100 Subject: [PATCH 09/19] Implemented settings page and respect settings when store a layout. --- .../layout/store/LayoutCreator.java | 40 +++--- .../com/layoutmanager/persistence/Layout.java | 26 ++++ .../persistence/ToolWindowInfo.java | 25 ++++ .../ui/dialogs/LayoutNameDialog.java | 22 ++++ .../ui/menu/WindowMenuService.java | 16 ++- .../settings/LayoutManagerSettingsPanel.form | 2 +- .../settings/LayoutManagerSettingsPanel.java | 117 +++++++++++++++--- .../ui/settings/SettingsPage.java | 17 ++- 8 files changed, 217 insertions(+), 48 deletions(-) create mode 100644 src/main/java/com/layoutmanager/ui/dialogs/LayoutNameDialog.java diff --git a/src/main/java/com/layoutmanager/layout/store/LayoutCreator.java b/src/main/java/com/layoutmanager/layout/store/LayoutCreator.java index c32c3f0..bf05f40 100644 --- a/src/main/java/com/layoutmanager/layout/store/LayoutCreator.java +++ b/src/main/java/com/layoutmanager/layout/store/LayoutCreator.java @@ -1,56 +1,47 @@ package com.layoutmanager.layout.store; -import com.intellij.icons.AllIcons; import com.intellij.ide.ui.UISettings; -import com.intellij.openapi.ui.Messages; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.openapi.wm.impl.ToolWindowImpl; - import com.layoutmanager.layout.store.smartdock.SmartDocker; import com.layoutmanager.layout.store.smartdock.SmartDockerFactory; import com.layoutmanager.layout.store.validation.LayoutValidationHelper; import com.layoutmanager.localization.MessagesHelper; import com.layoutmanager.persistence.Layout; +import com.layoutmanager.persistence.LayoutConfig; +import com.layoutmanager.persistence.LayoutSettings; import com.layoutmanager.persistence.ToolWindowInfo; +import com.layoutmanager.ui.dialogs.LayoutNameDialog; import com.layoutmanager.ui.helpers.NotificationHelper; import com.layoutmanager.ui.helpers.ToolWindowHelper; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; -import org.jetbrains.annotations.NotNull; - public class LayoutCreator { - + private final LayoutSettings layoutSettings; private final SmartDockerFactory smartDockerFactory; + private final LayoutNameDialog layoutNameDialog; - public LayoutCreator(SmartDockerFactory smartDockerFactory) { + public LayoutCreator( + LayoutSettings layoutSettings, + SmartDockerFactory smartDockerFactory, + LayoutNameDialog layoutNameDialog) { + this.layoutSettings = layoutSettings; this.smartDockerFactory = smartDockerFactory; + this.layoutNameDialog = layoutNameDialog; } public Layout create(ToolWindowManager toolWindowManager, String defaultName) { - String name = this.getLayoutName(defaultName); + String name = this.layoutNameDialog.show(defaultName); return name != null ? this.createLayout(toolWindowManager, name) : null; } - private String getLayoutName(String defaultName) { - String name; - do { - name = Messages.showInputDialog( - MessagesHelper.message("StoreLayout.Dialog.Title"), - MessagesHelper.message("StoreLayout.Dialog.Content"), - AllIcons.Actions.Edit, - defaultName, - null); - } while (name != null && name.isEmpty()); - - return name; - } - private Layout createLayout(ToolWindowManager toolWindowManager, String name) { List toolWindows = getToolWindows(toolWindowManager); Layout layout = new Layout( @@ -60,7 +51,10 @@ private Layout createLayout(ToolWindowManager toolWindowManager, String name) { .toArray(ToolWindowInfo[]::new), getEditorPlacement()); - this.dock(toolWindowManager, layout); + if (this.layoutSettings.getUseSmartDock()) { + this.dock(toolWindowManager, layout); + } + validateLayout(layout); return layout; diff --git a/src/main/java/com/layoutmanager/persistence/Layout.java b/src/main/java/com/layoutmanager/persistence/Layout.java index fc031b1..e7675fd 100644 --- a/src/main/java/com/layoutmanager/persistence/Layout.java +++ b/src/main/java/com/layoutmanager/persistence/Layout.java @@ -1,6 +1,9 @@ package com.layoutmanager.persistence; +import java.util.Arrays; +import java.util.Objects; + public class Layout { private String name; private int editorTabPlacement; @@ -45,4 +48,27 @@ public ToolWindowInfo[] getToolWindows() { public void setToolWindows(ToolWindowInfo[] toolWindows) { this.toolWindows = toolWindows; } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (other == null || getClass() != other.getClass()) { + return false; + } + + Layout that = (Layout) other; + return this.editorTabPlacement == that.editorTabPlacement && + this.name.equals(that.name) && + Arrays.equals(this.toolWindows, that.toolWindows); + } + + @Override + public int hashCode() { + int result = Objects.hash(this.name, this.editorTabPlacement); + result = 31 * result + Arrays.hashCode(toolWindows); + return result; + } } \ No newline at end of file diff --git a/src/main/java/com/layoutmanager/persistence/ToolWindowInfo.java b/src/main/java/com/layoutmanager/persistence/ToolWindowInfo.java index 8f04ef7..5190faa 100644 --- a/src/main/java/com/layoutmanager/persistence/ToolWindowInfo.java +++ b/src/main/java/com/layoutmanager/persistence/ToolWindowInfo.java @@ -3,6 +3,7 @@ import com.intellij.openapi.wm.ToolWindowType; import java.awt.Rectangle; +import java.util.Objects; public class ToolWindowInfo { private String id; @@ -90,4 +91,28 @@ public void setVisible(boolean visible) { public void setIsToolWindow(boolean isToolWindow) { this.isToolWindow = isToolWindow; } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (other == null || getClass() != other.getClass()) { + return false; + } + + ToolWindowInfo that = (ToolWindowInfo) other; + return this.isVisible == that.isVisible && + this.isToolWindow == that.isToolWindow && + this.id.equals(that.id) && + this.type == that.type && + this.anchor.equals(that.anchor) && + this.bounds.equals(that.bounds); + } + + @Override + public int hashCode() { + return Objects.hash(this.id, this.type, this.anchor, this.bounds, this.isVisible, this.isToolWindow); + } } diff --git a/src/main/java/com/layoutmanager/ui/dialogs/LayoutNameDialog.java b/src/main/java/com/layoutmanager/ui/dialogs/LayoutNameDialog.java new file mode 100644 index 0000000..c36e4e0 --- /dev/null +++ b/src/main/java/com/layoutmanager/ui/dialogs/LayoutNameDialog.java @@ -0,0 +1,22 @@ +package com.layoutmanager.ui.dialogs; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.ui.Messages; +import com.layoutmanager.localization.MessagesHelper; + +public class LayoutNameDialog { + + public String show(String defaultName) { + String name; + do { + name = Messages.showInputDialog( + MessagesHelper.message("StoreLayout.Dialog.Title"), + MessagesHelper.message("StoreLayout.Dialog.Content"), + AllIcons.Actions.Edit, + defaultName, + null); + } while (name != null && name.isEmpty()); + + return name; + } +} diff --git a/src/main/java/com/layoutmanager/ui/menu/WindowMenuService.java b/src/main/java/com/layoutmanager/ui/menu/WindowMenuService.java index 0c9b880..7398651 100644 --- a/src/main/java/com/layoutmanager/ui/menu/WindowMenuService.java +++ b/src/main/java/com/layoutmanager/ui/menu/WindowMenuService.java @@ -12,6 +12,7 @@ import com.layoutmanager.localization.MessagesHelper; import com.layoutmanager.persistence.Layout; import com.layoutmanager.persistence.LayoutConfig; +import com.layoutmanager.ui.dialogs.LayoutNameDialog; public class WindowMenuService { private DefaultActionGroup storeLayout; @@ -19,7 +20,7 @@ public class WindowMenuService { private DefaultActionGroup deleteLayout; public void create() { - if (this.storeLayout != null) { + if (this.hasBeenCreated()) { return; } @@ -28,6 +29,10 @@ public void create() { } public void recreate() { + if (!this.hasBeenCreated()) { + return; + } + this.restoreLayout.removeAll(); this.storeLayout.removeAll(); this.deleteLayout.removeAll(); @@ -35,6 +40,10 @@ public void recreate() { this.createStoreRestoreActions(); } + private boolean hasBeenCreated() { + return this.storeLayout != null; + } + private void createMainActions(DefaultActionGroup windowMenu) { this.storeLayout = this.createMainAction(MessagesHelper.message("StoreLayout.Menu"), windowMenu); this.restoreLayout = this.createMainAction(MessagesHelper.message("RestoreLayout.Menu"), windowMenu); @@ -56,7 +65,10 @@ private void createStoreRestoreActions() { } private void addStoreLayoutActions(LayoutConfig config) { - LayoutCreator layoutCreator = new LayoutCreator(new SmartDockerFactory()); + LayoutCreator layoutCreator = new LayoutCreator( + config.getSettings(), + new SmartDockerFactory(), + new LayoutNameDialog()); for (int index = 0; index < config.getLayoutCount(); index++) { this.storeLayout.add(new OverwriteLayoutAction(layoutCreator, index)); diff --git a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.form b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.form index 0489e1e..ce2a650 100644 --- a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.form +++ b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.form @@ -53,7 +53,7 @@ - + diff --git a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java index d01a096..033d39c 100644 --- a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java +++ b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java @@ -1,21 +1,35 @@ package com.layoutmanager.ui.settings; +import com.intellij.openapi.components.ServiceManager; import com.intellij.uiDesigner.core.GridConstraints; import com.intellij.uiDesigner.core.GridLayoutManager; import com.intellij.uiDesigner.core.Spacer; import com.layoutmanager.persistence.Layout; +import com.layoutmanager.persistence.LayoutConfig; +import com.layoutmanager.ui.dialogs.LayoutNameDialog; +import com.layoutmanager.ui.menu.WindowMenuService; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import javax.swing.event.TableModelEvent; import javax.swing.table.DefaultTableModel; import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.EventObject; public class LayoutManagerSettingsPanel { + private final LayoutConfig layoutConfig; + private final LayoutNameDialog layoutNameDialog; + private ArrayList currentLayouts = new ArrayList<>(); private JCheckBox useSmartDockingCheckbox; private JButton deleteButton; private JButton renameButton; private JButton exportButton; - private JButton buttonImport; + private JButton importButton; private JPanel settingsPanel; private JTable tableLayouts; @@ -26,24 +40,95 @@ public class LayoutManagerSettingsPanel { $$$setupUI$$$(); } - public LayoutManagerSettingsPanel(Layout[] layouts) { - DefaultTableModel table = createTableContent(layouts); + public LayoutManagerSettingsPanel( + LayoutConfig layoutConfig, + LayoutNameDialog layoutNameDialog) { + this.layoutConfig = layoutConfig; + this.layoutNameDialog = layoutNameDialog; + + Collections.addAll(this.currentLayouts, layoutConfig.getLayouts()); + + DefaultTableModel table = createTableContent(); this.tableLayouts.setModel(table); + this.tableLayouts.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + useSmartDockingCheckbox.setSelected(layoutConfig.getSettings().getUseSmartDock()); + + this.tableLayouts.getSelectionModel().addListSelectionListener(listSelectionEvent -> { + deleteButton.setEnabled(this.tableLayouts.getSelectedRow() >= 0); + renameButton.setEnabled(this.tableLayouts.getSelectedRow() >= 0); + }); + + this.deleteButton.addActionListener(e -> + ((DefaultTableModel)this.tableLayouts.getModel()) + .removeRow(this.tableLayouts.getSelectedRow())); + this.renameButton.addActionListener(e -> { + int selectedRow = this.tableLayouts.getSelectedRow(); + String newName = this.layoutNameDialog.show(this.currentLayouts.get(selectedRow).getName()); + if (newName != null) { + this.tableLayouts.setValueAt(newName, selectedRow, 0); + } + }); + } + + public boolean hasChanged() { + return this.useSmartDockingCheckbox.isSelected() != this.layoutConfig.getSettings().getUseSmartDock() || + !Arrays.equals( + this.layoutConfig.getLayouts(), + this.currentLayouts + .stream() + .toArray(Layout[]::new)); + } + + public void apply() { + this.layoutConfig.getSettings().setUseSmartDock(this.useSmartDockingCheckbox.isSelected()); + this.layoutConfig.setLayouts(this.currentLayouts + .stream() + .toArray(Layout[]::new)); + + WindowMenuService windowMenuService = ServiceManager.getService(WindowMenuService.class); + windowMenuService.recreate(); } @NotNull - private DefaultTableModel createTableContent(Layout[] layouts) { - DefaultTableModel model = new DefaultTableModel(new String[] { "Name", "Configured Windows" }, 0) { + private DefaultTableModel createTableContent() { + DefaultTableModel model = new DefaultTableModel(new String[] { "Name", "Configured Windows" }, currentLayouts.size()) { @Override public boolean isCellEditable(int row, int column) { - return false; + return column == 0; } - }; - for (Layout layout : layouts) { - model.addRow(new Object[] {layout.getName(), layout.getToolWindows().length }); - } + @Override + public void setValueAt(Object aValue, int row, int column) { + currentLayouts.get(row).setName(aValue.toString()); + this.fireTableChanged(new TableModelEvent(this, row)); + } + + @Override + public int getRowCount() { + return currentLayouts.size(); + } + + @Override + public void removeRow(int row) { + currentLayouts.remove(row); + this.fireTableRowsDeleted(row, row); + } + + @Override + public Object getValueAt(int row, int column) { + Layout layout = currentLayouts.get(row); + + switch(column) { + case 0: + return layout.getName(); + case 1: + return layout.getToolWindows().length; + } + return null; + } + }; return model; } @@ -94,12 +179,12 @@ public JPanel getPanel() { exportButton.setMnemonic('E'); exportButton.setDisplayedMnemonicIndex(0); panel1.add(exportButton, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); - buttonImport = new JButton(); - buttonImport.setEnabled(false); - buttonImport.setText("Import"); - buttonImport.setMnemonic('I'); - buttonImport.setDisplayedMnemonicIndex(0); - panel1.add(buttonImport, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + importButton = new JButton(); + importButton.setEnabled(false); + importButton.setText("Import"); + importButton.setMnemonic('I'); + importButton.setDisplayedMnemonicIndex(0); + panel1.add(importButton, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); final Spacer spacer1 = new Spacer(); panel1.add(spacer1, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false)); } diff --git a/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java b/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java index 5b4e6b0..954f7af 100644 --- a/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java +++ b/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java @@ -5,35 +5,40 @@ import javax.swing.JComponent; import com.layoutmanager.persistence.LayoutConfig; +import com.layoutmanager.ui.dialogs.LayoutNameDialog; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.Nullable; public class SettingsPage implements Configurable { + private final LayoutManagerSettingsPanel panel; + + public SettingsPage() { + this.panel = new LayoutManagerSettingsPanel(LayoutConfig.getInstance(), new LayoutNameDialog()); + } + @Nls(capitalization = Nls.Capitalization.Title) @Override public String getDisplayName() { - return "Hello World"; + return "Window Layout Manager"; } @Nullable @Override public JComponent createComponent() { - return new LayoutManagerSettingsPanel(LayoutConfig.getInstance().getLayouts()) - .getPanel(); + return this.panel.getPanel(); } @Override public boolean isModified() { - return false; + return this.panel.hasChanged(); } @Override public void apply() { - + this.panel.apply(); } @Override public void reset() { - } } From df24c09d2c80b239cf49ca2332807fb0f9a20338 Mon Sep 17 00:00:00 2001 From: Michael Estermann <14977799+michaelestermann@users.noreply.github.com> Date: Fri, 27 Mar 2020 10:43:28 +0100 Subject: [PATCH 10/19] Adapted description of the plugin. --- src/main/resources/META-INF/plugin.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 49b43ba..45409a7 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -32,6 +32,7 @@ Mar 26, 2020 (ver 1.4.0) - Introduced settings page. - Introduced smart docking when saving a layout (Configurable). + - Store docked tool window sizes and restore them accordingly. ]]> From 740e1cbeeb30b61300400cbae220767385b09512 Mon Sep 17 00:00:00 2001 From: Michael Estermann <14977799+michaelestermann@users.noreply.github.com> Date: Wed, 8 Apr 2020 17:13:54 +0200 Subject: [PATCH 11/19] First draft of im-/export feature. --- build.gradle | 5 + .../layoutmanager/ui/settings/ExportPage.form | 119 ++++++++++++++ .../layoutmanager/ui/settings/ExportPage.java | 102 ++++++++++++ .../ui/settings/ImportDialog.form | 153 ++++++++++++++++++ .../ui/settings/ImportDialog.java | 131 +++++++++++++++ .../settings/LayoutManagerSettingsPanel.form | 121 +++++++------- .../settings/LayoutManagerSettingsPanel.java | 150 +++++++---------- 7 files changed, 627 insertions(+), 154 deletions(-) create mode 100644 src/main/java/com/layoutmanager/ui/settings/ExportPage.form create mode 100644 src/main/java/com/layoutmanager/ui/settings/ExportPage.java create mode 100644 src/main/java/com/layoutmanager/ui/settings/ImportDialog.form create mode 100644 src/main/java/com/layoutmanager/ui/settings/ImportDialog.java diff --git a/build.gradle b/build.gradle index 20d0222..c459d6e 100644 --- a/build.gradle +++ b/build.gradle @@ -3,6 +3,11 @@ plugins { id 'org.jetbrains.intellij' version '0.4.15' id 'checkstyle' } + +dependencies { + compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5' + compile group: 'com.github.tommyettinger', name: 'blazingchain', version: '1.4.4.2' +} group 'com.layoutmanager' version '1.4.0' diff --git a/src/main/java/com/layoutmanager/ui/settings/ExportPage.form b/src/main/java/com/layoutmanager/ui/settings/ExportPage.form new file mode 100644 index 0000000..6bafed1 --- /dev/null +++ b/src/main/java/com/layoutmanager/ui/settings/ExportPage.form @@ -0,0 +1,119 @@ + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    diff --git a/src/main/java/com/layoutmanager/ui/settings/ExportPage.java b/src/main/java/com/layoutmanager/ui/settings/ExportPage.java new file mode 100644 index 0000000..686cd9c --- /dev/null +++ b/src/main/java/com/layoutmanager/ui/settings/ExportPage.java @@ -0,0 +1,102 @@ +package com.layoutmanager.ui.settings; + +import com.intellij.openapi.ui.MessageType; +import com.intellij.openapi.ui.popup.Balloon; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.ui.awt.RelativePoint; + +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import java.awt.*; +import java.awt.datatransfer.StringSelection; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +// TODO: Change to dialog and cleanup +public class ExportPage { + // TODO: Move to common class + public static final String FILE_ENDING = "wl"; + public static final String FILE_ENDING_WITH_DOT = "." + FILE_ENDING; + + private JTextArea exportTextBox; + private JPanel importPanel; + private JButton exportToFileButton; + private JButton exportToClipboardButton; + private JButton closeButton; + private JLabel layoutNameLabel; + + private String layoutName; + private String content; + + public ExportPage(String layoutName, String content) { + this.layoutName = layoutName; + this.content = content; + + closeButton.addActionListener(actionEvent -> { + JDialog window = (JDialog) SwingUtilities.getAncestorOfClass(JDialog.class, this.importPanel); + window.dispose(); + }); + + exportToClipboardButton.addActionListener(actionEvent -> { + this.exportTextBox.requestFocus(); + this.exportTextBox.selectAll(); + Toolkit + .getDefaultToolkit() + .getSystemClipboard() + .setContents( + new StringSelection(this.exportTextBox.getText()), + null); + showNotificationOnComponent(this.exportToClipboardButton, "Copied to clipboard!", MessageType.INFO); // TODO: Resources + }); + + exportToFileButton.addActionListener(actionEvent -> { + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setDialogTitle("Specify a file to save"); // TODO: Resources + fileChooser.setSelectedFile(new File(this.layoutName + FILE_ENDING_WITH_DOT)); + fileChooser.setAcceptAllFileFilterUsed(false); + FileNameExtensionFilter filter = new FileNameExtensionFilter("Window layouts", FILE_ENDING); // TODO: Window layouts to constant + fileChooser.setFileFilter(filter); + + int userSelection = fileChooser.showSaveDialog(null); + + if (userSelection == JFileChooser.APPROVE_OPTION) { + File fileToSave = fileChooser.getSelectedFile(); + + byte[] encodedContent = this.content.getBytes(); + String fullPath = fileToSave.getAbsolutePath(); + if (!fullPath.toLowerCase().endsWith(FILE_ENDING_WITH_DOT)) { + fullPath += FILE_ENDING_WITH_DOT; + } + + Path path = Paths.get(fullPath); + try { + Files.write(path, encodedContent); + showNotificationOnComponent(this.exportToFileButton, "Saved to file " + path.getFileName().toString() +" !", MessageType.INFO); // TODO: Resources + } catch (IOException e) { + showNotificationOnComponent(this.exportToFileButton, "Failed to write export file: " + e.getMessage(), MessageType.ERROR); // TODO: Resources + } + } + }); + + this.layoutNameLabel.setText(layoutName); + this.exportTextBox.setText(content); + } + + // TODO: To library + private void showNotificationOnComponent(JComponent component, String message, MessageType type) { + JBPopupFactory.getInstance() + .createHtmlTextBalloonBuilder(message, type, null) + .setFadeoutTime(7500) + .createBalloon() + .show( + RelativePoint.getCenterOf(component), + Balloon.Position.above); + } + + public JPanel getPanel() { + return this.importPanel; + } +} diff --git a/src/main/java/com/layoutmanager/ui/settings/ImportDialog.form b/src/main/java/com/layoutmanager/ui/settings/ImportDialog.form new file mode 100644 index 0000000..c85c851 --- /dev/null +++ b/src/main/java/com/layoutmanager/ui/settings/ImportDialog.form @@ -0,0 +1,153 @@ + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    diff --git a/src/main/java/com/layoutmanager/ui/settings/ImportDialog.java b/src/main/java/com/layoutmanager/ui/settings/ImportDialog.java new file mode 100644 index 0000000..6af2056 --- /dev/null +++ b/src/main/java/com/layoutmanager/ui/settings/ImportDialog.java @@ -0,0 +1,131 @@ +package com.layoutmanager.ui.settings; + +import blazing.chain.LZSEncoding; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.layoutmanager.persistence.Layout; + +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import java.awt.*; +import java.awt.datatransfer.DataFlavor; +import java.awt.event.*; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; + +// TODO: +// Name as textbox -> possible to edit +// Nicer UI +public class ImportDialog extends JDialog { + public static final int OK_RESULT = 1; + public static final int ABORT_RESULT = 0; + + private JPanel contentPane; + private JButton importButton; + private JButton abortButton; + private JButton fileButton; + private JButton importFromClipboard; + private JLabel layoutNameLabel; + private JLabel layoutConfiguredWindowCountLabel; + + private Layout importedLayout; + private int result; + + public ImportDialog() { + setContentPane(contentPane); + setModal(true); + getRootPane().setDefaultButton(importButton); + + importButton.addActionListener(e -> onOK()); + + abortButton.addActionListener(e -> onCancel()); + + // call onCancel() when cross is clicked + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + onCancel(); + } + }); + + // call onCancel() on ESCAPE + contentPane.registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + + importFromClipboard.addActionListener(actionEvent -> { + try { + String lzEncodedContent = (String) Toolkit + .getDefaultToolkit() + .getSystemClipboard() + .getData(DataFlavor.stringFlavor); + + importLayout(lzEncodedContent); + } catch (Exception e) { + // TODO: Show + } + }); + + fileButton.addActionListener(actionEvent -> { + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setDialogTitle("Select layout file"); // TODO: Resources + fileChooser.setAcceptAllFileFilterUsed(false); + FileNameExtensionFilter filter = new FileNameExtensionFilter("Window layouts", ExportPage.FILE_ENDING); // TODO: Window layouts is also a constant, which must be shared... + fileChooser.setFileFilter(filter); + + int result = fileChooser.showOpenDialog(null); + if (result == JFileChooser.APPROVE_OPTION && + fileChooser.getSelectedFile().exists()) { + + try { + String lzEncodedContent = new String(Files.readAllBytes(Paths.get(fileChooser.getSelectedFile().getPath())), StandardCharsets.UTF_8); + importLayout(lzEncodedContent); + } catch (IOException e) { + // TODO: handle + e.printStackTrace(); + } + } + }); + } + + public int showDialogInCenterOf(JDialog parent) { + this.setSize(this.getPreferredSize()); + this.setLocationRelativeTo(parent); + this.setVisible(true); + return result; + } + + private void onOK() { + this.result = OK_RESULT; + dispose(); + } + + private void onCancel() { + this.result = ABORT_RESULT; + dispose(); + } + + private void importLayout(String lzEncodedContent) { + String jsonContent = LZSEncoding.decompressFromBase64(lzEncodedContent); + Gson gson = new GsonBuilder().create(); + Layout selectedLayout = gson.fromJson(jsonContent, Layout.class); + + selectLayout(selectedLayout); + + // TODO: Show notification + } + + private void selectLayout(Layout layout) { + this.importedLayout = layout; + + // TODO: Extract to method + this.layoutNameLabel.setText(this.importedLayout.getName()); + this.layoutConfiguredWindowCountLabel.setText(Integer.toString(this.importedLayout.getToolWindows().length)); + + this.importButton.setEnabled(true); + } + + public Layout getImportedLayout() { + return this.importedLayout; + } +} diff --git a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.form b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.form index ce2a650..e01fd92 100644 --- a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.form +++ b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.form @@ -1,6 +1,6 @@
    - + @@ -8,7 +8,7 @@ - + @@ -24,78 +24,18 @@ - - - - - - - - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -106,7 +46,7 @@ - + @@ -117,6 +57,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java index 033d39c..7d4415b 100644 --- a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java +++ b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java @@ -1,29 +1,27 @@ package com.layoutmanager.ui.settings; +import blazing.chain.LZSEncoding; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import com.intellij.openapi.components.ServiceManager; -import com.intellij.uiDesigner.core.GridConstraints; -import com.intellij.uiDesigner.core.GridLayoutManager; -import com.intellij.uiDesigner.core.Spacer; import com.layoutmanager.persistence.Layout; import com.layoutmanager.persistence.LayoutConfig; import com.layoutmanager.ui.dialogs.LayoutNameDialog; import com.layoutmanager.ui.menu.WindowMenuService; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.TableModelEvent; import javax.swing.table.DefaultTableModel; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.EventObject; public class LayoutManagerSettingsPanel { private final LayoutConfig layoutConfig; private final LayoutNameDialog layoutNameDialog; + private ArrayList currentLayouts = new ArrayList<>(); private JCheckBox useSmartDockingCheckbox; private JButton deleteButton; @@ -31,14 +29,7 @@ public class LayoutManagerSettingsPanel { private JButton exportButton; private JButton importButton; private JPanel settingsPanel; - private JTable tableLayouts; - - { -// GUI initializer generated by IntelliJ IDEA GUI Designer -// >>> IMPORTANT!! <<< -// DO NOT EDIT OR ADD ANY CODE HERE! - $$$setupUI$$$(); - } + private JTable layoutsTable; public LayoutManagerSettingsPanel( LayoutConfig layoutConfig, @@ -49,35 +40,75 @@ public LayoutManagerSettingsPanel( Collections.addAll(this.currentLayouts, layoutConfig.getLayouts()); DefaultTableModel table = createTableContent(); - this.tableLayouts.setModel(table); - this.tableLayouts.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + this.layoutsTable.setModel(table); + this.layoutsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); useSmartDockingCheckbox.setSelected(layoutConfig.getSettings().getUseSmartDock()); - this.tableLayouts.getSelectionModel().addListSelectionListener(listSelectionEvent -> { - deleteButton.setEnabled(this.tableLayouts.getSelectedRow() >= 0); - renameButton.setEnabled(this.tableLayouts.getSelectedRow() >= 0); + this.layoutsTable.getSelectionModel().addListSelectionListener(listSelectionEvent -> { + deleteButton.setEnabled(this.layoutsTable.getSelectedRow() >= 0); + renameButton.setEnabled(this.layoutsTable.getSelectedRow() >= 0); + exportButton.setEnabled(this.layoutsTable.getSelectedRow() >= 0); }); - this.deleteButton.addActionListener(e -> - ((DefaultTableModel)this.tableLayouts.getModel()) - .removeRow(this.tableLayouts.getSelectedRow())); + ((DefaultTableModel)this.layoutsTable.getModel()) + .removeRow(this.layoutsTable.getSelectedRow())); this.renameButton.addActionListener(e -> { - int selectedRow = this.tableLayouts.getSelectedRow(); + int selectedRow = this.layoutsTable.getSelectedRow(); String newName = this.layoutNameDialog.show(this.currentLayouts.get(selectedRow).getName()); + if (newName != null) { - this.tableLayouts.setValueAt(newName, selectedRow, 0); + this.layoutsTable.setValueAt(newName, selectedRow, 0); + } + }); + + exportButton.addActionListener(actionEvent -> { + int selectedRow = this.layoutsTable.getSelectedRow(); + Layout selectedLayout = this.currentLayouts.get(selectedRow); + + // TODO: Extract to class + Gson gson = new GsonBuilder().create(); + String jsonContent = gson.toJson(selectedLayout); + String lzEncodedContent = LZSEncoding.compressToBase64(jsonContent); + + ExportPage exportPage = new ExportPage(selectedLayout.getName(), lzEncodedContent); + + showDialog(exportPage.getPanel()); + + }); + + importButton.addActionListener(actionEvent -> { + ImportDialog importDialog = new ImportDialog(); + JDialog parent = getParentDialog(); + if (importDialog.showDialogInCenterOf(parent) == ImportDialog.OK_RESULT) { + this.currentLayouts.add(importDialog.getImportedLayout()); + ((DefaultTableModel)layoutsTable.getModel()).fireTableDataChanged(); } }); } + private void showDialog(JComponent component) { + // TODO: Extract to class + JDialog parent = getParentDialog(); + final JDialog dialog = new JDialog(parent, "Export layout", true); // TODO: Resources + dialog.getContentPane().add(component); + dialog.pack(); + dialog.setLocationRelativeTo(parent); + dialog.setVisible(true); + } + + @Nullable + private JDialog getParentDialog() { + return (JDialog) SwingUtilities.getAncestorOfClass(JDialog.class, this.settingsPanel); + } + public boolean hasChanged() { return this.useSmartDockingCheckbox.isSelected() != this.layoutConfig.getSettings().getUseSmartDock() || - !Arrays.equals( - this.layoutConfig.getLayouts(), - this.currentLayouts - .stream() - .toArray(Layout[]::new)); + !Arrays.equals( + this.layoutConfig.getLayouts(), + this.currentLayouts + .stream() + .toArray(Layout[]::new)); } public void apply() { @@ -136,63 +167,4 @@ public Object getValueAt(int row, int column) { public JPanel getPanel() { return this.settingsPanel; } - - /** - * Method generated by IntelliJ IDEA GUI Designer - * >>> IMPORTANT!! <<< - * DO NOT edit this method OR call it in your code! - * - * @noinspection ALL - */ - private void $$$setupUI$$$() { - settingsPanel = new JPanel(); - settingsPanel.setLayout(new GridLayoutManager(5, 1, new Insets(0, 0, 0, 0), -1, -1)); - final JLabel label1 = new JLabel(); - label1.setText("Docking"); - settingsPanel.add(label1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); - useSmartDockingCheckbox = new JCheckBox(); - useSmartDockingCheckbox.setText("Use smart docking when storing a layout"); - settingsPanel.add(useSmartDockingCheckbox, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); - final JLabel label2 = new JLabel(); - label2.setText("Layouts"); - settingsPanel.add(label2, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); - tableLayouts = new JTable(); - settingsPanel.add(tableLayouts, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_WANT_GROW, null, new Dimension(150, 50), null, 0, false)); - final JPanel panel1 = new JPanel(); - panel1.setLayout(new GridLayoutManager(1, 5, new Insets(0, 0, 0, 0), -1, -1)); - settingsPanel.add(panel1, new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); - deleteButton = new JButton(); - deleteButton.setEnabled(false); - deleteButton.setText("Delete"); - deleteButton.setMnemonic('D'); - deleteButton.setDisplayedMnemonicIndex(0); - panel1.add(deleteButton, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); - renameButton = new JButton(); - renameButton.setEnabled(false); - renameButton.setText("Rename"); - renameButton.setMnemonic('R'); - renameButton.setDisplayedMnemonicIndex(0); - panel1.add(renameButton, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); - exportButton = new JButton(); - exportButton.setEnabled(false); - exportButton.setText("Export"); - exportButton.setMnemonic('E'); - exportButton.setDisplayedMnemonicIndex(0); - panel1.add(exportButton, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); - importButton = new JButton(); - importButton.setEnabled(false); - importButton.setText("Import"); - importButton.setMnemonic('I'); - importButton.setDisplayedMnemonicIndex(0); - panel1.add(importButton, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); - final Spacer spacer1 = new Spacer(); - panel1.add(spacer1, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false)); - } - - /** - * @noinspection ALL - */ - public JComponent $$$getRootComponent$$$() { - return settingsPanel; - } } From a94ebc57ecf6deb694f41e87fc5d2d79911c5efc Mon Sep 17 00:00:00 2001 From: Michael Estermann <14977799+michaelestermann@users.noreply.github.com> Date: Thu, 23 Apr 2020 16:01:43 +0200 Subject: [PATCH 12/19] Moved messages to resources. --- .../layoutmanager/ui/settings/ExportPage.java | 21 ++++++------ .../ui/settings/ImportDialog.java | 13 ++++---- .../ui/settings/ImportExportConstants.java | 9 ++++++ .../settings/LayoutManagerSettingsPanel.java | 32 +++++++++++-------- .../ui/settings/SettingsPage.java | 3 +- .../com/layoutmanager/ui/messages.properties | 11 +++++++ 6 files changed, 57 insertions(+), 32 deletions(-) create mode 100644 src/main/java/com/layoutmanager/ui/settings/ImportExportConstants.java diff --git a/src/main/java/com/layoutmanager/ui/settings/ExportPage.java b/src/main/java/com/layoutmanager/ui/settings/ExportPage.java index 686cd9c..cb70ef7 100644 --- a/src/main/java/com/layoutmanager/ui/settings/ExportPage.java +++ b/src/main/java/com/layoutmanager/ui/settings/ExportPage.java @@ -4,6 +4,7 @@ import com.intellij.openapi.ui.popup.Balloon; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.ui.awt.RelativePoint; +import com.layoutmanager.localization.MessagesHelper; import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; @@ -17,10 +18,6 @@ // TODO: Change to dialog and cleanup public class ExportPage { - // TODO: Move to common class - public static final String FILE_ENDING = "wl"; - public static final String FILE_ENDING_WITH_DOT = "." + FILE_ENDING; - private JTextArea exportTextBox; private JPanel importPanel; private JButton exportToFileButton; @@ -49,15 +46,15 @@ public ExportPage(String layoutName, String content) { .setContents( new StringSelection(this.exportTextBox.getText()), null); - showNotificationOnComponent(this.exportToClipboardButton, "Copied to clipboard!", MessageType.INFO); // TODO: Resources + showNotificationOnComponent(this.exportToClipboardButton, MessagesHelper.message("ExportPage.CopiedToClipboard"), MessageType.INFO); }); exportToFileButton.addActionListener(actionEvent -> { JFileChooser fileChooser = new JFileChooser(); - fileChooser.setDialogTitle("Specify a file to save"); // TODO: Resources - fileChooser.setSelectedFile(new File(this.layoutName + FILE_ENDING_WITH_DOT)); + fileChooser.setDialogTitle(MessagesHelper.message("ExportPage.SaveFileTitle")); + fileChooser.setSelectedFile(new File(this.layoutName + ImportExportConstants.FILE_ENDING_WITH_DOT)); fileChooser.setAcceptAllFileFilterUsed(false); - FileNameExtensionFilter filter = new FileNameExtensionFilter("Window layouts", FILE_ENDING); // TODO: Window layouts to constant + FileNameExtensionFilter filter = new FileNameExtensionFilter(ImportExportConstants.FILE_TYPE_NAME, ImportExportConstants.FILE_ENDING); fileChooser.setFileFilter(filter); int userSelection = fileChooser.showSaveDialog(null); @@ -67,16 +64,16 @@ public ExportPage(String layoutName, String content) { byte[] encodedContent = this.content.getBytes(); String fullPath = fileToSave.getAbsolutePath(); - if (!fullPath.toLowerCase().endsWith(FILE_ENDING_WITH_DOT)) { - fullPath += FILE_ENDING_WITH_DOT; + if (!fullPath.toLowerCase().endsWith(ImportExportConstants.FILE_ENDING_WITH_DOT)) { + fullPath += ImportExportConstants.FILE_ENDING_WITH_DOT; } Path path = Paths.get(fullPath); try { Files.write(path, encodedContent); - showNotificationOnComponent(this.exportToFileButton, "Saved to file " + path.getFileName().toString() +" !", MessageType.INFO); // TODO: Resources + showNotificationOnComponent(this.exportToFileButton, MessagesHelper.message("ExportPage.SavedTo", path.getFileName().toString()), MessageType.INFO); } catch (IOException e) { - showNotificationOnComponent(this.exportToFileButton, "Failed to write export file: " + e.getMessage(), MessageType.ERROR); // TODO: Resources + showNotificationOnComponent(this.exportToFileButton, MessagesHelper.message("ExportPage.FailedToWriteFile", e.getMessage()), MessageType.ERROR); } } }); diff --git a/src/main/java/com/layoutmanager/ui/settings/ImportDialog.java b/src/main/java/com/layoutmanager/ui/settings/ImportDialog.java index 6af2056..1b9fbbc 100644 --- a/src/main/java/com/layoutmanager/ui/settings/ImportDialog.java +++ b/src/main/java/com/layoutmanager/ui/settings/ImportDialog.java @@ -3,6 +3,7 @@ import blazing.chain.LZSEncoding; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.layoutmanager.localization.MessagesHelper; import com.layoutmanager.persistence.Layout; import javax.swing.*; @@ -68,9 +69,9 @@ public void windowClosing(WindowEvent e) { fileButton.addActionListener(actionEvent -> { JFileChooser fileChooser = new JFileChooser(); - fileChooser.setDialogTitle("Select layout file"); // TODO: Resources + fileChooser.setDialogTitle(MessagesHelper.message("ImportDialog.SelectFileTitle")); fileChooser.setAcceptAllFileFilterUsed(false); - FileNameExtensionFilter filter = new FileNameExtensionFilter("Window layouts", ExportPage.FILE_ENDING); // TODO: Window layouts is also a constant, which must be shared... + FileNameExtensionFilter filter = new FileNameExtensionFilter(ImportExportConstants.FILE_TYPE_NAME, ImportExportConstants.FILE_ENDING); fileChooser.setFileFilter(filter); int result = fileChooser.showOpenDialog(null); @@ -88,6 +89,10 @@ public void windowClosing(WindowEvent e) { }); } + public Layout getImportedLayout() { + return this.importedLayout; + } + public int showDialogInCenterOf(JDialog parent) { this.setSize(this.getPreferredSize()); this.setLocationRelativeTo(parent); @@ -124,8 +129,4 @@ private void selectLayout(Layout layout) { this.importButton.setEnabled(true); } - - public Layout getImportedLayout() { - return this.importedLayout; - } } diff --git a/src/main/java/com/layoutmanager/ui/settings/ImportExportConstants.java b/src/main/java/com/layoutmanager/ui/settings/ImportExportConstants.java new file mode 100644 index 0000000..9800e6e --- /dev/null +++ b/src/main/java/com/layoutmanager/ui/settings/ImportExportConstants.java @@ -0,0 +1,9 @@ +package com.layoutmanager.ui.settings; + +public class ImportExportConstants { + public static final String FILE_ENDING = "wl"; + public static final String FILE_ENDING_WITH_DOT = "." + FILE_ENDING; + + + public static final String FILE_TYPE_NAME = "Window layouts"; +} diff --git a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java index 7d4415b..b21afc5 100644 --- a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java +++ b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java @@ -4,6 +4,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.intellij.openapi.components.ServiceManager; +import com.layoutmanager.localization.MessagesHelper; import com.layoutmanager.persistence.Layout; import com.layoutmanager.persistence.LayoutConfig; import com.layoutmanager.ui.dialogs.LayoutNameDialog; @@ -51,8 +52,8 @@ public LayoutManagerSettingsPanel( exportButton.setEnabled(this.layoutsTable.getSelectedRow() >= 0); }); this.deleteButton.addActionListener(e -> - ((DefaultTableModel)this.layoutsTable.getModel()) - .removeRow(this.layoutsTable.getSelectedRow())); + ((DefaultTableModel) this.layoutsTable.getModel()) + .removeRow(this.layoutsTable.getSelectedRow())); this.renameButton.addActionListener(e -> { int selectedRow = this.layoutsTable.getSelectedRow(); String newName = this.layoutNameDialog.show(this.currentLayouts.get(selectedRow).getName()); @@ -82,7 +83,7 @@ public LayoutManagerSettingsPanel( JDialog parent = getParentDialog(); if (importDialog.showDialogInCenterOf(parent) == ImportDialog.OK_RESULT) { this.currentLayouts.add(importDialog.getImportedLayout()); - ((DefaultTableModel)layoutsTable.getModel()).fireTableDataChanged(); + ((DefaultTableModel) layoutsTable.getModel()).fireTableDataChanged(); } }); } @@ -90,7 +91,7 @@ public LayoutManagerSettingsPanel( private void showDialog(JComponent component) { // TODO: Extract to class JDialog parent = getParentDialog(); - final JDialog dialog = new JDialog(parent, "Export layout", true); // TODO: Resources + final JDialog dialog = new JDialog(parent, MessagesHelper.message("ExportPage.Title"), true); // TODO: Resources dialog.getContentPane().add(component); dialog.pack(); dialog.setLocationRelativeTo(parent); @@ -104,18 +105,18 @@ private JDialog getParentDialog() { public boolean hasChanged() { return this.useSmartDockingCheckbox.isSelected() != this.layoutConfig.getSettings().getUseSmartDock() || - !Arrays.equals( - this.layoutConfig.getLayouts(), - this.currentLayouts - .stream() - .toArray(Layout[]::new)); + !Arrays.equals( + this.layoutConfig.getLayouts(), + this.currentLayouts + .stream() + .toArray(Layout[]::new)); } public void apply() { this.layoutConfig.getSettings().setUseSmartDock(this.useSmartDockingCheckbox.isSelected()); this.layoutConfig.setLayouts(this.currentLayouts - .stream() - .toArray(Layout[]::new)); + .stream() + .toArray(Layout[]::new)); WindowMenuService windowMenuService = ServiceManager.getService(WindowMenuService.class); windowMenuService.recreate(); @@ -123,7 +124,12 @@ public void apply() { @NotNull private DefaultTableModel createTableContent() { - DefaultTableModel model = new DefaultTableModel(new String[] { "Name", "Configured Windows" }, currentLayouts.size()) { + DefaultTableModel model = new DefaultTableModel( + new String[]{ + MessagesHelper.message("SettingsPage.NameColumn"), + MessagesHelper.message("SettingsPage.ConfiguredWindowsColumn") + }, + currentLayouts.size()) { @Override public boolean isCellEditable(int row, int column) { @@ -151,7 +157,7 @@ public void removeRow(int row) { public Object getValueAt(int row, int column) { Layout layout = currentLayouts.get(row); - switch(column) { + switch (column) { case 0: return layout.getName(); case 1: diff --git a/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java b/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java index 954f7af..55e934b 100644 --- a/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java +++ b/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java @@ -4,6 +4,7 @@ import javax.swing.JComponent; +import com.layoutmanager.localization.MessagesHelper; import com.layoutmanager.persistence.LayoutConfig; import com.layoutmanager.ui.dialogs.LayoutNameDialog; import org.jetbrains.annotations.Nls; @@ -19,7 +20,7 @@ public SettingsPage() { @Nls(capitalization = Nls.Capitalization.Title) @Override public String getDisplayName() { - return "Window Layout Manager"; + return MessagesHelper.message("SettingsPage.Title"); } @Nullable diff --git a/src/main/resources/com/layoutmanager/ui/messages.properties b/src/main/resources/com/layoutmanager/ui/messages.properties index d9e5cf8..34c9091 100644 --- a/src/main/resources/com/layoutmanager/ui/messages.properties +++ b/src/main/resources/com/layoutmanager/ui/messages.properties @@ -17,3 +17,14 @@ DeleteLayout.Menu=Delete Layout DeleteLayout.Notification.Title=Window layout deleted DeleteLayout.Notification.Content=The window layout ''{0}'' has been successfully deleted. +ExportPage.Title=Export layout +ExportPage.CopiedToClipboard=Copied to clipboard! +ExportPage.SaveFileTitle=Specify a file to save +ExportPage.SavedTo=Saved to file ''{0}'' ! +ExportPage.FailedToWriteFile=Failed to write export file: {0} + +SettingsPage.Title=Window Layout Manager +SettingsPage.NameColumn=Name +SettingsPage.ConfiguredWindowsColumn=Configured Windows + +ImportDialog.SelectFileTitle=Select layout file \ No newline at end of file From b79f50a93acb4f13ca0ca73c8876b3d7d40c67e7 Mon Sep 17 00:00:00 2001 From: Michael Estermann <14977799+michaelestermann@users.noreply.github.com> Date: Thu, 7 May 2020 17:10:58 +0200 Subject: [PATCH 13/19] Added multiple rider version in gradle configuration for fast exchange --- build.gradle | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index c459d6e..496ed6a 100644 --- a/build.gradle +++ b/build.gradle @@ -21,9 +21,15 @@ repositories { mavenCentral() } +// https://www.jetbrains.org/intellij/sdk/docs/reference_guide/intellij_artifacts.html +// https://www.jetbrains.com/intellij-repository/releases/ +// https://www.jetbrains.com/intellij-repository/snapshots/ intellij { type = 'RD' - version = "2020.1-SNAPSHOT" + version = "2020.2-SNAPSHOT" + // version = "2019.3.4" + // version = "2020.1.0" + // version = "2020.1-SNAPSHOT" updateSinceUntilBuild = false } From 14276d0e1831470fce82fe9e9874933619ca4bed Mon Sep 17 00:00:00 2001 From: Michael Estermann <14977799+michaelestermann@users.noreply.github.com> Date: Thu, 7 May 2020 17:11:25 +0200 Subject: [PATCH 14/19] Cleanup todos --- .../layout/delete/DeleteLayoutAction.java | 4 +- .../layout/restore/RestoreLayoutAction.java | 4 +- .../layout/store/LayoutCreator.java | 5 +- .../layout/store/create/NewLayoutAction.java | 4 +- .../overwrite/OverwriteLayoutAction.java | 4 +- .../ui/dialogs/LayoutNameDialog.java | 10 +- .../ui/dialogs/LayoutNameValidator.java | 11 + ...per.java => BaloonNotificationHelper.java} | 82 ++--- .../helpers/ComponentNotificationHelper.java | 29 ++ .../ui/menu/WindowMenuService.java | 3 +- .../ui/settings/ImportDialog.java | 132 -------- .../settings/LayoutManagerSettingsPanel.java | 108 ++++--- .../ui/settings/SettingsPage.java | 7 +- .../settings/{ => exporting}/ExportPage.form | 238 +++++++------- .../settings/{ => exporting}/ExportPage.java | 186 +++++------ .../{ => importing}/ImportDialog.form | 299 +++++++++--------- .../ui/settings/importing/ImportDialog.java | 155 +++++++++ .../com/layoutmanager/ui/messages.properties | 6 +- 18 files changed, 686 insertions(+), 601 deletions(-) create mode 100644 src/main/java/com/layoutmanager/ui/dialogs/LayoutNameValidator.java rename src/main/java/com/layoutmanager/ui/helpers/{NotificationHelper.java => BaloonNotificationHelper.java} (95%) create mode 100644 src/main/java/com/layoutmanager/ui/helpers/ComponentNotificationHelper.java delete mode 100644 src/main/java/com/layoutmanager/ui/settings/ImportDialog.java rename src/main/java/com/layoutmanager/ui/settings/{ => exporting}/ExportPage.form (96%) rename src/main/java/com/layoutmanager/ui/settings/{ => exporting}/ExportPage.java (69%) rename src/main/java/com/layoutmanager/ui/settings/{ => importing}/ImportDialog.form (70%) create mode 100644 src/main/java/com/layoutmanager/ui/settings/importing/ImportDialog.java diff --git a/src/main/java/com/layoutmanager/layout/delete/DeleteLayoutAction.java b/src/main/java/com/layoutmanager/layout/delete/DeleteLayoutAction.java index bd708a9..05791e9 100644 --- a/src/main/java/com/layoutmanager/layout/delete/DeleteLayoutAction.java +++ b/src/main/java/com/layoutmanager/layout/delete/DeleteLayoutAction.java @@ -9,7 +9,7 @@ import com.layoutmanager.localization.MessagesHelper; import com.layoutmanager.persistence.Layout; import com.layoutmanager.persistence.LayoutConfig; -import com.layoutmanager.ui.helpers.NotificationHelper; +import com.layoutmanager.ui.helpers.BaloonNotificationHelper; import com.layoutmanager.ui.menu.WindowMenuService; import org.jetbrains.annotations.NotNull; @@ -38,7 +38,7 @@ private void deleteLayout() { } private void showNotification() { - NotificationHelper.info( + BaloonNotificationHelper.info( MessagesHelper.message("DeleteLayout.Notification.Title"), MessagesHelper.message("DeleteLayout.Notification.Content", this.layout.getName())); } diff --git a/src/main/java/com/layoutmanager/layout/restore/RestoreLayoutAction.java b/src/main/java/com/layoutmanager/layout/restore/RestoreLayoutAction.java index 5dd3a15..f4edbdf 100644 --- a/src/main/java/com/layoutmanager/layout/restore/RestoreLayoutAction.java +++ b/src/main/java/com/layoutmanager/layout/restore/RestoreLayoutAction.java @@ -13,7 +13,7 @@ import com.layoutmanager.localization.MessagesHelper; import com.layoutmanager.persistence.Layout; import com.layoutmanager.persistence.ToolWindowInfo; -import com.layoutmanager.ui.helpers.NotificationHelper; +import com.layoutmanager.ui.helpers.BaloonNotificationHelper; import com.layoutmanager.ui.helpers.ToolWindowHelper; import org.jetbrains.annotations.NotNull; @@ -104,7 +104,7 @@ private ToolWindowManager getToolWindowManager(AnActionEvent event) { } private void showNotification(Layout updatedLayout) { - NotificationHelper.info( + BaloonNotificationHelper.info( MessagesHelper.message("RestoreLayout.Notification.Title"), MessagesHelper.message("RestoreLayout.Notification.Content", updatedLayout.getName())); } diff --git a/src/main/java/com/layoutmanager/layout/store/LayoutCreator.java b/src/main/java/com/layoutmanager/layout/store/LayoutCreator.java index bf05f40..d9e64c7 100644 --- a/src/main/java/com/layoutmanager/layout/store/LayoutCreator.java +++ b/src/main/java/com/layoutmanager/layout/store/LayoutCreator.java @@ -8,11 +8,10 @@ import com.layoutmanager.layout.store.validation.LayoutValidationHelper; import com.layoutmanager.localization.MessagesHelper; import com.layoutmanager.persistence.Layout; -import com.layoutmanager.persistence.LayoutConfig; import com.layoutmanager.persistence.LayoutSettings; import com.layoutmanager.persistence.ToolWindowInfo; import com.layoutmanager.ui.dialogs.LayoutNameDialog; -import com.layoutmanager.ui.helpers.NotificationHelper; +import com.layoutmanager.ui.helpers.BaloonNotificationHelper; import com.layoutmanager.ui.helpers.ToolWindowHelper; import org.jetbrains.annotations.NotNull; @@ -94,7 +93,7 @@ private static void validateLayout(Layout layout) { .map(ToolWindowInfo::getId) .toArray(String[]::new)); - NotificationHelper.warning( + BaloonNotificationHelper.warning( MessagesHelper.message("StoreLayout.Validation.ToolWindowOutOfScreen.Title"), MessagesHelper.message("StoreLayout.Validation.ToolWindowOutOfScreen.Content", invalidToolWindowNames)); } diff --git a/src/main/java/com/layoutmanager/layout/store/create/NewLayoutAction.java b/src/main/java/com/layoutmanager/layout/store/create/NewLayoutAction.java index 99d6d9c..6159a9d 100644 --- a/src/main/java/com/layoutmanager/layout/store/create/NewLayoutAction.java +++ b/src/main/java/com/layoutmanager/layout/store/create/NewLayoutAction.java @@ -11,7 +11,7 @@ import com.layoutmanager.localization.MessagesHelper; import com.layoutmanager.persistence.Layout; import com.layoutmanager.persistence.LayoutConfig; -import com.layoutmanager.ui.helpers.NotificationHelper; +import com.layoutmanager.ui.helpers.BaloonNotificationHelper; import com.layoutmanager.ui.menu.WindowMenuService; import org.jetbrains.annotations.NotNull; @@ -49,7 +49,7 @@ private void updateWindowMenuItems() { } private void showNotification(Layout newLayout) { - NotificationHelper.info( + BaloonNotificationHelper.info( MessagesHelper.message("StoreLayout.New.Notification.Title"), MessagesHelper.message("StoreLayout.New.Notification.Content", newLayout.getName())); } diff --git a/src/main/java/com/layoutmanager/layout/store/overwrite/OverwriteLayoutAction.java b/src/main/java/com/layoutmanager/layout/store/overwrite/OverwriteLayoutAction.java index 8502b42..ea95769 100644 --- a/src/main/java/com/layoutmanager/layout/store/overwrite/OverwriteLayoutAction.java +++ b/src/main/java/com/layoutmanager/layout/store/overwrite/OverwriteLayoutAction.java @@ -11,7 +11,7 @@ import com.layoutmanager.localization.MessagesHelper; import com.layoutmanager.persistence.Layout; import com.layoutmanager.persistence.LayoutConfig; -import com.layoutmanager.ui.helpers.NotificationHelper; +import com.layoutmanager.ui.helpers.BaloonNotificationHelper; import com.layoutmanager.ui.menu.WindowMenuService; import org.jetbrains.annotations.NotNull; @@ -63,7 +63,7 @@ private void updateWindowMenuItems() { } private void showNotification(Layout updatedLayout, Layout previousLayout) { - NotificationHelper.info( + BaloonNotificationHelper.info( MessagesHelper.message("StoreLayout.Overwrite.Notification.Title"), MessagesHelper.message("StoreLayout.Overwrite.Notification.Content", previousLayout.getName(), updatedLayout.getName())); } diff --git a/src/main/java/com/layoutmanager/ui/dialogs/LayoutNameDialog.java b/src/main/java/com/layoutmanager/ui/dialogs/LayoutNameDialog.java index c36e4e0..3dee2e1 100644 --- a/src/main/java/com/layoutmanager/ui/dialogs/LayoutNameDialog.java +++ b/src/main/java/com/layoutmanager/ui/dialogs/LayoutNameDialog.java @@ -6,6 +6,13 @@ public class LayoutNameDialog { + private final LayoutNameValidator layoutNameValidator; + + public LayoutNameDialog(LayoutNameValidator layoutNameValidator) { + + this.layoutNameValidator = layoutNameValidator; + } + public String show(String defaultName) { String name; do { @@ -15,8 +22,9 @@ public String show(String defaultName) { AllIcons.Actions.Edit, defaultName, null); - } while (name != null && name.isEmpty()); + } while (!this.layoutNameValidator.isValid(name)); return name; } } + diff --git a/src/main/java/com/layoutmanager/ui/dialogs/LayoutNameValidator.java b/src/main/java/com/layoutmanager/ui/dialogs/LayoutNameValidator.java new file mode 100644 index 0000000..971d852 --- /dev/null +++ b/src/main/java/com/layoutmanager/ui/dialogs/LayoutNameValidator.java @@ -0,0 +1,11 @@ +package com.layoutmanager.ui.dialogs; + +public class LayoutNameValidator { + public Boolean isValid(String name) { + return name != null && !this.isBlank(name); + } + + private boolean isBlank(String name) { + return name.trim().length() == 0; + } +} diff --git a/src/main/java/com/layoutmanager/ui/helpers/NotificationHelper.java b/src/main/java/com/layoutmanager/ui/helpers/BaloonNotificationHelper.java similarity index 95% rename from src/main/java/com/layoutmanager/ui/helpers/NotificationHelper.java rename to src/main/java/com/layoutmanager/ui/helpers/BaloonNotificationHelper.java index f82743c..b2bf895 100644 --- a/src/main/java/com/layoutmanager/ui/helpers/NotificationHelper.java +++ b/src/main/java/com/layoutmanager/ui/helpers/BaloonNotificationHelper.java @@ -1,41 +1,41 @@ -package com.layoutmanager.ui.helpers; - -import com.intellij.notification.Notification; -import com.intellij.notification.NotificationDisplayType; -import com.intellij.notification.NotificationGroup; -import com.intellij.notification.NotificationType; -import com.intellij.notification.Notifications; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectManager; - -import java.util.Arrays; -import java.util.UUID; - -public class NotificationHelper { - private static final NotificationGroup DEFAULT_GROUP = - new NotificationGroup("demo.notifications.balloon", NotificationDisplayType.STICKY_BALLOON, true); - - public static void info(String title, String content) { - Notification notification = DEFAULT_GROUP.createNotification(title, null, content, NotificationType.INFORMATION); - notify(notification); - } - - public static void warning(String title, String content) { - String groupId = UUID.nameUUIDFromBytes(title.getBytes()).toString(); - NotificationGroup groupByNotificationTitle = new NotificationGroup(groupId, NotificationDisplayType.STICKY_BALLOON, true); - Notification notification = groupByNotificationTitle.createNotification(title, null, content, NotificationType.WARNING); - notify(notification); - } - - private static void notify(Notification notification) { - Project currentProject = getCurrentProject(); - Notifications.Bus.notify(notification, currentProject); - } - - private static Project getCurrentProject() { - Project[] openedProjects = ProjectManager.getInstance().getOpenProjects(); - return Arrays.stream(openedProjects) - .findFirst() - .orElse(null); - } -} +package com.layoutmanager.ui.helpers; + +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationDisplayType; +import com.intellij.notification.NotificationGroup; +import com.intellij.notification.NotificationType; +import com.intellij.notification.Notifications; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectManager; + +import java.util.Arrays; +import java.util.UUID; + +public class BaloonNotificationHelper { + private static final NotificationGroup DEFAULT_GROUP = + new NotificationGroup("demo.notifications.balloon", NotificationDisplayType.STICKY_BALLOON, true); + + public static void info(String title, String content) { + Notification notification = DEFAULT_GROUP.createNotification(title, null, content, NotificationType.INFORMATION); + notify(notification); + } + + public static void warning(String title, String content) { + String groupId = UUID.nameUUIDFromBytes(title.getBytes()).toString(); + NotificationGroup groupByNotificationTitle = new NotificationGroup(groupId, NotificationDisplayType.STICKY_BALLOON, true); + Notification notification = groupByNotificationTitle.createNotification(title, null, content, NotificationType.WARNING); + notify(notification); + } + + private static void notify(Notification notification) { + Project currentProject = getCurrentProject(); + Notifications.Bus.notify(notification, currentProject); + } + + private static Project getCurrentProject() { + Project[] openedProjects = ProjectManager.getInstance().getOpenProjects(); + return Arrays.stream(openedProjects) + .findFirst() + .orElse(null); + } +} diff --git a/src/main/java/com/layoutmanager/ui/helpers/ComponentNotificationHelper.java b/src/main/java/com/layoutmanager/ui/helpers/ComponentNotificationHelper.java new file mode 100644 index 0000000..7a58cf1 --- /dev/null +++ b/src/main/java/com/layoutmanager/ui/helpers/ComponentNotificationHelper.java @@ -0,0 +1,29 @@ +package com.layoutmanager.ui.helpers; + +import com.intellij.openapi.ui.MessageType; +import com.intellij.openapi.ui.popup.Balloon; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.ui.awt.RelativePoint; + +import javax.swing.*; + +public class ComponentNotificationHelper { + + public static void info(JComponent component, String message) { + show(component, message, MessageType.INFO); + } + + public static void error(JComponent component, String message) { + show(component, message, MessageType.ERROR); + } + + private static void show(JComponent component, String message, MessageType type) { + JBPopupFactory.getInstance() + .createHtmlTextBalloonBuilder(message, type, null) + .setFadeoutTime(7500) + .createBalloon() + .show( + RelativePoint.getCenterOf(component), + Balloon.Position.above); + } +} diff --git a/src/main/java/com/layoutmanager/ui/menu/WindowMenuService.java b/src/main/java/com/layoutmanager/ui/menu/WindowMenuService.java index 7398651..45787dd 100644 --- a/src/main/java/com/layoutmanager/ui/menu/WindowMenuService.java +++ b/src/main/java/com/layoutmanager/ui/menu/WindowMenuService.java @@ -13,6 +13,7 @@ import com.layoutmanager.persistence.Layout; import com.layoutmanager.persistence.LayoutConfig; import com.layoutmanager.ui.dialogs.LayoutNameDialog; +import com.layoutmanager.ui.dialogs.LayoutNameValidator; public class WindowMenuService { private DefaultActionGroup storeLayout; @@ -68,7 +69,7 @@ private void addStoreLayoutActions(LayoutConfig config) { LayoutCreator layoutCreator = new LayoutCreator( config.getSettings(), new SmartDockerFactory(), - new LayoutNameDialog()); + new LayoutNameDialog(new LayoutNameValidator())); for (int index = 0; index < config.getLayoutCount(); index++) { this.storeLayout.add(new OverwriteLayoutAction(layoutCreator, index)); diff --git a/src/main/java/com/layoutmanager/ui/settings/ImportDialog.java b/src/main/java/com/layoutmanager/ui/settings/ImportDialog.java deleted file mode 100644 index 1b9fbbc..0000000 --- a/src/main/java/com/layoutmanager/ui/settings/ImportDialog.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.layoutmanager.ui.settings; - -import blazing.chain.LZSEncoding; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.layoutmanager.localization.MessagesHelper; -import com.layoutmanager.persistence.Layout; - -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import java.awt.*; -import java.awt.datatransfer.DataFlavor; -import java.awt.event.*; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; - -// TODO: -// Name as textbox -> possible to edit -// Nicer UI -public class ImportDialog extends JDialog { - public static final int OK_RESULT = 1; - public static final int ABORT_RESULT = 0; - - private JPanel contentPane; - private JButton importButton; - private JButton abortButton; - private JButton fileButton; - private JButton importFromClipboard; - private JLabel layoutNameLabel; - private JLabel layoutConfiguredWindowCountLabel; - - private Layout importedLayout; - private int result; - - public ImportDialog() { - setContentPane(contentPane); - setModal(true); - getRootPane().setDefaultButton(importButton); - - importButton.addActionListener(e -> onOK()); - - abortButton.addActionListener(e -> onCancel()); - - // call onCancel() when cross is clicked - setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); - addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - onCancel(); - } - }); - - // call onCancel() on ESCAPE - contentPane.registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); - - importFromClipboard.addActionListener(actionEvent -> { - try { - String lzEncodedContent = (String) Toolkit - .getDefaultToolkit() - .getSystemClipboard() - .getData(DataFlavor.stringFlavor); - - importLayout(lzEncodedContent); - } catch (Exception e) { - // TODO: Show - } - }); - - fileButton.addActionListener(actionEvent -> { - JFileChooser fileChooser = new JFileChooser(); - fileChooser.setDialogTitle(MessagesHelper.message("ImportDialog.SelectFileTitle")); - fileChooser.setAcceptAllFileFilterUsed(false); - FileNameExtensionFilter filter = new FileNameExtensionFilter(ImportExportConstants.FILE_TYPE_NAME, ImportExportConstants.FILE_ENDING); - fileChooser.setFileFilter(filter); - - int result = fileChooser.showOpenDialog(null); - if (result == JFileChooser.APPROVE_OPTION && - fileChooser.getSelectedFile().exists()) { - - try { - String lzEncodedContent = new String(Files.readAllBytes(Paths.get(fileChooser.getSelectedFile().getPath())), StandardCharsets.UTF_8); - importLayout(lzEncodedContent); - } catch (IOException e) { - // TODO: handle - e.printStackTrace(); - } - } - }); - } - - public Layout getImportedLayout() { - return this.importedLayout; - } - - public int showDialogInCenterOf(JDialog parent) { - this.setSize(this.getPreferredSize()); - this.setLocationRelativeTo(parent); - this.setVisible(true); - return result; - } - - private void onOK() { - this.result = OK_RESULT; - dispose(); - } - - private void onCancel() { - this.result = ABORT_RESULT; - dispose(); - } - - private void importLayout(String lzEncodedContent) { - String jsonContent = LZSEncoding.decompressFromBase64(lzEncodedContent); - Gson gson = new GsonBuilder().create(); - Layout selectedLayout = gson.fromJson(jsonContent, Layout.class); - - selectLayout(selectedLayout); - - // TODO: Show notification - } - - private void selectLayout(Layout layout) { - this.importedLayout = layout; - - // TODO: Extract to method - this.layoutNameLabel.setText(this.importedLayout.getName()); - this.layoutConfiguredWindowCountLabel.setText(Integer.toString(this.importedLayout.getToolWindows().length)); - - this.importButton.setEnabled(true); - } -} diff --git a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java index b21afc5..17acadf 100644 --- a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java +++ b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java @@ -8,7 +8,11 @@ import com.layoutmanager.persistence.Layout; import com.layoutmanager.persistence.LayoutConfig; import com.layoutmanager.ui.dialogs.LayoutNameDialog; +import com.layoutmanager.ui.dialogs.LayoutNameValidator; +import com.layoutmanager.ui.helpers.ComponentNotificationHelper; import com.layoutmanager.ui.menu.WindowMenuService; +import com.layoutmanager.ui.settings.exporting.ExportPage; +import com.layoutmanager.ui.settings.importing.ImportDialog; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -22,6 +26,7 @@ public class LayoutManagerSettingsPanel { private final LayoutConfig layoutConfig; private final LayoutNameDialog layoutNameDialog; + private final LayoutNameValidator layoutNameValidator; private ArrayList currentLayouts = new ArrayList<>(); private JCheckBox useSmartDockingCheckbox; @@ -34,10 +39,22 @@ public class LayoutManagerSettingsPanel { public LayoutManagerSettingsPanel( LayoutConfig layoutConfig, - LayoutNameDialog layoutNameDialog) { + LayoutNameDialog layoutNameDialog, + LayoutNameValidator layoutNameValidator) { this.layoutConfig = layoutConfig; this.layoutNameDialog = layoutNameDialog; + this.layoutNameValidator = layoutNameValidator; + this.loadSettings(layoutConfig); + + this.layoutsTable.getSelectionModel().addListSelectionListener(listSelectionEvent -> this.selectedLayoutChanged()); + this.deleteButton.addActionListener(e -> this.deleteLayout()); + this.renameButton.addActionListener(e -> this.renameLayout()); + this.exportButton.addActionListener(actionEvent -> this.exportLayout()); + this.importButton.addActionListener(actionEvent -> this.importLayout()); + } + + private void loadSettings(LayoutConfig layoutConfig) { Collections.addAll(this.currentLayouts, layoutConfig.getLayouts()); DefaultTableModel table = createTableContent(); @@ -45,53 +62,55 @@ public LayoutManagerSettingsPanel( this.layoutsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); useSmartDockingCheckbox.setSelected(layoutConfig.getSettings().getUseSmartDock()); + } - this.layoutsTable.getSelectionModel().addListSelectionListener(listSelectionEvent -> { - deleteButton.setEnabled(this.layoutsTable.getSelectedRow() >= 0); - renameButton.setEnabled(this.layoutsTable.getSelectedRow() >= 0); - exportButton.setEnabled(this.layoutsTable.getSelectedRow() >= 0); - }); - this.deleteButton.addActionListener(e -> - ((DefaultTableModel) this.layoutsTable.getModel()) - .removeRow(this.layoutsTable.getSelectedRow())); - this.renameButton.addActionListener(e -> { - int selectedRow = this.layoutsTable.getSelectedRow(); - String newName = this.layoutNameDialog.show(this.currentLayouts.get(selectedRow).getName()); - - if (newName != null) { - this.layoutsTable.setValueAt(newName, selectedRow, 0); - } - }); + private void selectedLayoutChanged() { + deleteButton.setEnabled(this.layoutsTable.getSelectedRow() >= 0); + renameButton.setEnabled(this.layoutsTable.getSelectedRow() >= 0); + exportButton.setEnabled(this.layoutsTable.getSelectedRow() >= 0); + } - exportButton.addActionListener(actionEvent -> { - int selectedRow = this.layoutsTable.getSelectedRow(); - Layout selectedLayout = this.currentLayouts.get(selectedRow); + private void deleteLayout() { + DefaultTableModel table = (DefaultTableModel)this.layoutsTable.getModel(); + table.removeRow(this.layoutsTable.getSelectedRow()); + } + + private void renameLayout() { + int selectedRow = this.layoutsTable.getSelectedRow(); + String newName = this.layoutNameDialog.show(this.currentLayouts.get(selectedRow).getName()); - // TODO: Extract to class - Gson gson = new GsonBuilder().create(); - String jsonContent = gson.toJson(selectedLayout); - String lzEncodedContent = LZSEncoding.compressToBase64(jsonContent); + if (newName != null) { + this.layoutsTable.setValueAt(newName, selectedRow, 0); + } + } - ExportPage exportPage = new ExportPage(selectedLayout.getName(), lzEncodedContent); + private void exportLayout() { + int selectedRow = this.layoutsTable.getSelectedRow(); + Layout selectedLayout = this.currentLayouts.get(selectedRow); - showDialog(exportPage.getPanel()); + // TODO: Extract to class + Gson gson = new GsonBuilder().create(); + String jsonContent = gson.toJson(selectedLayout); + String lzEncodedContent = LZSEncoding.compressToBase64(jsonContent); - }); + ExportPage exportPage = new ExportPage(selectedLayout.getName(), lzEncodedContent); - importButton.addActionListener(actionEvent -> { - ImportDialog importDialog = new ImportDialog(); - JDialog parent = getParentDialog(); - if (importDialog.showDialogInCenterOf(parent) == ImportDialog.OK_RESULT) { - this.currentLayouts.add(importDialog.getImportedLayout()); - ((DefaultTableModel) layoutsTable.getModel()).fireTableDataChanged(); - } - }); + showDialog(exportPage.getPanel()); + } + + private void importLayout() { + ImportDialog importDialog = new ImportDialog(this.layoutNameValidator); + JDialog parent = getParentDialog(); + if (importDialog.showDialogInCenterOf(parent) == ImportDialog.OK_RESULT) { + this.currentLayouts.add(importDialog.getImportedLayout()); + ((DefaultTableModel) layoutsTable.getModel()).fireTableDataChanged(); + } } private void showDialog(JComponent component) { // TODO: Extract to class JDialog parent = getParentDialog(); - final JDialog dialog = new JDialog(parent, MessagesHelper.message("ExportPage.Title"), true); // TODO: Resources + final JDialog dialog = new JDialog(parent, MessagesHelper.message("ExportPage.Title"), true); dialog.getContentPane().add(component); dialog.pack(); dialog.setLocationRelativeTo(parent); @@ -122,6 +141,10 @@ public void apply() { windowMenuService.recreate(); } + public JPanel getPanel() { + return this.settingsPanel; + } + @NotNull private DefaultTableModel createTableContent() { DefaultTableModel model = new DefaultTableModel( @@ -138,8 +161,13 @@ public boolean isCellEditable(int row, int column) { @Override public void setValueAt(Object aValue, int row, int column) { - currentLayouts.get(row).setName(aValue.toString()); - this.fireTableChanged(new TableModelEvent(this, row)); + String newLayoutName = aValue.toString(); + if (layoutNameValidator.isValid(newLayoutName)) { + currentLayouts.get(row).setName(aValue.toString()); + this.fireTableChanged(new TableModelEvent(this, row)); + } else { + ComponentNotificationHelper.error(layoutsTable, MessagesHelper.message("LayoutNameValidation.InvalidName")); + } } @Override @@ -169,8 +197,4 @@ public Object getValueAt(int row, int column) { return model; } - - public JPanel getPanel() { - return this.settingsPanel; - } } diff --git a/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java b/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java index 55e934b..c5429f2 100644 --- a/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java +++ b/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java @@ -7,6 +7,7 @@ import com.layoutmanager.localization.MessagesHelper; import com.layoutmanager.persistence.LayoutConfig; import com.layoutmanager.ui.dialogs.LayoutNameDialog; +import com.layoutmanager.ui.dialogs.LayoutNameValidator; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.Nullable; @@ -14,7 +15,11 @@ public class SettingsPage implements Configurable { private final LayoutManagerSettingsPanel panel; public SettingsPage() { - this.panel = new LayoutManagerSettingsPanel(LayoutConfig.getInstance(), new LayoutNameDialog()); + LayoutNameValidator layoutNameValidator = new LayoutNameValidator(); + this.panel = new LayoutManagerSettingsPanel( + LayoutConfig.getInstance(), + new LayoutNameDialog(layoutNameValidator), + layoutNameValidator); } @Nls(capitalization = Nls.Capitalization.Title) diff --git a/src/main/java/com/layoutmanager/ui/settings/ExportPage.form b/src/main/java/com/layoutmanager/ui/settings/exporting/ExportPage.form similarity index 96% rename from src/main/java/com/layoutmanager/ui/settings/ExportPage.form rename to src/main/java/com/layoutmanager/ui/settings/exporting/ExportPage.form index 6bafed1..4e4d79c 100644 --- a/src/main/java/com/layoutmanager/ui/settings/ExportPage.form +++ b/src/main/java/com/layoutmanager/ui/settings/exporting/ExportPage.form @@ -1,119 +1,119 @@ - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    diff --git a/src/main/java/com/layoutmanager/ui/settings/ExportPage.java b/src/main/java/com/layoutmanager/ui/settings/exporting/ExportPage.java similarity index 69% rename from src/main/java/com/layoutmanager/ui/settings/ExportPage.java rename to src/main/java/com/layoutmanager/ui/settings/exporting/ExportPage.java index cb70ef7..4e27ee3 100644 --- a/src/main/java/com/layoutmanager/ui/settings/ExportPage.java +++ b/src/main/java/com/layoutmanager/ui/settings/exporting/ExportPage.java @@ -1,99 +1,87 @@ -package com.layoutmanager.ui.settings; - -import com.intellij.openapi.ui.MessageType; -import com.intellij.openapi.ui.popup.Balloon; -import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.ui.awt.RelativePoint; -import com.layoutmanager.localization.MessagesHelper; - -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import java.awt.*; -import java.awt.datatransfer.StringSelection; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -// TODO: Change to dialog and cleanup -public class ExportPage { - private JTextArea exportTextBox; - private JPanel importPanel; - private JButton exportToFileButton; - private JButton exportToClipboardButton; - private JButton closeButton; - private JLabel layoutNameLabel; - - private String layoutName; - private String content; - - public ExportPage(String layoutName, String content) { - this.layoutName = layoutName; - this.content = content; - - closeButton.addActionListener(actionEvent -> { - JDialog window = (JDialog) SwingUtilities.getAncestorOfClass(JDialog.class, this.importPanel); - window.dispose(); - }); - - exportToClipboardButton.addActionListener(actionEvent -> { - this.exportTextBox.requestFocus(); - this.exportTextBox.selectAll(); - Toolkit - .getDefaultToolkit() - .getSystemClipboard() - .setContents( - new StringSelection(this.exportTextBox.getText()), - null); - showNotificationOnComponent(this.exportToClipboardButton, MessagesHelper.message("ExportPage.CopiedToClipboard"), MessageType.INFO); - }); - - exportToFileButton.addActionListener(actionEvent -> { - JFileChooser fileChooser = new JFileChooser(); - fileChooser.setDialogTitle(MessagesHelper.message("ExportPage.SaveFileTitle")); - fileChooser.setSelectedFile(new File(this.layoutName + ImportExportConstants.FILE_ENDING_WITH_DOT)); - fileChooser.setAcceptAllFileFilterUsed(false); - FileNameExtensionFilter filter = new FileNameExtensionFilter(ImportExportConstants.FILE_TYPE_NAME, ImportExportConstants.FILE_ENDING); - fileChooser.setFileFilter(filter); - - int userSelection = fileChooser.showSaveDialog(null); - - if (userSelection == JFileChooser.APPROVE_OPTION) { - File fileToSave = fileChooser.getSelectedFile(); - - byte[] encodedContent = this.content.getBytes(); - String fullPath = fileToSave.getAbsolutePath(); - if (!fullPath.toLowerCase().endsWith(ImportExportConstants.FILE_ENDING_WITH_DOT)) { - fullPath += ImportExportConstants.FILE_ENDING_WITH_DOT; - } - - Path path = Paths.get(fullPath); - try { - Files.write(path, encodedContent); - showNotificationOnComponent(this.exportToFileButton, MessagesHelper.message("ExportPage.SavedTo", path.getFileName().toString()), MessageType.INFO); - } catch (IOException e) { - showNotificationOnComponent(this.exportToFileButton, MessagesHelper.message("ExportPage.FailedToWriteFile", e.getMessage()), MessageType.ERROR); - } - } - }); - - this.layoutNameLabel.setText(layoutName); - this.exportTextBox.setText(content); - } - - // TODO: To library - private void showNotificationOnComponent(JComponent component, String message, MessageType type) { - JBPopupFactory.getInstance() - .createHtmlTextBalloonBuilder(message, type, null) - .setFadeoutTime(7500) - .createBalloon() - .show( - RelativePoint.getCenterOf(component), - Balloon.Position.above); - } - - public JPanel getPanel() { - return this.importPanel; - } -} +package com.layoutmanager.ui.settings.exporting; + +import com.layoutmanager.localization.MessagesHelper; +import com.layoutmanager.ui.helpers.ComponentNotificationHelper; +import com.layoutmanager.ui.settings.ImportExportConstants; + +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import java.awt.*; +import java.awt.datatransfer.StringSelection; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +// TODO: Change to dialog and cleanup +public class ExportPage { + private JTextArea exportTextBox; + private JPanel importPanel; + private JButton exportToFileButton; + private JButton exportToClipboardButton; + private JButton closeButton; + private JLabel layoutNameLabel; + + private String layoutName; + private String content; + + // TODO: Move to own methods + public ExportPage(String layoutName, String content) { + this.layoutName = layoutName; + this.content = content; + + closeButton.addActionListener(actionEvent -> { + JDialog window = (JDialog) SwingUtilities.getAncestorOfClass(JDialog.class, this.importPanel); + window.dispose(); + }); + + exportToClipboardButton.addActionListener(actionEvent -> { + this.exportTextBox.requestFocus(); + this.exportTextBox.selectAll(); + Toolkit + .getDefaultToolkit() + .getSystemClipboard() + .setContents( + new StringSelection(this.exportTextBox.getText()), + null); + ComponentNotificationHelper.info(this.exportToClipboardButton, MessagesHelper.message("ExportPage.CopiedToClipboard")); + }); + + exportToFileButton.addActionListener(actionEvent -> { + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setDialogTitle(MessagesHelper.message("ExportPage.SaveFileTitle")); + fileChooser.setSelectedFile(new File(this.layoutName + ImportExportConstants.FILE_ENDING_WITH_DOT)); + fileChooser.setAcceptAllFileFilterUsed(false); + FileNameExtensionFilter filter = new FileNameExtensionFilter(ImportExportConstants.FILE_TYPE_NAME, ImportExportConstants.FILE_ENDING); + fileChooser.setFileFilter(filter); + + int userSelection = fileChooser.showSaveDialog(null); + + if (userSelection == JFileChooser.APPROVE_OPTION) { + File fileToSave = fileChooser.getSelectedFile(); + + byte[] encodedContent = this.content.getBytes(); + String fullPath = fileToSave.getAbsolutePath(); + if (!fullPath.toLowerCase().endsWith(ImportExportConstants.FILE_ENDING_WITH_DOT)) { + fullPath += ImportExportConstants.FILE_ENDING_WITH_DOT; + } + + Path path = Paths.get(fullPath); + try { + Files.write(path, encodedContent); + ComponentNotificationHelper.info(this.exportToFileButton, MessagesHelper.message("ExportPage.SavedTo", path.getFileName().toString())); + } catch (IOException e) { + ComponentNotificationHelper.error(this.exportToFileButton, MessagesHelper.message("ExportPage.FailedToWriteFile", e.getMessage())); + } + } + }); + + this.layoutNameLabel.setText(layoutName); + this.exportTextBox.setText(content); + } + + public JPanel getPanel() { + return this.importPanel; + } +} diff --git a/src/main/java/com/layoutmanager/ui/settings/ImportDialog.form b/src/main/java/com/layoutmanager/ui/settings/importing/ImportDialog.form similarity index 70% rename from src/main/java/com/layoutmanager/ui/settings/ImportDialog.form rename to src/main/java/com/layoutmanager/ui/settings/importing/ImportDialog.form index c85c851..2d2856a 100644 --- a/src/main/java/com/layoutmanager/ui/settings/ImportDialog.form +++ b/src/main/java/com/layoutmanager/ui/settings/importing/ImportDialog.form @@ -1,153 +1,146 @@ - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    diff --git a/src/main/java/com/layoutmanager/ui/settings/importing/ImportDialog.java b/src/main/java/com/layoutmanager/ui/settings/importing/ImportDialog.java new file mode 100644 index 0000000..8f31713 --- /dev/null +++ b/src/main/java/com/layoutmanager/ui/settings/importing/ImportDialog.java @@ -0,0 +1,155 @@ +package com.layoutmanager.ui.settings.importing; + +import blazing.chain.LZSEncoding; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.layoutmanager.localization.MessagesHelper; +import com.layoutmanager.persistence.Layout; +import com.layoutmanager.ui.dialogs.LayoutNameValidator; +import com.layoutmanager.ui.helpers.ComponentNotificationHelper; +import com.layoutmanager.ui.settings.ImportExportConstants; + +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import java.awt.*; +import java.awt.datatransfer.DataFlavor; +import java.awt.event.*; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; + +// TODO: +// Nicer UI +public class ImportDialog extends JDialog { + public static final int OK_RESULT = 1; + public static final int ABORT_RESULT = 0; + private final LayoutNameValidator layoutNameValidator; + + private JPanel contentPane; + private JButton importButton; + private JButton abortButton; + private JButton importFromFileButton; + private JButton importFromClipboardButton; + private JLabel layoutConfiguredWindowCountLabel; + private JTextField layoutNameTextBox; + + private Layout importedLayout; + private int result; + + public ImportDialog(LayoutNameValidator layoutNameValidator) { + this.layoutNameValidator = layoutNameValidator; + + this.setContentPane(contentPane); + this.setModal(true); + this.setResizable(false); + this.getRootPane().setDefaultButton(importButton); + + this.importButton.addActionListener(e -> onOK()); + this.abortButton.addActionListener(e -> onCancel()); + this.importFromClipboardButton.addActionListener(actionEvent -> importFromClipboard()); + this.importFromFileButton.addActionListener(actionEvent -> importFromFile()); + + // call onCancel() when cross is clicked + this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + this.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + onCancel(); + } + }); + + // call onCancel() on ESCAPE + this.contentPane.registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + } + + public Layout getImportedLayout() { + return this.importedLayout; + } + + public int showDialogInCenterOf(JDialog parent) { + this.setSize(this.getPreferredSize()); + this.setLocationRelativeTo(parent); + this.setVisible(true); + return this.result; + } + + private void importFromFile() { + File selectedFile = selectFile(); + if (selectedFile != null) { + importFile(selectedFile); + } + } + + private File selectFile() { + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setDialogTitle(MessagesHelper.message("ImportDialog.SelectFileTitle")); + fileChooser.setAcceptAllFileFilterUsed(false); + FileNameExtensionFilter filter = new FileNameExtensionFilter(ImportExportConstants.FILE_TYPE_NAME, ImportExportConstants.FILE_ENDING); + fileChooser.setFileFilter(filter); + + int result = fileChooser.showOpenDialog(null); + return result == JFileChooser.APPROVE_OPTION && fileChooser.getSelectedFile().exists() ? + fileChooser.getSelectedFile() : null; + } + + private void importFile(File file) { + try { + String lzEncodedContent = new String(Files.readAllBytes(Paths.get(file.getPath())), StandardCharsets.UTF_8); + importLayout(lzEncodedContent); + } catch (IOException e) { + ComponentNotificationHelper.error(importFromFileButton, MessagesHelper.message("ImportDialog.UnexpectedError", e.getMessage())); + } + } + + private void importFromClipboard() { + try { + String lzEncodedContent = (String) Toolkit + .getDefaultToolkit() + .getSystemClipboard() + .getData(DataFlavor.stringFlavor); + + importLayout(lzEncodedContent); + } catch (Exception e) { + ComponentNotificationHelper.error(importFromClipboardButton, MessagesHelper.message("ImportDialog.UnexpectedError", e.getMessage())); + } + } + + private void importLayout(String lzEncodedContent) { + // TODO Export to class + String jsonContent = LZSEncoding.decompressFromBase64(lzEncodedContent); + Gson gson = new GsonBuilder().create(); + Layout selectedLayout = gson.fromJson(jsonContent, Layout.class); + + selectLayout(selectedLayout); + } + + private void selectLayout(Layout layout) { + this.importedLayout = layout; + + this.layoutNameTextBox.setText(layout.getName()); + this.layoutNameTextBox.requestFocus(); + this.layoutConfiguredWindowCountLabel.setText(Integer.toString(layout.getToolWindows().length)); + + ComponentNotificationHelper.info(layoutNameTextBox, MessagesHelper.message("ImportDialog.SuccessfullyLoadedLayout", layout.getName())); + + this.importButton.setEnabled(true); + this.layoutNameTextBox.setEnabled(true); + } + + private void onOK() { + if (!this.layoutNameValidator.isValid(this.layoutNameTextBox.getText())) { + ComponentNotificationHelper.error(importButton, MessagesHelper.message("LayoutNameValidation.InvalidName")); + return; + } + + + this.result = OK_RESULT; + dispose(); + } + + private void onCancel() { + this.result = ABORT_RESULT; + dispose(); + } +} diff --git a/src/main/resources/com/layoutmanager/ui/messages.properties b/src/main/resources/com/layoutmanager/ui/messages.properties index 34c9091..46933d8 100644 --- a/src/main/resources/com/layoutmanager/ui/messages.properties +++ b/src/main/resources/com/layoutmanager/ui/messages.properties @@ -27,4 +27,8 @@ SettingsPage.Title=Window Layout Manager SettingsPage.NameColumn=Name SettingsPage.ConfiguredWindowsColumn=Configured Windows -ImportDialog.SelectFileTitle=Select layout file \ No newline at end of file +ImportDialog.SelectFileTitle=Select layout file +ImportDialog.UnexpectedError=Unexpected error occurred: {0} +ImportDialog.SuccessfullyLoadedLayout=Successfully loaded the layout ''{0}'' + +LayoutNameValidation.InvalidName=The layout name must not be empty or contain illegal characters. \ No newline at end of file From cb6f9e5a1bbb3c98b499f19770261d7b9c6d5196 Mon Sep 17 00:00:00 2001 From: Michael Estermann <14977799+michaelestermann@users.noreply.github.com> Date: Thu, 7 May 2020 17:56:27 +0200 Subject: [PATCH 15/19] Refactored export page to be a dialog. --- .../settings/LayoutManagerSettingsPanel.java | 52 +++----- .../ui/settings/LayoutSerializer.java | 20 +++ .../ui/settings/SettingsPage.java | 3 +- .../{ExportPage.form => ExportDialog.form} | 4 +- .../ui/settings/exporting/ExportDialog.java | 117 ++++++++++++++++++ .../ui/settings/exporting/ExportPage.java | 87 ------------- .../ui/settings/importing/ImportDialog.form | 4 +- .../ui/settings/importing/ImportDialog.java | 72 ++++++----- .../com/layoutmanager/ui/messages.properties | 16 +-- 9 files changed, 213 insertions(+), 162 deletions(-) create mode 100644 src/main/java/com/layoutmanager/ui/settings/LayoutSerializer.java rename src/main/java/com/layoutmanager/ui/settings/exporting/{ExportPage.form => ExportDialog.form} (96%) create mode 100644 src/main/java/com/layoutmanager/ui/settings/exporting/ExportDialog.java delete mode 100644 src/main/java/com/layoutmanager/ui/settings/exporting/ExportPage.java diff --git a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java index 17acadf..4ea409b 100644 --- a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java +++ b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java @@ -1,8 +1,5 @@ package com.layoutmanager.ui.settings; -import blazing.chain.LZSEncoding; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.intellij.openapi.components.ServiceManager; import com.layoutmanager.localization.MessagesHelper; import com.layoutmanager.persistence.Layout; @@ -11,7 +8,7 @@ import com.layoutmanager.ui.dialogs.LayoutNameValidator; import com.layoutmanager.ui.helpers.ComponentNotificationHelper; import com.layoutmanager.ui.menu.WindowMenuService; -import com.layoutmanager.ui.settings.exporting.ExportPage; +import com.layoutmanager.ui.settings.exporting.ExportDialog; import com.layoutmanager.ui.settings.importing.ImportDialog; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,6 +24,7 @@ public class LayoutManagerSettingsPanel { private final LayoutConfig layoutConfig; private final LayoutNameDialog layoutNameDialog; private final LayoutNameValidator layoutNameValidator; + private final LayoutSerializer layoutSerializer; private ArrayList currentLayouts = new ArrayList<>(); private JCheckBox useSmartDockingCheckbox; @@ -40,10 +38,12 @@ public class LayoutManagerSettingsPanel { public LayoutManagerSettingsPanel( LayoutConfig layoutConfig, LayoutNameDialog layoutNameDialog, - LayoutNameValidator layoutNameValidator) { + LayoutNameValidator layoutNameValidator, + LayoutSerializer layoutSerializer) { this.layoutConfig = layoutConfig; this.layoutNameDialog = layoutNameDialog; this.layoutNameValidator = layoutNameValidator; + this.layoutSerializer = layoutSerializer; this.loadSettings(layoutConfig); @@ -57,17 +57,17 @@ public LayoutManagerSettingsPanel( private void loadSettings(LayoutConfig layoutConfig) { Collections.addAll(this.currentLayouts, layoutConfig.getLayouts()); - DefaultTableModel table = createTableContent(); + DefaultTableModel table = this.createTableContent(); this.layoutsTable.setModel(table); this.layoutsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - useSmartDockingCheckbox.setSelected(layoutConfig.getSettings().getUseSmartDock()); + this.useSmartDockingCheckbox.setSelected(layoutConfig.getSettings().getUseSmartDock()); } private void selectedLayoutChanged() { - deleteButton.setEnabled(this.layoutsTable.getSelectedRow() >= 0); - renameButton.setEnabled(this.layoutsTable.getSelectedRow() >= 0); - exportButton.setEnabled(this.layoutsTable.getSelectedRow() >= 0); + this.deleteButton.setEnabled(this.layoutsTable.getSelectedRow() >= 0); + this.renameButton.setEnabled(this.layoutsTable.getSelectedRow() >= 0); + this.exportButton.setEnabled(this.layoutsTable.getSelectedRow() >= 0); } private void deleteLayout() { @@ -88,35 +88,25 @@ private void exportLayout() { int selectedRow = this.layoutsTable.getSelectedRow(); Layout selectedLayout = this.currentLayouts.get(selectedRow); - // TODO: Extract to class - Gson gson = new GsonBuilder().create(); - String jsonContent = gson.toJson(selectedLayout); - String lzEncodedContent = LZSEncoding.compressToBase64(jsonContent); - - ExportPage exportPage = new ExportPage(selectedLayout.getName(), lzEncodedContent); + String encodedContent = this.layoutSerializer.serialize(selectedLayout); + showExportDialog(selectedLayout, encodedContent); + } - showDialog(exportPage.getPanel()); + private void showExportDialog(Layout selectedLayout, String encodedContent) { + ExportDialog exportDialog = new ExportDialog(selectedLayout.getName(), encodedContent); + JDialog parent = this.getParentDialog(); + exportDialog.showDialogInCenterOf(parent); } private void importLayout() { - ImportDialog importDialog = new ImportDialog(this.layoutNameValidator); - JDialog parent = getParentDialog(); + ImportDialog importDialog = new ImportDialog(this.layoutNameValidator, this.layoutSerializer); + JDialog parent = this.getParentDialog(); if (importDialog.showDialogInCenterOf(parent) == ImportDialog.OK_RESULT) { this.currentLayouts.add(importDialog.getImportedLayout()); ((DefaultTableModel) layoutsTable.getModel()).fireTableDataChanged(); } } - private void showDialog(JComponent component) { - // TODO: Extract to class - JDialog parent = getParentDialog(); - final JDialog dialog = new JDialog(parent, MessagesHelper.message("ExportPage.Title"), true); - dialog.getContentPane().add(component); - dialog.pack(); - dialog.setLocationRelativeTo(parent); - dialog.setVisible(true); - } - @Nullable private JDialog getParentDialog() { return (JDialog) SwingUtilities.getAncestorOfClass(JDialog.class, this.settingsPanel); @@ -147,7 +137,7 @@ public JPanel getPanel() { @NotNull private DefaultTableModel createTableContent() { - DefaultTableModel model = new DefaultTableModel( + return new DefaultTableModel( new String[]{ MessagesHelper.message("SettingsPage.NameColumn"), MessagesHelper.message("SettingsPage.ConfiguredWindowsColumn") @@ -194,7 +184,5 @@ public Object getValueAt(int row, int column) { return null; } }; - - return model; } } diff --git a/src/main/java/com/layoutmanager/ui/settings/LayoutSerializer.java b/src/main/java/com/layoutmanager/ui/settings/LayoutSerializer.java new file mode 100644 index 0000000..1329ac7 --- /dev/null +++ b/src/main/java/com/layoutmanager/ui/settings/LayoutSerializer.java @@ -0,0 +1,20 @@ +package com.layoutmanager.ui.settings; + +import blazing.chain.LZSEncoding; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.layoutmanager.persistence.Layout; + +public class LayoutSerializer { + public String serialize(Layout layout) { + Gson gson = new GsonBuilder().create(); + String jsonContent = gson.toJson(layout); + return LZSEncoding.compressToBase64(jsonContent); + } + + public Layout deserialize(String encodedContent) { + String jsonContent = LZSEncoding.decompressFromBase64(encodedContent); + Gson gson = new GsonBuilder().create(); + return gson.fromJson(jsonContent, Layout.class); + } +} diff --git a/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java b/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java index c5429f2..59f19f3 100644 --- a/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java +++ b/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java @@ -19,7 +19,8 @@ public SettingsPage() { this.panel = new LayoutManagerSettingsPanel( LayoutConfig.getInstance(), new LayoutNameDialog(layoutNameValidator), - layoutNameValidator); + layoutNameValidator, + new LayoutSerializer()); } @Nls(capitalization = Nls.Capitalization.Title) diff --git a/src/main/java/com/layoutmanager/ui/settings/exporting/ExportPage.form b/src/main/java/com/layoutmanager/ui/settings/exporting/ExportDialog.form similarity index 96% rename from src/main/java/com/layoutmanager/ui/settings/exporting/ExportPage.form rename to src/main/java/com/layoutmanager/ui/settings/exporting/ExportDialog.form index 4e4d79c..34903ca 100644 --- a/src/main/java/com/layoutmanager/ui/settings/exporting/ExportPage.form +++ b/src/main/java/com/layoutmanager/ui/settings/exporting/ExportDialog.form @@ -1,6 +1,6 @@ -
    - + + diff --git a/src/main/java/com/layoutmanager/ui/settings/exporting/ExportDialog.java b/src/main/java/com/layoutmanager/ui/settings/exporting/ExportDialog.java new file mode 100644 index 0000000..abd5287 --- /dev/null +++ b/src/main/java/com/layoutmanager/ui/settings/exporting/ExportDialog.java @@ -0,0 +1,117 @@ +package com.layoutmanager.ui.settings.exporting; + +import com.layoutmanager.localization.MessagesHelper; +import com.layoutmanager.ui.helpers.ComponentNotificationHelper; +import com.layoutmanager.ui.settings.ImportExportConstants; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import java.awt.*; +import java.awt.datatransfer.StringSelection; +import java.awt.event.KeyEvent; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class ExportDialog extends JDialog { + private JTextArea exportTextBox; + private JPanel contentPanel; + private JButton exportToFileButton; + private JButton exportToClipboardButton; + private JButton closeButton; + private JLabel layoutNameLabel; + + private String layoutName; + private String content; + + public ExportDialog(String layoutName, String content) { + this.layoutName = layoutName; + this.content = content; + + this.setContentPane(contentPanel); + this.setModal(true); + this.getRootPane().setDefaultButton(closeButton); + + this.exportToClipboardButton.addActionListener(actionEvent -> this.exportToClipboard()); + this.exportToFileButton.addActionListener(actionEvent -> this.exportToFile()); + this.closeButton.addActionListener(actionEvent -> this.onClose()); + + this.layoutNameLabel.setText(layoutName); + this.exportTextBox.setText(content); + + this.contentPanel.registerKeyboardAction(e -> onClose(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + } + + public void showDialogInCenterOf(JDialog parent) { + this.setTitle(MessagesHelper.message("ExportDialog.Title")); + this.setSize(this.getPreferredSize()); + this.setLocationRelativeTo(parent); + this.setVisible(true); + } + + public JPanel getPanel() { + return this.contentPanel; + } + + private void exportToClipboard() { + this.exportTextBox.requestFocus(); + this.exportTextBox.selectAll(); + Toolkit + .getDefaultToolkit() + .getSystemClipboard() + .setContents( + new StringSelection(this.exportTextBox.getText()), + null); + ComponentNotificationHelper.info(this.exportToClipboardButton, MessagesHelper.message("ExportDialog.CopiedToClipboard")); + } + + private void exportToFile() { + File selectedFile = this.selectFile(); + if (selectedFile != null) { + Path path = this.getPath(selectedFile); + this.writeContentToFile(path); + } + } + + private File selectFile() { + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setDialogTitle(MessagesHelper.message("ExportDialog.SaveFileTitle")); + fileChooser.setSelectedFile(new File(this.layoutName + ImportExportConstants.FILE_ENDING_WITH_DOT)); + fileChooser.setAcceptAllFileFilterUsed(false); + FileNameExtensionFilter filter = new FileNameExtensionFilter(ImportExportConstants.FILE_TYPE_NAME, ImportExportConstants.FILE_ENDING); + fileChooser.setFileFilter(filter); + + int result = fileChooser.showSaveDialog(null); + return result == JFileChooser.APPROVE_OPTION ? + fileChooser.getSelectedFile() : + null; + } + + @NotNull + private Path getPath(File selectedFile) { + String fullPath = selectedFile.getAbsolutePath(); + if (!fullPath.toLowerCase().endsWith(ImportExportConstants.FILE_ENDING_WITH_DOT)) { + fullPath += ImportExportConstants.FILE_ENDING_WITH_DOT; + } + + return Paths.get(fullPath); + } + + private void writeContentToFile(Path path) { + try { + byte[] encodedContent = this.content.getBytes(); + Files.write(path, encodedContent); + ComponentNotificationHelper.info(this.exportToFileButton, MessagesHelper.message("ExportDialog.SavedTo", path.getFileName().toString())); + } catch (IOException e) { + ComponentNotificationHelper.error(this.exportToFileButton, MessagesHelper.message("ExportDialog.FailedToWriteFile", e.getMessage())); + } + } + + private void onClose() { + JDialog window = (JDialog) SwingUtilities.getAncestorOfClass(JDialog.class, this.contentPanel); + window.dispose(); + } +} diff --git a/src/main/java/com/layoutmanager/ui/settings/exporting/ExportPage.java b/src/main/java/com/layoutmanager/ui/settings/exporting/ExportPage.java deleted file mode 100644 index 4e27ee3..0000000 --- a/src/main/java/com/layoutmanager/ui/settings/exporting/ExportPage.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.layoutmanager.ui.settings.exporting; - -import com.layoutmanager.localization.MessagesHelper; -import com.layoutmanager.ui.helpers.ComponentNotificationHelper; -import com.layoutmanager.ui.settings.ImportExportConstants; - -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import java.awt.*; -import java.awt.datatransfer.StringSelection; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -// TODO: Change to dialog and cleanup -public class ExportPage { - private JTextArea exportTextBox; - private JPanel importPanel; - private JButton exportToFileButton; - private JButton exportToClipboardButton; - private JButton closeButton; - private JLabel layoutNameLabel; - - private String layoutName; - private String content; - - // TODO: Move to own methods - public ExportPage(String layoutName, String content) { - this.layoutName = layoutName; - this.content = content; - - closeButton.addActionListener(actionEvent -> { - JDialog window = (JDialog) SwingUtilities.getAncestorOfClass(JDialog.class, this.importPanel); - window.dispose(); - }); - - exportToClipboardButton.addActionListener(actionEvent -> { - this.exportTextBox.requestFocus(); - this.exportTextBox.selectAll(); - Toolkit - .getDefaultToolkit() - .getSystemClipboard() - .setContents( - new StringSelection(this.exportTextBox.getText()), - null); - ComponentNotificationHelper.info(this.exportToClipboardButton, MessagesHelper.message("ExportPage.CopiedToClipboard")); - }); - - exportToFileButton.addActionListener(actionEvent -> { - JFileChooser fileChooser = new JFileChooser(); - fileChooser.setDialogTitle(MessagesHelper.message("ExportPage.SaveFileTitle")); - fileChooser.setSelectedFile(new File(this.layoutName + ImportExportConstants.FILE_ENDING_WITH_DOT)); - fileChooser.setAcceptAllFileFilterUsed(false); - FileNameExtensionFilter filter = new FileNameExtensionFilter(ImportExportConstants.FILE_TYPE_NAME, ImportExportConstants.FILE_ENDING); - fileChooser.setFileFilter(filter); - - int userSelection = fileChooser.showSaveDialog(null); - - if (userSelection == JFileChooser.APPROVE_OPTION) { - File fileToSave = fileChooser.getSelectedFile(); - - byte[] encodedContent = this.content.getBytes(); - String fullPath = fileToSave.getAbsolutePath(); - if (!fullPath.toLowerCase().endsWith(ImportExportConstants.FILE_ENDING_WITH_DOT)) { - fullPath += ImportExportConstants.FILE_ENDING_WITH_DOT; - } - - Path path = Paths.get(fullPath); - try { - Files.write(path, encodedContent); - ComponentNotificationHelper.info(this.exportToFileButton, MessagesHelper.message("ExportPage.SavedTo", path.getFileName().toString())); - } catch (IOException e) { - ComponentNotificationHelper.error(this.exportToFileButton, MessagesHelper.message("ExportPage.FailedToWriteFile", e.getMessage())); - } - } - }); - - this.layoutNameLabel.setText(layoutName); - this.exportTextBox.setText(content); - } - - public JPanel getPanel() { - return this.importPanel; - } -} diff --git a/src/main/java/com/layoutmanager/ui/settings/importing/ImportDialog.form b/src/main/java/com/layoutmanager/ui/settings/importing/ImportDialog.form index 2d2856a..1028af4 100644 --- a/src/main/java/com/layoutmanager/ui/settings/importing/ImportDialog.form +++ b/src/main/java/com/layoutmanager/ui/settings/importing/ImportDialog.form @@ -1,6 +1,6 @@ - + @@ -81,7 +81,7 @@ - + diff --git a/src/main/java/com/layoutmanager/ui/settings/importing/ImportDialog.java b/src/main/java/com/layoutmanager/ui/settings/importing/ImportDialog.java index 8f31713..22e80df 100644 --- a/src/main/java/com/layoutmanager/ui/settings/importing/ImportDialog.java +++ b/src/main/java/com/layoutmanager/ui/settings/importing/ImportDialog.java @@ -1,33 +1,32 @@ package com.layoutmanager.ui.settings.importing; -import blazing.chain.LZSEncoding; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.layoutmanager.localization.MessagesHelper; import com.layoutmanager.persistence.Layout; import com.layoutmanager.ui.dialogs.LayoutNameValidator; import com.layoutmanager.ui.helpers.ComponentNotificationHelper; import com.layoutmanager.ui.settings.ImportExportConstants; +import com.layoutmanager.ui.settings.LayoutSerializer; import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; import java.awt.*; import java.awt.datatransfer.DataFlavor; -import java.awt.event.*; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; -// TODO: -// Nicer UI public class ImportDialog extends JDialog { public static final int OK_RESULT = 1; public static final int ABORT_RESULT = 0; private final LayoutNameValidator layoutNameValidator; + private final LayoutSerializer layoutSerializer; - private JPanel contentPane; + private JPanel contentPanel; private JButton importButton; private JButton abortButton; private JButton importFromFileButton; @@ -38,18 +37,21 @@ public class ImportDialog extends JDialog { private Layout importedLayout; private int result; - public ImportDialog(LayoutNameValidator layoutNameValidator) { + public ImportDialog( + LayoutNameValidator layoutNameValidator, + LayoutSerializer layoutSerializer) { this.layoutNameValidator = layoutNameValidator; + this.layoutSerializer = layoutSerializer; - this.setContentPane(contentPane); + this.setContentPane(contentPanel); this.setModal(true); this.setResizable(false); this.getRootPane().setDefaultButton(importButton); - this.importButton.addActionListener(e -> onOK()); - this.abortButton.addActionListener(e -> onCancel()); - this.importFromClipboardButton.addActionListener(actionEvent -> importFromClipboard()); - this.importFromFileButton.addActionListener(actionEvent -> importFromFile()); + this.importButton.addActionListener(e -> this.onOK()); + this.abortButton.addActionListener(e -> this.onCancel()); + this.importFromClipboardButton.addActionListener(actionEvent -> this.importFromClipboard()); + this.importFromFileButton.addActionListener(actionEvent -> this.importFromFile()); // call onCancel() when cross is clicked this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); @@ -59,8 +61,7 @@ public void windowClosing(WindowEvent e) { } }); - // call onCancel() on ESCAPE - this.contentPane.registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + this.contentPanel.registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); } public Layout getImportedLayout() { @@ -68,6 +69,7 @@ public Layout getImportedLayout() { } public int showDialogInCenterOf(JDialog parent) { + this.setTitle(MessagesHelper.message("ImportDialog.Title")); this.setSize(this.getPreferredSize()); this.setLocationRelativeTo(parent); this.setVisible(true); @@ -75,9 +77,9 @@ public int showDialogInCenterOf(JDialog parent) { } private void importFromFile() { - File selectedFile = selectFile(); + File selectedFile = this.selectFile(); if (selectedFile != null) { - importFile(selectedFile); + this.importFile(selectedFile); } } @@ -95,10 +97,14 @@ private File selectFile() { private void importFile(File file) { try { - String lzEncodedContent = new String(Files.readAllBytes(Paths.get(file.getPath())), StandardCharsets.UTF_8); - importLayout(lzEncodedContent); + String encodedContent = new String(Files.readAllBytes(Paths.get(file.getPath())), StandardCharsets.UTF_8); + this.importLayout(encodedContent); } catch (IOException e) { - ComponentNotificationHelper.error(importFromFileButton, MessagesHelper.message("ImportDialog.UnexpectedError", e.getMessage())); + ComponentNotificationHelper.error(this.importFromFileButton, MessagesHelper.message("ImportDialog.IOException", file.getName(), e.getMessage())); + this.deselectLayout(); + } catch(Exception e) { + ComponentNotificationHelper.error(this.importFromFileButton, MessagesHelper.message("ImportDialog.UnknownFormat")); + this.deselectLayout(); } } @@ -109,19 +115,16 @@ private void importFromClipboard() { .getSystemClipboard() .getData(DataFlavor.stringFlavor); - importLayout(lzEncodedContent); + this.importLayout(lzEncodedContent); } catch (Exception e) { - ComponentNotificationHelper.error(importFromClipboardButton, MessagesHelper.message("ImportDialog.UnexpectedError", e.getMessage())); + ComponentNotificationHelper.error(this.importFromClipboardButton, MessagesHelper.message("ImportDialog.UnknownFormat")); + this.deselectLayout(); } } - private void importLayout(String lzEncodedContent) { - // TODO Export to class - String jsonContent = LZSEncoding.decompressFromBase64(lzEncodedContent); - Gson gson = new GsonBuilder().create(); - Layout selectedLayout = gson.fromJson(jsonContent, Layout.class); - - selectLayout(selectedLayout); + private void importLayout(String encodedContent) { + Layout selectedLayout = this.layoutSerializer.deserialize(encodedContent); + this.selectLayout(selectedLayout); } private void selectLayout(Layout layout) { @@ -131,15 +134,22 @@ private void selectLayout(Layout layout) { this.layoutNameTextBox.requestFocus(); this.layoutConfiguredWindowCountLabel.setText(Integer.toString(layout.getToolWindows().length)); - ComponentNotificationHelper.info(layoutNameTextBox, MessagesHelper.message("ImportDialog.SuccessfullyLoadedLayout", layout.getName())); + ComponentNotificationHelper.info(this.layoutNameTextBox, MessagesHelper.message("ImportDialog.SuccessfullyLoadedLayout", layout.getName())); this.importButton.setEnabled(true); this.layoutNameTextBox.setEnabled(true); } + private void deselectLayout() { + this.importedLayout = null; + this.importButton.setEnabled(false); + this.layoutNameTextBox.setText(""); + this.layoutNameTextBox.setEnabled(false); + } + private void onOK() { if (!this.layoutNameValidator.isValid(this.layoutNameTextBox.getText())) { - ComponentNotificationHelper.error(importButton, MessagesHelper.message("LayoutNameValidation.InvalidName")); + ComponentNotificationHelper.error(this.importButton, MessagesHelper.message("LayoutNameValidation.InvalidName")); return; } diff --git a/src/main/resources/com/layoutmanager/ui/messages.properties b/src/main/resources/com/layoutmanager/ui/messages.properties index 46933d8..1ec14e9 100644 --- a/src/main/resources/com/layoutmanager/ui/messages.properties +++ b/src/main/resources/com/layoutmanager/ui/messages.properties @@ -17,18 +17,20 @@ DeleteLayout.Menu=Delete Layout DeleteLayout.Notification.Title=Window layout deleted DeleteLayout.Notification.Content=The window layout ''{0}'' has been successfully deleted. -ExportPage.Title=Export layout -ExportPage.CopiedToClipboard=Copied to clipboard! -ExportPage.SaveFileTitle=Specify a file to save -ExportPage.SavedTo=Saved to file ''{0}'' ! -ExportPage.FailedToWriteFile=Failed to write export file: {0} - SettingsPage.Title=Window Layout Manager SettingsPage.NameColumn=Name SettingsPage.ConfiguredWindowsColumn=Configured Windows +ExportDialog.Title=Export layout +ExportDialog.CopiedToClipboard=Copied to clipboard! +ExportDialog.SaveFileTitle=Specify a file to save +ExportDialog.SavedTo=Saved to file ''{0}'' ! +ExportDialog.FailedToWriteFile=Failed to write export file: {0} + +ImportDialog.Title=Import layout ImportDialog.SelectFileTitle=Select layout file -ImportDialog.UnexpectedError=Unexpected error occurred: {0} +ImportDialog.IOException=Failed to read file '{0}'. Reason: {1} +ImportDialog.UnknownFormat=Import failed due to a unknown format ImportDialog.SuccessfullyLoadedLayout=Successfully loaded the layout ''{0}'' LayoutNameValidation.InvalidName=The layout name must not be empty or contain illegal characters. \ No newline at end of file From 2cfbf05fa09793d194af827c8cc2971c72a02adc Mon Sep 17 00:00:00 2001 From: Michael Estermann <14977799+michaelestermann@users.noreply.github.com> Date: Thu, 7 May 2020 18:09:55 +0200 Subject: [PATCH 16/19] Delete key binding. --- .../settings/LayoutManagerSettingsPanel.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java index 4ea409b..265d3e5 100644 --- a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java +++ b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java @@ -16,10 +16,14 @@ import javax.swing.*; import javax.swing.event.TableModelEvent; import javax.swing.table.DefaultTableModel; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import static javax.swing.JComponent.WHEN_FOCUSED; + public class LayoutManagerSettingsPanel { private final LayoutConfig layoutConfig; private final LayoutNameDialog layoutNameDialog; @@ -58,12 +62,28 @@ private void loadSettings(LayoutConfig layoutConfig) { Collections.addAll(this.currentLayouts, layoutConfig.getLayouts()); DefaultTableModel table = this.createTableContent(); + this.setKeyBindings(table); this.layoutsTable.setModel(table); this.layoutsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); this.useSmartDockingCheckbox.setSelected(layoutConfig.getSettings().getUseSmartDock()); } + private void setKeyBindings(DefaultTableModel tableModel){ + InputMap inputMap = layoutsTable.getInputMap(WHEN_FOCUSED); + ActionMap actionMap = layoutsTable.getActionMap(); + + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "delete"); + actionMap.put("delete", new AbstractAction() { + public void actionPerformed(ActionEvent evt) { + int selectedRow = layoutsTable.getSelectedRow(); + if (selectedRow >= 0) { + tableModel.removeRow(selectedRow); + } + } + }); + } + private void selectedLayoutChanged() { this.deleteButton.setEnabled(this.layoutsTable.getSelectedRow() >= 0); this.renameButton.setEnabled(this.layoutsTable.getSelectedRow() >= 0); From 73bd5ffb5d5d708aa7dd5b66e9d3c7297fd62ce0 Mon Sep 17 00:00:00 2001 From: Michael Estermann <14977799+michaelestermann@users.noreply.github.com> Date: Thu, 7 May 2020 18:26:11 +0200 Subject: [PATCH 17/19] Fixed issues --- .../java/com/layoutmanager/ui/dialogs/LayoutNameDialog.java | 2 +- .../com/layoutmanager/ui/settings/importing/ImportDialog.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/layoutmanager/ui/dialogs/LayoutNameDialog.java b/src/main/java/com/layoutmanager/ui/dialogs/LayoutNameDialog.java index 3dee2e1..3abc064 100644 --- a/src/main/java/com/layoutmanager/ui/dialogs/LayoutNameDialog.java +++ b/src/main/java/com/layoutmanager/ui/dialogs/LayoutNameDialog.java @@ -22,7 +22,7 @@ public String show(String defaultName) { AllIcons.Actions.Edit, defaultName, null); - } while (!this.layoutNameValidator.isValid(name)); + } while (name != null && !this.layoutNameValidator.isValid(name)); return name; } diff --git a/src/main/java/com/layoutmanager/ui/settings/importing/ImportDialog.java b/src/main/java/com/layoutmanager/ui/settings/importing/ImportDialog.java index 22e80df..2595a19 100644 --- a/src/main/java/com/layoutmanager/ui/settings/importing/ImportDialog.java +++ b/src/main/java/com/layoutmanager/ui/settings/importing/ImportDialog.java @@ -145,6 +145,7 @@ private void deselectLayout() { this.importButton.setEnabled(false); this.layoutNameTextBox.setText(""); this.layoutNameTextBox.setEnabled(false); + this.layoutConfiguredWindowCountLabel.setText("-"); } private void onOK() { @@ -152,7 +153,7 @@ private void onOK() { ComponentNotificationHelper.error(this.importButton, MessagesHelper.message("LayoutNameValidation.InvalidName")); return; } - + this.importedLayout.setName(this.layoutNameTextBox.getText()); this.result = OK_RESULT; dispose(); From d1e9a188fc7b8e64935dcc2e6f17326b88cb8b96 Mon Sep 17 00:00:00 2001 From: Michael Estermann <14977799+michaelestermann@users.noreply.github.com> Date: Fri, 8 May 2020 08:20:02 +0200 Subject: [PATCH 18/19] Fix style issues. --- .../java/com/layoutmanager/ui/helpers/ToolWindowHelper.java | 4 +++- .../layoutmanager/ui/settings/LayoutManagerSettingsPanel.java | 3 ++- src/main/java/com/layoutmanager/ui/settings/SettingsPage.java | 4 ---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java b/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java index 53d35c9..9b65b35 100644 --- a/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java +++ b/src/main/java/com/layoutmanager/ui/helpers/ToolWindowHelper.java @@ -2,7 +2,9 @@ import com.intellij.openapi.wm.ToolWindowAnchor; import com.intellij.openapi.wm.ToolWindowType; -import com.intellij.openapi.wm.impl.*; +import com.intellij.openapi.wm.impl.FloatingDecorator; +import com.intellij.openapi.wm.impl.InternalDecorator; +import com.intellij.openapi.wm.impl.ToolWindowImpl; import com.intellij.util.ui.UIUtil; import java.awt.Rectangle; diff --git a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java index 265d3e5..d890705 100644 --- a/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java +++ b/src/main/java/com/layoutmanager/ui/settings/LayoutManagerSettingsPanel.java @@ -200,8 +200,9 @@ public Object getValueAt(int row, int column) { return layout.getName(); case 1: return layout.getToolWindows().length; + default: + return null; } - return null; } }; } diff --git a/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java b/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java index 59f19f3..8d6d23b 100644 --- a/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java +++ b/src/main/java/com/layoutmanager/ui/settings/SettingsPage.java @@ -44,8 +44,4 @@ public boolean isModified() { public void apply() { this.panel.apply(); } - - @Override - public void reset() { - } } From d4fb2a1a5dc1f93d2be6cad5b24b07bb34fa4e29 Mon Sep 17 00:00:00 2001 From: Michael Estermann <14977799+michaelestermann@users.noreply.github.com> Date: Fri, 8 May 2020 08:26:56 +0200 Subject: [PATCH 19/19] Adapted date --- src/main/resources/META-INF/plugin.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 45409a7..7c0142d 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -29,7 +29,7 @@
  • Jan 07, 2020 (ver 1.3.2) - Minor bugfixes.
  • Feb 25, 2020 (ver 1.3.3) - Issues when storing and restoring invisible windows fixed.
  • - Mar 26, 2020 (ver 1.4.0) + May 8, 2020 (ver 1.4.0) - Introduced settings page. - Introduced smart docking when saving a layout (Configurable). - Store docked tool window sizes and restore them accordingly.