diff --git a/src/base-config/keyboard.json b/src/base-config/keyboard.json index aa9c67cd4d5..8beca674314 100644 --- a/src/base-config/keyboard.json +++ b/src/base-config/keyboard.json @@ -266,6 +266,15 @@ "platform": "mac" } ], + "mainView.swapPaneContent": [ + { + "key" : "Ctrl-Alt-F" + }, + { + "key": "Cmd-Shift-F", + "platform": "mac" + } + ], "navigate.quickOpen": [ "Ctrl-Shift-O" ], diff --git a/src/command/Commands.js b/src/command/Commands.js index 40eae36b16d..c67481abc1a 100644 --- a/src/command/Commands.js +++ b/src/command/Commands.js @@ -154,6 +154,7 @@ define(function (require, exports, module) { exports.CMD_SPLITVIEW_VERTICAL = "cmd.splitViewVertical"; // SidebarView.js _handleSplitVertical() exports.CMD_SPLITVIEW_HORIZONTAL = "cmd.splitViewHorizontal"; // SidebarView.js _handleSplitHorizontal() exports.CMD_SWITCH_PANE_FOCUS = "cmd.switchPaneFocus"; // MainViewManager.js _switchPaneFocus() + exports.CMD_SWAP_PANE_CONTENT = "mainView.swapPaneContent"; // MainViewManager.js _swapPaneContent() // File shell callbacks - string must MATCH string in native code (appshell/command_callbacks.h) exports.HELP_ABOUT = "help.about"; // HelpCommandHandlers.js _handleAboutDialog() diff --git a/src/config.json b/src/config.json index 3775afad8db..da1c1354e88 100644 --- a/src/config.json +++ b/src/config.json @@ -74,7 +74,8 @@ }, "scripts": { "postinstall": "grunt install", - "test": "grunt cla-check-pull test" + "test": "grunt test cla-check-pull", + "eslint": "grunt eslint" }, "licenses": [ { @@ -82,4 +83,4 @@ "url": "https://github.com/adobe/brackets/blob/master/LICENSE" } ] -} \ No newline at end of file +} diff --git a/src/nls/root/strings.js b/src/nls/root/strings.js index 6e15cfaf9f8..94a9729ebd6 100644 --- a/src/nls/root/strings.js +++ b/src/nls/root/strings.js @@ -420,6 +420,7 @@ define({ "CMD_SHOW_IN_FINDER" : "Show in Finder", "CMD_SHOW_IN_OS" : "Show in OS", "CMD_SWITCH_PANE_FOCUS" : "Switch Pane Focus", + "CMD_SWAP_PANE_CONTENT" : "Swap Visible Content Between Split Panes", // Help menu commands "HELP_MENU" : "Help", diff --git a/src/view/MainViewManager.js b/src/view/MainViewManager.js index 671b370795f..85c6d7f0a32 100644 --- a/src/view/MainViewManager.js +++ b/src/view/MainViewManager.js @@ -25,7 +25,7 @@ * MainViewManager manages the arrangement of all open panes as well as provides the controller * logic behind all views in the MainView (e.g. ensuring that a file doesn't appear in 2 lists) * - * Each pane contains one or more views wich are created by a view factory and inserted into a pane list. + * Each pane contains one or more views which are created by a view factory and inserted into a pane list. * There may be several panes managed by the MainViewManager with each pane containing a list of views. * The panes are always visible and the layout is determined by the MainViewManager and the user. * @@ -140,6 +140,7 @@ define(function (require, exports, module) { */ var SECOND_PANE = "second-pane"; + /* * NOTE: The following commands and constants will change * when implementing the UX UI Treatment @larz0 @@ -845,6 +846,62 @@ define(function (require, exports, module) { return result.promise(); } + /** + * swaps current views to opposite panes + */ + function swapPaneContent() { + + var activeFileInactiveView, + inactiveFileActiveView, + activePaneId = getActivePaneId(), + inactivePaneId = activePaneId === FIRST_PANE ? SECOND_PANE : FIRST_PANE, + activePane = _getPane(activePaneId), + inactivePane = _getPane(inactivePaneId), + activeFile = activePane.getCurrentlyViewedFile(), + inactiveFile = inactivePane.getCurrentlyViewedFile(); + + // Check if one of the panes is empty move and open currently viewed file in opposite pane. + // if both are empty do nothing. + if (!activeFile || !inactiveFile) { + if (!activeFile && inactiveFile) { + _moveView(inactivePaneId, activePaneId, inactiveFile, 0); + } else if (!inactiveFile && activeFile) { + _moveView(activePaneId, inactivePaneId, activeFile, 0); + } + + } else { + + // check if currently viewed file is present in opposing pane. If it is open the file. + // if it is not add it to the opposite pane and open. + activeFileInactiveView = inactivePane.getViewForPath(activeFile.fullPath); + inactiveFileActiveView = activePane.getViewForPath(inactiveFile.fullPath); + + if (inactiveFileActiveView) { + CommandManager.execute(Commands.FILE_OPEN, { + fullPath: inactiveFile.fullPath, + paneId: activePaneId + }); + } else { + CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { + fullPath: inactiveFile.fullPath, + paneId: activePaneId + }); + } + + if (activeFileInactiveView) { + CommandManager.execute(Commands.FILE_OPEN, { + fullPath: activeFile.fullPath, + paneId: inactivePaneId + }); + } else { + CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { + fullPath: activeFile.fullPath, + paneId: inactivePaneId + }); + } + } + }; + /** * Switch between panes */ @@ -1752,6 +1809,7 @@ define(function (require, exports, module) { exports.getAllOpenFiles = getAllOpenFiles; exports.focusActivePane = focusActivePane; exports.switchPaneFocus = switchPaneFocus; + exports.swapPaneContent = swapPaneContent; // Layout exports.setLayoutScheme = setLayoutScheme; diff --git a/src/view/ViewCommandHandlers.js b/src/view/ViewCommandHandlers.js index 95fe3cfc491..2bb4612537e 100644 --- a/src/view/ViewCommandHandlers.js +++ b/src/view/ViewCommandHandlers.js @@ -501,6 +501,13 @@ define(function (require, exports, module) { ThemeSettings.showDialog(); } + /** Handle enabling swapPaneContent in MainViewManager */ + function _handleSwapPaneContent(){ + if (PreferencesManager.get("mainView.swapPaneContent", PreferencesManager.CURRENT_PROJECT)) { + MainViewManager.swapPaneContent(); + } + } + // Register command handlers CommandManager.register(Strings.CMD_INCREASE_FONT_SIZE, Commands.VIEW_INCREASE_FONT_SIZE, _handleIncreaseFontSize); CommandManager.register(Strings.CMD_DECREASE_FONT_SIZE, Commands.VIEW_DECREASE_FONT_SIZE, _handleDecreaseFontSize); @@ -509,6 +516,13 @@ define(function (require, exports, module) { CommandManager.register(Strings.CMD_SCROLL_LINE_DOWN, Commands.VIEW_SCROLL_LINE_DOWN, _handleScrollLineDown); CommandManager.register(Strings.CMD_THEMES, Commands.CMD_THEMES_OPEN_SETTINGS, _handleThemeSettings); + CommandManager.register(Strings.CMD_SWAP_PANE_CONTENT, Commands.CMD_SWAP_PANE_CONTENT, _handleSwapPaneContent); + + // Define swapPaneVisibleContent, which controls whether to enable command to swap visible content between panes. + PreferencesManager.definePreference("mainView.swapPaneContent", "boolean", false, { + description: Strings.CMD_SWAP_PANE_CONTENT + }); + prefs.definePreference("fontSize", "string", DEFAULT_FONT_SIZE + "px", { description: Strings.DESCRIPTION_FONT_SIZE }).on("change", function () { diff --git a/test/spec/MainViewManager-test.js b/test/spec/MainViewManager-test.js index a69f3b84913..4a48ae08cb7 100644 --- a/test/spec/MainViewManager-test.js +++ b/test/spec/MainViewManager-test.js @@ -479,6 +479,101 @@ define(function (require, exports, module) { expect(EditorManager.getCurrentFullEditor().document.file.name).toEqual("test.js"); }); }); + it("should swap views between panes", function () { + runs(function () { + MainViewManager.setLayoutScheme(1, 2); + }); + runs(function () { + promise = CommandManager.execute(Commands.FILE_OPEN, { fullPath: testPath + "/test.js", + paneId: "first-pane" }); + waitsForDone(promise, Commands.FILE_OPEN); + }); + runs(function () { + promise = CommandManager.execute(Commands.FILE_OPEN, { fullPath: testPath + "/test.css", + paneId: "second-pane" }); + waitsForDone(promise, Commands.FILE_OPEN); + }); + runs(function () { + expect(MainViewManager._getPaneIdForPath(testPath + "/test.js")).toEqual("first-pane"); + expect(MainViewManager._getPaneIdForPath(testPath + "/test.css")).toEqual("second-pane"); + }); + runs(function () { + expect(MainViewManager.getCurrentlyViewedFile("first-pane").name).toEqual("test.js"); + expect(MainViewManager.getCurrentlyViewedFile("second-pane").name).toEqual("test.css"); + }); + runs(function () { + MainViewManager.swapPaneContent(); + }); + runs(function () { + MainViewManager.setActivePaneId("first-pane"); + expect(MainViewManager.getCurrentlyViewedFile(MainViewManager.ACTIVE_PANE).name).toEqual("test.css"); + MainViewManager.setActivePaneId("second-pane"); + expect(MainViewManager.getCurrentlyViewedFile(MainViewManager.ACTIVE_PANE).name).toEqual("test.js"); + }); + runs(function () { + MainViewManager.swapPaneContent(); + }); + runs(function () { + MainViewManager.setActivePaneId("first-pane"); + expect(MainViewManager.getCurrentlyViewedFile(MainViewManager.ACTIVE_PANE).name).toEqual("test.js"); + MainViewManager.setActivePaneId("second-pane"); + expect(MainViewManager.getCurrentlyViewedFile(MainViewManager.ACTIVE_PANE).name).toEqual("test.css"); + }); + }); + it("should show a file instead of swapping if file is already open", function () { + runs(function () { + MainViewManager.setLayoutScheme(1, 2); + }); + runs(function () { + promise = CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { fullPath: testPath + "/test.js", + paneId: "first-pane" }); + waitsForDone(promise, Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN); + }); + runs(function () { + promise = CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { fullPath: testPath + "/test.css", + paneId: "second-pane" }); + waitsForDone(promise, Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN); + }); + runs(function () { + promise = CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { fullPath: testPath + "/test.js", + paneId: "second-pane" }); + waitsForDone(promise, Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN); + }); + runs(function(){ + MainViewManager.setActivePaneId("second-pane"); + expect(MainViewManager.getCurrentlyViewedFile(MainViewManager.ACTIVE_PANE).name).toEqual("test.js"); + }); + runs(function () { + MainViewManager.swapPaneContent(); + }); + runs(function () { + MainViewManager.setActivePaneId("first-pane"); + expect(MainViewManager.getCurrentlyViewedFile(MainViewManager.ACTIVE_PANE).name).toEqual("test.js"); + expect(EditorManager.getCurrentFullEditor().document.file.name).toEqual("test.js"); + MainViewManager.setActivePaneId("second-pane"); + expect(MainViewManager.getCurrentlyViewedFile(MainViewManager.ACTIVE_PANE).name).toEqual("test.js"); + expect(EditorManager.getCurrentFullEditor().document.file.name).toEqual("test.js"); + }); + }); + it("should move file if one pane is empty", function () { + runs(function () { + MainViewManager.setLayoutScheme(1, 2); + }); + runs(function () { + promise = CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { fullPath: testPath + "/test.js", + paneId: "first-pane" }); + waitsForDone(promise, Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN); + }); + runs(function () { + MainViewManager.swapPaneContent(); + }); + runs(function () { + MainViewManager.setActivePaneId("first-pane"); + expect(MainViewManager.getCurrentlyViewedFile(MainViewManager.ACTIVE_PANE)).toEqual(null); + MainViewManager.setActivePaneId("second-pane"); + expect(MainViewManager.getCurrentlyViewedFile(MainViewManager.ACTIVE_PANE).name).toEqual("test.js"); + }); + }); it("should merge two panes to the right", function () { runs(function () { MainViewManager.setLayoutScheme(1, 2);