diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 068ec791..6baa972e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,42 +17,45 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 - + - name: Set LD_VERSION if: ${{ github.event_name == 'push'}} run: echo "LD_VERSION=${GITHUB_REF#refs/*/v}" >> $GITHUB_ENV - name: Set LD_VERSION if: ${{ github.event_name == 'workflow_dispatch'}} run: echo "LD_VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV - + - name: Set PUBLISH_TOKEN + run: echo "PUBLISH_TOKEN=${{ secrets.PUBLISH_TOKEN }}" >> $GITHUB_ENV + - name: Set up JDK 11 uses: actions/setup-java@v1 with: java-version: 11 - + - name: Grant execute permission for gradlew run: chmod +x gradlew - + - name: Build the plugin - run: ./gradlew buildPlugin + run: ./gradlew publishPlugin env: - LD_VERSION: ${{ env.LD_VERSION }} - - - name: Verify plugin - id: verify - uses: ChrisCarini/intellij-platform-plugin-verifier-action@v1.0.5 - with: - failure-levels: | - INVALID_PLUGIN - ide-versions: | - ideaIC:2021.1 - ideaIC:LATEST-EAP-SNAPSHOT - - - name: Print verify contents - run: | - echo "The log file path is: ${{steps.verify.outputs.verification-output-log-filename}}" ; - cat ${{steps.verify.outputs.verification-output-log-filename}} - + LD_VERSION: ${{ env.LD_VERSION }} + PUBLISH_TOKEN: ${{ env.PUBLISH_TOKEN }} + + # - name: Verify plugin + # id: verify + # uses: ChrisCarini/intellij-platform-plugin-verifier-action@v1.0.5 + # with: + # failure-levels: | + # INVALID_PLUGIN + # ide-versions: | + # ideaIC:2020.3 + # ideaIC:LATEST-EAP-SNAPSHOT + + # - name: Print verify contents + # run: | + # echo "The log file path is: ${{steps.verify.outputs.verification-output-log-filename}}" ; + # cat ${{steps.verify.outputs.verification-output-log-filename}} + - name: Create Release id: create_release uses: actions/create-release@v1 @@ -63,14 +66,14 @@ jobs: release_name: v${{ env.LD_VERSION }} draft: true prerelease: false - + - name: Upload Release Asset - id: upload-release-asset + id: upload-release-asset uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps asset_path: ./build/distributions/leetcode-editor-${{ env.LD_VERSION }}.zip asset_name: leetcode-editor-${{ env.LD_VERSION }}.zip - asset_content_type: application/zip + asset_content_type: application/zip diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..3a7719d1 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,37 @@ + + +# Leetcode Editor Changelog + +## 8.2.0 + +### Added +- 增加了不同的窗口,包括*分页窗口*、*全部题目窗口*、*[CodeTop](https://codetop.cc/?utm_source=leetcode_editor)窗口*,可以在导航栏中通过按钮切换. +- Added different windows, including paging window, all problem window, [CodeTop](https://codetop.cc/?utm_source=leetcode_editor) window, which can be switched by buttons in the navigation bar. + +- 增加数据统计信息存储,可配合[action](https://github.com/shuzijun/leetcode-editor/blob/master/action/README_ZH.md)生成勋章 +- Increase the storage of data statistics, you can use [action](https://github.com/shuzijun/leetcode-editor/tree/master/action) to generate medals + + +### Changed +- 修改消息通知方式 +- Modify the message notification method + +- 更改窗口位置 +- Change window position +### Deprecated + +### Fixed +- fix bugs + +### Removed + +## 0.0.0 + +### Added + +### Changed +- Snapshot + +### Deprecated + +### Removed \ No newline at end of file diff --git a/README.md b/README.md index a986dfa5..5e5a5baa 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,50 @@ -# leetcode-editor [](https://github.com/shuzijun/leetcode-editor/releases) [](https://github.com/shuzijun/leetcode-editor/actions?query=workflow%3ASnapshot) - - - [English Document](#Introduction) - - [中文文档](https://github.com/shuzijun/leetcode-editor/blob/master/README_ZH.md) - - - Useful Links - - [Login Help](https://github.com/shuzijun/leetcode-editor/blob/master/doc/LoginHelp.md) - - [Custom Code](https://github.com/shuzijun/leetcode-editor/blob/master/doc/CustomCode.md) ([demo](https://github.com/shuzijun/leetcode-question)) - +# [![Leetcode Editor][plugin-logo]][gh:leetcode-editor] Leetcode Editor + +[![Release][badge:release]][gh:releases] +[![Snapshot][badge:snapshot]][gh:snapshot] +[![License][badge:license]][gh:license] +[![Plugin Homepage][badge:plugin-homepage]][plugin-homepage] +[![Version][badge:version]][plugin-versions] +[![Pro Plugin Homepage][badge:plugin-homepage-pro]][plugin-homepage-pro] +[![Version][badge:pro-version]][plugin-versions-pro] +[![Downloads][badge:downloads]][plugin-homepage] +[![English Document][badge:en-doc]][gh:en-doc] +[![中文文档][badge:zh-doc]][gh:zh-doc] +[![捐赠][badge:donate]][shuzijun-donate] +[![内推][badge:referrals]][shuzijun-referrals] + +
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
");
+ } else {
+ context.delegateRender();
+ }
+ } else if (node.getChars().startsWith("
");
+ } else {
+ context.delegateRender();
+ }
} else {
context.delegateRender();
}
@@ -145,6 +160,13 @@ private void recursionElement(Element element) {
if (StringUtils.isNotBlank(src)) {
element.attr("src", formatUrl(src));
}
+ } else if ("code".equals(element.tagName())) {
+ if (element.parent() != null && "pre".equals(element.parent().tagName())) {
+ Element span = new Element("span");
+ element.before(span);
+ element.remove();
+ element.appendTo(span);
+ }
} else {
Elements elements = element.children();
for (Element element1 : elements) {
diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/ConsolePanel.java b/src/main/java/com/shuzijun/leetcode/plugin/window/ConsolePanel.java
new file mode 100644
index 00000000..a7800df3
--- /dev/null
+++ b/src/main/java/com/shuzijun/leetcode/plugin/window/ConsolePanel.java
@@ -0,0 +1,52 @@
+package com.shuzijun.leetcode.plugin.window;
+
+import com.intellij.execution.filters.TextConsoleBuilderFactory;
+import com.intellij.execution.ui.ConsoleView;
+import com.intellij.openapi.actionSystem.ActionManager;
+import com.intellij.openapi.actionSystem.ActionToolbar;
+import com.intellij.openapi.actionSystem.DataProvider;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.SimpleToolWindowPanel;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.wm.ToolWindow;
+import com.shuzijun.leetcode.plugin.model.PluginConstant;
+import com.shuzijun.leetcode.plugin.utils.DataKeys;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author shuzijun
+ */
+public class ConsolePanel extends SimpleToolWindowPanel implements DataProvider {
+
+ private ConsoleView consoleView;
+
+ public ConsolePanel(ToolWindow toolWindow, Project project) {
+ super(Boolean.FALSE, Boolean.TRUE);
+ this.consoleView = TextConsoleBuilderFactory.getInstance().createBuilder(project).getConsole();
+ SimpleToolWindowPanel toolWindowPanel = new SimpleToolWindowPanel(Boolean.FALSE, Boolean.TRUE);
+ toolWindowPanel.setContent(consoleView.getComponent());
+ setContent(toolWindowPanel);
+ final DefaultActionGroup consoleGroup = new DefaultActionGroup(consoleView.createConsoleActions());
+ ActionToolbar consoleToolbar = ActionManager.getInstance().createActionToolbar(PluginConstant.ACTION_PREFIX + " ConsoleToolbar", consoleGroup, true);
+ consoleToolbar.setTargetComponent(toolWindowPanel);
+ setToolbar(consoleToolbar.getComponent());
+
+ }
+
+ @Override
+ public @Nullable Object getData(@NotNull @NonNls String dataId) {
+ if (DataKeys.LEETCODE_CONSOLE_VIEW.is(dataId)) {
+ return consoleView;
+ }
+ return super.getData(dataId);
+ }
+
+ public void dispose() {
+ if (consoleView != null) {
+ Disposer.dispose(consoleView);
+ }
+ }
+}
diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/ConsoleWindowFactory.java b/src/main/java/com/shuzijun/leetcode/plugin/window/ConsoleWindowFactory.java
new file mode 100644
index 00000000..416da6b7
--- /dev/null
+++ b/src/main/java/com/shuzijun/leetcode/plugin/window/ConsoleWindowFactory.java
@@ -0,0 +1,45 @@
+package com.shuzijun.leetcode.plugin.window;
+
+import com.intellij.ide.DataManager;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.wm.ToolWindow;
+import com.intellij.openapi.wm.ToolWindowFactory;
+import com.intellij.openapi.wm.ToolWindowManager;
+import com.intellij.ui.content.Content;
+import com.shuzijun.leetcode.plugin.model.PluginConstant;
+import com.shuzijun.leetcode.plugin.setting.PersistentConfig;
+import icons.LeetCodeEditorIcons;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author shuzijun
+ */
+public class ConsoleWindowFactory implements ToolWindowFactory, DumbAware {
+
+ public static String ID = PluginConstant.CONSOLE_WINDOW_ID;
+
+
+ @Override
+ public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
+
+ ConsolePanel consolePanel = new ConsolePanel(toolWindow, project);
+ Content content = toolWindow.getContentManager().getFactory().createContent(consolePanel, "", true);
+ toolWindow.getContentManager().addContent(content);
+ if (PersistentConfig.getInstance().getInitConfig() != null && !PersistentConfig.getInstance().getInitConfig().getShowToolIcon()) {
+ toolWindow.setIcon(LeetCodeEditorIcons.EMPEROR_NEW_CLOTHES);
+ }
+ }
+
+ public static DataContext getDataContext(@NotNull Project project) {
+ ToolWindow leetcodeToolWindows = ToolWindowManager.getInstance(project).getToolWindow(ID);
+ ConsolePanel consolePanel = (ConsolePanel) leetcodeToolWindows.getContentManager().getContent(0).getComponent();
+ return DataManager.getInstance().getDataContext(consolePanel);
+ }
+
+ @Override
+ public boolean shouldBeAvailable(@NotNull Project project) {
+ return false;
+ }
+}
diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/CookieLogin.java b/src/main/java/com/shuzijun/leetcode/plugin/window/CookieLogin.java
deleted file mode 100644
index 6b97ceec..00000000
--- a/src/main/java/com/shuzijun/leetcode/plugin/window/CookieLogin.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package com.shuzijun.leetcode.plugin.window;
-
-import com.intellij.ide.BrowserUtil;
-import com.intellij.openapi.progress.ProgressIndicator;
-import com.intellij.openapi.progress.ProgressManager;
-import com.intellij.openapi.progress.Task;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.DialogWrapper;
-import com.intellij.ui.components.JBPanel;
-import com.intellij.ui.components.JBScrollPane;
-import com.shuzijun.leetcode.plugin.model.PluginConstant;
-import com.shuzijun.leetcode.plugin.utils.HttpRequestUtils;
-import com.shuzijun.leetcode.plugin.utils.PropertiesUtils;
-import com.shuzijun.leetcode.plugin.utils.URLUtils;
-import org.apache.commons.lang.StringUtils;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.ActionEvent;
-import java.net.HttpCookie;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author shuzijun
- */
-public class CookieLogin implements LoginFrame {
- private NavigatorTable navigatorTable;
- private Project project;
-
-
- public CookieLogin(Project project, NavigatorTable navigatorTable) {
- this.navigatorTable = navigatorTable;
- this.project = project;
- }
-
- @Override
- public void loadComponent() {
- CookiePanel cookiePanel = new CookiePanel(project);
- if (cookiePanel.showAndGet()) {
- String cookiesString = cookiePanel.cookieText();
- if (StringUtils.isBlank(cookiesString)) {
- JOptionPane.showMessageDialog(null, "cookie is null");
- return;
- }
- final List cookieList = new ArrayList<>();
- String[] cookies = cookiesString.split(";");
- for (String cookieString : cookies) {
- String[] cookie = cookieString.trim().split("=");
- if (cookie.length >= 2) {
- try {
- HttpCookie basicClientCookie = new HttpCookie(cookie[0], cookie[1]);
- basicClientCookie.setDomain("." + URLUtils.getLeetcodeHost());
- basicClientCookie.setPath("/");
- cookieList.add(basicClientCookie);
- } catch (IllegalArgumentException ignore) {
-
- }
- }
- }
- HttpRequestUtils.setCookie(cookieList);
-
- ProgressManager.getInstance().run(new Task.Backgroundable(project, PluginConstant.ACTION_PREFIX+".loginSuccess", false) {
- @Override
- public void run(@NotNull ProgressIndicator progressIndicator) {
- if (HttpRequestUtils.isLogin()) {
- HttpLogin.loginSuccess(navigatorTable, project, cookieList);
- } else {
- JOptionPane.showMessageDialog(null, PropertiesUtils.getInfo("login.failed"));
- }
-
- }
- });
- }
- }
-
- class CookiePanel extends DialogWrapper {
-
- private JPanel jpanel;
- private JTextArea caseText;
-
- public CookiePanel(Project project) {
- super(project, Boolean.TRUE);
-
- jpanel = new JBPanel();
- jpanel.setLayout(new BorderLayout());
- caseText = new JTextArea();
- caseText.setLineWrap(true);
- caseText.setMinimumSize(new Dimension(400, 200));
- caseText.setPreferredSize(new Dimension(400, 200));
- jpanel.add(new JBScrollPane(caseText, JBScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JBScrollPane.HORIZONTAL_SCROLLBAR_NEVER), BorderLayout.CENTER);
- setModal(true);
- init();
- setTitle("Cookie login");
- }
-
- @NotNull
- @Override
- protected Action getOKAction() {
- Action action = super.getOKAction();
- action.putValue(Action.NAME, "login");
- return action;
- }
-
- @NotNull
- @Override
- protected Action[] createActions() {
- Action helpAction = new AbstractAction() {
- @Override
- public void actionPerformed(ActionEvent e) {
- BrowserUtil.browse("https://github.com/shuzijun/leetcode-editor/blob/master/doc/LoginHelp.md");
- }
-
- };
- helpAction.putValue(Action.NAME, "help");
- Action[] actions = new Action[]{helpAction, this.getOKAction(), this.getCancelAction()};
- return actions;
- }
-
- @Nullable
- @Override
- protected JComponent createCenterPanel() {
- return jpanel;
- }
-
- public String cookieText() {
- return caseText.getText();
- }
- }
-}
diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/JcefLogin.java b/src/main/java/com/shuzijun/leetcode/plugin/window/JcefLogin.java
deleted file mode 100644
index 86f730e0..00000000
--- a/src/main/java/com/shuzijun/leetcode/plugin/window/JcefLogin.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package com.shuzijun.leetcode.plugin.window;
-
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.DialogWrapper;
-import com.intellij.openapi.util.Disposer;
-import com.intellij.ui.components.JBPanel;
-import com.intellij.ui.components.JBScrollPane;
-import com.intellij.ui.jcef.JCEFHtmlPanel;
-import com.shuzijun.leetcode.plugin.model.PluginConstant;
-import com.shuzijun.leetcode.plugin.utils.HttpRequestUtils;
-import com.shuzijun.leetcode.plugin.utils.LogUtils;
-import com.shuzijun.leetcode.plugin.utils.PropertiesUtils;
-import com.shuzijun.leetcode.plugin.utils.URLUtils;
-import org.cef.browser.CefBrowser;
-import org.cef.browser.CefFrame;
-import org.cef.callback.CefCookieVisitor;
-import org.cef.handler.CefLoadHandler;
-import org.cef.handler.CefLoadHandlerAdapter;
-import org.cef.misc.BoolRef;
-import org.cef.network.CefCookie;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-import java.awt.*;
-import java.net.HttpCookie;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author shuzijun
- */
-public class JcefLogin implements LoginFrame {
-
- private NavigatorTable navigatorTable;
- private Project project;
-
-
- public JcefLogin(Project project, NavigatorTable navigatorTable) {
- this.navigatorTable = navigatorTable;
- this.project = project;
- }
-
- @Override
- public void loadComponent() {
- JCEFPanel cookiePanel = new JCEFPanel(project);
- cookiePanel.show();
- }
-
-
- private class JCEFPanel extends DialogWrapper {
-
- private JPanel jpanel;
- private LoginJCEFPanel loginJCEFPanel;
-
- public JCEFPanel(Project project) {
- super(project, Boolean.TRUE);
-
- jpanel = new JBPanel();
- jpanel.setLayout(new BorderLayout());
- loginJCEFPanel = new LoginJCEFPanel();
- loginJCEFPanel.getComponent().setMinimumSize(new Dimension(1000, 500));
- loginJCEFPanel.getComponent().setPreferredSize(new Dimension(1000, 500));
- jpanel.add(new JBScrollPane(loginJCEFPanel.getComponent(), JBScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JBScrollPane.HORIZONTAL_SCROLLBAR_NEVER), BorderLayout.CENTER);
- setModal(true);
- init();
- setTitle("login");
- loginJCEFPanel.loadURL(URLUtils.getLeetcodeLogin());
- }
-
- @NotNull
- @Override
- protected Action[] createActions() {
- return new Action[]{};
- }
-
- @Nullable
- @Override
- protected JComponent createCenterPanel() {
- return jpanel;
- }
-
- @Override
- protected void dispose() {
- Disposer.dispose(loginJCEFPanel);
- super.dispose();
- }
- }
-
-
- private class LoginJCEFPanel extends JCEFHtmlPanel {
-
- private CefLoadHandlerAdapter cefLoadHandler;
-
- public LoginJCEFPanel() {
- super("about:blank");
- getJBCefClient().addLoadHandler(cefLoadHandler = new CefLoadHandlerAdapter() {
-
- boolean successDispose = false;
-
- @Override
- public void onLoadError(CefBrowser browser, CefFrame frame, CefLoadHandler.ErrorCode errorCode, String errorText, String failedUrl) {
- if (!successDispose) {
- browser.executeJavaScript("alert('The page failed to load, please check the network and open it again')", PluginConstant.PLUGIN_ID, 0);
- }
- }
-
- @Override
- public void onLoadingStateChange(CefBrowser browser, boolean isLoading, boolean canGoBack, boolean canGoForward) {
-
- getJBCefCookieManager().getCefCookieManager().visitAllCookies(new CefCookieVisitor() {
-
- private List cookieList = new ArrayList<>();
-
- @Override
- public boolean visit(CefCookie cefCookie, int count, int total, BoolRef boolRef) {
-
- boolean isSession = Boolean.FALSE;
- if (cefCookie.domain.contains("leetcode")) {
- HttpCookie cookie = new HttpCookie(cefCookie.name, cefCookie.value);
- cookie.setDomain(cefCookie.domain);
- cookie.setPath(cefCookie.path);
- cookieList.add(cookie);
- if ("LEETCODE_SESSION".equals(cefCookie.name)) {
- isSession = Boolean.TRUE;
- }
- }
- if (count == total - 1 && isSession) {
- HttpRequestUtils.setCookie(cookieList);
- if (HttpRequestUtils.isLogin()) {
- HttpLogin.loginSuccess(navigatorTable, project, cookieList);
- browser.executeJavaScript("alert('"+ PropertiesUtils.getInfo("browser.login.success") +"')", "leetcode-editor", 0);
- successDispose = true;
- } else {
- cookieList.clear();
- LogUtils.LOG.info("login failure");
- }
- }
- return true;
- }
- });
- }
- }, getCefBrowser());
- }
-
- @Override
- public void dispose() {
- getJBCefClient().removeLoadHandler(cefLoadHandler,getCefBrowser());
- getJBCefBrowser(getCefBrowser()).getJBCefCookieManager().deleteCookies(URLUtils.leetcode, false);
- getJBCefBrowser(getCefBrowser()).getJBCefCookieManager().deleteCookies(URLUtils.leetcodecn, false);
- super.dispose();
- }
- }
-
-}
diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/LoginFrame.java b/src/main/java/com/shuzijun/leetcode/plugin/window/LoginFrame.java
deleted file mode 100644
index 59afdc9e..00000000
--- a/src/main/java/com/shuzijun/leetcode/plugin/window/LoginFrame.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.shuzijun.leetcode.plugin.window;
-
-/**
- * @author shuzijun
- */
-public interface LoginFrame {
-
- public void loadComponent();
-
-}
diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/NavigatorPanel.java b/src/main/java/com/shuzijun/leetcode/plugin/window/NavigatorPanel.java
deleted file mode 100644
index 082fea82..00000000
--- a/src/main/java/com/shuzijun/leetcode/plugin/window/NavigatorPanel.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package com.shuzijun.leetcode.plugin.window;
-
-
-import com.intellij.openapi.actionSystem.ActionManager;
-import com.intellij.openapi.actionSystem.ActionToolbar;
-import com.intellij.openapi.actionSystem.DataProvider;
-import com.intellij.openapi.actionSystem.DefaultActionGroup;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.SimpleToolWindowPanel;
-import com.intellij.openapi.wm.ToolWindow;
-import com.intellij.ui.components.JBTextField;
-import com.shuzijun.leetcode.plugin.listener.QueryKeyListener;
-import com.shuzijun.leetcode.plugin.model.PluginConstant;
-import com.shuzijun.leetcode.plugin.utils.DataKeys;
-
-import javax.swing.*;
-
-/**
- * @author shuzijun
- */
-public class NavigatorPanel extends SimpleToolWindowPanel implements DataProvider {
-
-
- private JPanel queryPanel;
- private NavigatorTable navigatorTable;
- private ActionToolbar findToolbar;
- private ActionToolbar actionSortToolbar;
-
- public NavigatorPanel(ToolWindow toolWindow, Project project) {
- super(Boolean.TRUE, Boolean.TRUE);
- final ActionManager actionManager = ActionManager.getInstance();
-
- navigatorTable = new NavigatorTable(project);
-
- ActionToolbar actionToolbar = actionManager.createActionToolbar(PluginConstant.ACTION_PREFIX + " Toolbar",
- (DefaultActionGroup) actionManager.getAction(PluginConstant.LEETCODE_NAVIGATOR_ACTIONS_TOOLBAR),
- true);
- actionToolbar.setTargetComponent(navigatorTable);
- setToolbar(actionToolbar.getComponent());
-
- SimpleToolWindowPanel toolWindowPanel = new SimpleToolWindowPanel(Boolean.TRUE, Boolean.TRUE);
-
- toolWindowPanel.setContent(navigatorTable);
-
- queryPanel = new JPanel();
- queryPanel.setLayout(new BoxLayout(queryPanel, BoxLayout.Y_AXIS));
- JTextField queryField = new JBTextField();
- queryField.setToolTipText("Enter Search");
- queryField.addKeyListener(new QueryKeyListener(queryField, navigatorTable, project));
- queryPanel.add(queryField);
-
- findToolbar = actionManager.createActionToolbar(PluginConstant.LEETCODE_FIND_TOOLBAR,
- (DefaultActionGroup) actionManager.getAction(PluginConstant.LEETCODE_FIND_TOOLBAR),
- true);
- findToolbar.setTargetComponent(navigatorTable);
- actionSortToolbar = actionManager.createActionToolbar(PluginConstant.LEETCODE_FIND_SORT_TOOLBAR,
- (DefaultActionGroup) actionManager.getAction(PluginConstant.LEETCODE_FIND_SORT_TOOLBAR),
- true);
- actionSortToolbar.setTargetComponent(navigatorTable);
- queryPanel.add(findToolbar.getComponent());
- queryPanel.add(actionSortToolbar.getComponent());
-
- queryPanel.setVisible(false);
- toolWindowPanel.setToolbar(queryPanel);
- setContent(toolWindowPanel);
-
- }
-
- @Override
- public Object getData(String dataId) {
- if (DataKeys.LEETCODE_PROJECTS_TREE.is(dataId)) {
- return navigatorTable;
- }
-
- if (DataKeys.LEETCODE_PROJECTS_TERRFIND.is(dataId)) {
- return queryPanel;
- }
-
- if (DataKeys.LEETCODE_TOOLBAR_FIND.is(dataId)) {
- return findToolbar;
- }
- if (DataKeys.LEETCODE_TOOLBAR_SORT.is(dataId)) {
- return actionSortToolbar;
- }
- return super.getData(dataId);
- }
-}
diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/NavigatorPanelAction.java b/src/main/java/com/shuzijun/leetcode/plugin/window/NavigatorPanelAction.java
new file mode 100644
index 00000000..d66af933
--- /dev/null
+++ b/src/main/java/com/shuzijun/leetcode/plugin/window/NavigatorPanelAction.java
@@ -0,0 +1,10 @@
+package com.shuzijun.leetcode.plugin.window;
+
+import com.shuzijun.leetcode.plugin.manager.NavigatorAction;
+
+/**
+ * @author shuzijun
+ */
+public interface NavigatorPanelAction {
+ NavigatorAction getNavigatorAction();
+}
diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/NavigatorTable.java b/src/main/java/com/shuzijun/leetcode/plugin/window/NavigatorTable.java
deleted file mode 100644
index 55733a18..00000000
--- a/src/main/java/com/shuzijun/leetcode/plugin/window/NavigatorTable.java
+++ /dev/null
@@ -1,378 +0,0 @@
-package com.shuzijun.leetcode.plugin.window;
-
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.progress.ProgressIndicator;
-import com.intellij.openapi.progress.ProgressManager;
-import com.intellij.openapi.progress.Task;
-import com.intellij.openapi.project.Project;
-import com.intellij.ui.components.JBScrollPane;
-import com.intellij.ui.table.JBTable;
-import com.shuzijun.leetcode.plugin.listener.JTableKeyAdapter;
-import com.shuzijun.leetcode.plugin.listener.QuestionStatusListener;
-import com.shuzijun.leetcode.plugin.listener.TreeMouseListener;
-import com.shuzijun.leetcode.plugin.manager.ViewManager;
-import com.shuzijun.leetcode.plugin.model.Config;
-import com.shuzijun.leetcode.plugin.model.PageInfo;
-import com.shuzijun.leetcode.plugin.model.Question;
-import com.shuzijun.leetcode.plugin.setting.PersistentConfig;
-import com.shuzijun.leetcode.plugin.utils.PropertiesUtils;
-import icons.LeetCodeEditorIcons;
-import org.jetbrains.annotations.NotNull;
-
-import javax.swing.*;
-import javax.swing.table.DefaultTableModel;
-import javax.swing.table.JTableHeader;
-import javax.swing.table.TableCellRenderer;
-import java.awt.*;
-import java.awt.event.ItemEvent;
-import java.awt.event.MouseEvent;
-import java.text.NumberFormat;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author shuzijun
- */
-public class NavigatorTable extends JPanel {
-
- private static Color Level1 = new Color(92, 184, 92);
- private static Color Level2 = new Color(240, 173, 78);
- private static Color Level3 = new Color(217, 83, 79);
- private static Color defColor = null;
-
- private boolean first = true;
-
- private JBTable table;
- private MyTableModel tableModel;
- private Project project;
-
- private List questionList;
- private JComboBox page;
- private PageInfo pageInfo = new PageInfo<>(1, 50);
-
-
- public NavigatorTable(Project project) {
- super(new BorderLayout());
- this.project = project;
- loaColor();
- tableModel = new MyTableModel();
- table = new JBTable(tableModel) {
- @Override
- public String getToolTipText(MouseEvent e) {
- int row = table.rowAtPoint(e.getPoint());
- int col = table.columnAtPoint(e.getPoint());
- String tipTextString = null;
- if (row > -1 && col == 1) {
- Object value = table.getValueAt(row, col);
- if (null != value && !"".equals(value))
- tipTextString = value.toString();
- }
- return tipTextString;
- }
-
- @Override
- protected JTableHeader createDefaultTableHeader() {
- return new JTableHeader(columnModel) {
- public String getToolTipText(MouseEvent e) {
- java.awt.Point p = e.getPoint();
- int index = columnModel.getColumnIndexAtX(p.x);
- int realIndex = columnModel.getColumn(index).getModelIndex();
- return MyTableModel.columnName[realIndex];
- }
- };
- }
-
- @Override
- public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
- if (first) {
- if (row == 0 && column == 0) {
- return firstToolTip();
- } else {
- return super.prepareRenderer(renderer, row, column);
- }
- }
- Component component = super.prepareRenderer(renderer, row, column);
- if (defColor == null) {
- synchronized (NavigatorTable.class) {
- if (defColor == null) {
- defColor = component.getForeground();
- }
- }
- }
- DefaultTableModel model = (DefaultTableModel) this.getModel();
- if (column == 3) {
- Object value = model.getValueAt(row, column);
- if (value != null) {
- if (value.toString().equals("Easy")) {
- component.setForeground(Level1);
- } else if (value.toString().equals("Medium")) {
- component.setForeground(Level2);
- } else if (value.toString().equals("Hard")) {
- component.setForeground(Level3);
- }
- } else {
- component.setForeground(defColor);
- }
- } else {
- component.setForeground(defColor);
- }
- return component;
- }
- };
- table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- table.getTableHeader().setReorderingAllowed(false);
- table.setRowSelectionAllowed(true);
- table.setFillsViewportHeight(true);
- table.addMouseListener(new TreeMouseListener(this, project));
- table.addKeyListener(new JTableKeyAdapter(this, project));
- table.setRowHeight(0, 200);
-
- this.add(new JBScrollPane(table, JBScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JBScrollPane.HORIZONTAL_SCROLLBAR_NEVER), BorderLayout.CENTER);
- this.add(paging(), BorderLayout.SOUTH);
-
- project.getMessageBus().connect().subscribe(QuestionStatusListener.QUESTION_STATUS_TOPIC, new QuestionStatusListener() {
- @Override
- public void updateTable(Question question) {
- if (questionList != null) {
- for (Question q : questionList) {
- if (q.getTitleSlug().equals(question.getTitleSlug())) {
- q.setStatus(question.getStatus());
- refreshData();
- break;
- }
- }
- }
- }
- });
- }
-
- public static void loaColor() {
- Config config = PersistentConfig.getInstance().getInitConfig();
- if (config != null) {
- Color[] colors = config.getFormatLevelColour();
- Level1 = colors[0];
- Level2 = colors[1];
- Level3 = colors[2];
- }
- }
-
- private Component paging() {
- JPanel paging = new JPanel(new BorderLayout());
- Integer[] pageSizeData = {20, 50, 100};
- JComboBox pageSizeBox = new JComboBox(pageSizeData);
- pageSizeBox.setPreferredSize(new Dimension(60, -1));
- pageSizeBox.setSelectedItem(50);
- pageSizeBox.addItemListener(e -> {
- if (e.getStateChange() == ItemEvent.SELECTED) {
- pageInfo.setPageSize((Integer) e.getItem());
- }
- });
- paging.add(pageSizeBox, BorderLayout.WEST);
-
- JPanel control = new JPanel(new BorderLayout());
- JButton previous = new JButton("<");
- previous.setToolTipText("Previous");
- previous.setPreferredSize(new Dimension(50, -1));
- previous.setMaximumSize(new Dimension(50, -1));
- previous.addActionListener(event -> {
- if (page.getItemCount() <= 0 || (int) page.getSelectedItem() < 2) {
- return;
- } else {
- pageInfo.setPageIndex((int) page.getSelectedItem() - 1);
- NavigatorTable pNavigatorTable = this;
- ProgressManager.getInstance().run(new Task.Backgroundable(project, "Previous", false) {
- @Override
- public void run(@NotNull ProgressIndicator progressIndicator) {
- ViewManager.loadServiceData(pNavigatorTable, project);
- }
- });
- }
-
- });
- control.add(previous, BorderLayout.WEST);
- JButton next = new JButton(">");
- next.setToolTipText("Next");
- next.setPreferredSize(new Dimension(50, -1));
- next.setMaximumSize(new Dimension(50, -1));
- next.addActionListener(event -> {
- if (page.getItemCount() <= 0 || (int) page.getSelectedItem() >= page.getItemCount()) {
- return;
- } else {
- pageInfo.setPageIndex((int) page.getSelectedItem() + 1);
- NavigatorTable pNavigatorTable = this;
- ProgressManager.getInstance().run(new Task.Backgroundable(project, "Next", false) {
- @Override
- public void run(@NotNull ProgressIndicator progressIndicator) {
- ViewManager.loadServiceData(pNavigatorTable, project);
- }
- });
- }
-
- });
- control.add(next, BorderLayout.EAST);
- page = new JComboBox();
- control.add(page, BorderLayout.CENTER);
- paging.add(control, BorderLayout.CENTER);
-
- JButton go = new JButton("Go");
- go.setPreferredSize(new Dimension(50, -1));
- go.setMaximumSize(new Dimension(50, -1));
- go.addActionListener(event -> {
- if (page.getItemCount() <= 0) {
- return;
- } else {
- pageInfo.setPageIndex((int) page.getSelectedItem());
- NavigatorTable pNavigatorTable = this;
- ProgressManager.getInstance().run(new Task.Backgroundable(project, "Go to", false) {
- @Override
- public void run(@NotNull ProgressIndicator progressIndicator) {
- ViewManager.loadServiceData(pNavigatorTable, project);
- }
- });
- }
-
- });
- paging.add(go, BorderLayout.EAST);
-
- return paging;
- }
-
- public int getPageIndex() {
- if (page.getItemCount() <= 0) {
- return 1;
- } else {
- return (int) page.getSelectedItem();
- }
- }
-
- public PageInfo getPageInfo() {
- return pageInfo;
- }
-
- public void refreshData() {
- ApplicationManager.getApplication().invokeLater(() -> {
- this.tableModel.updateData(questionList);
- setColumnWidth();
- });
- }
-
- public void loadData(PageInfo pageInfo) {
- ApplicationManager.getApplication().invokeLater(() -> {
- if (this.first) {
- this.tableModel.setRowCount(0);
- this.tableModel.setColumnCount(5);
- this.first = false;
- }
- this.questionList = pageInfo.getRows();
- this.tableModel.updateData(questionList);
- setColumnWidth();
- });
- if (pageInfo.getPageTotal() != this.page.getItemCount()) {
- this.page.removeAllItems();
- for (int i = 1; i <= pageInfo.getPageTotal(); i++) {
- this.page.addItem(i);
- }
- }
- this.page.setSelectedItem(pageInfo.getPageIndex());
- this.pageInfo = pageInfo;
- }
-
- public Question getSelectedRowData() {
- int row = table.getSelectedRow();
- if (row < 0 || questionList == null || row >= questionList.size()) {
- return null;
- }
- return questionList.get(row);
- }
-
- private void setColumnWidth() {
- table.getColumnModel().getColumn(0).setMaxWidth(40);
- table.getColumnModel().getColumn(2).setMaxWidth(50);
- table.getColumnModel().getColumn(3).setMaxWidth(60);
- table.getColumnModel().getColumn(4).setMaxWidth(50);
- }
-
- private JTextPane firstToolTip() {
- JTextPane myPane = new JTextPane();
- myPane.setOpaque(false);
- String addIconText = "'login'";
- String refreshIconText = "'refresh'";
- String configIconText = "'config'";
- String message = PropertiesUtils.getInfo("config.load", addIconText, refreshIconText, configIconText);
- int addIconMarkerIndex = message.indexOf(addIconText);
- myPane.replaceSelection(message.substring(0, addIconMarkerIndex));
- myPane.insertIcon(LeetCodeEditorIcons.LOGIN);
- int refreshIconMarkerIndex = message.indexOf(refreshIconText);
- myPane.replaceSelection(message.substring(addIconMarkerIndex + addIconText.length(), refreshIconMarkerIndex));
- myPane.insertIcon(LeetCodeEditorIcons.REFRESH);
- int configIconMarkerIndex = message.indexOf(configIconText);
- myPane.replaceSelection(message.substring(refreshIconMarkerIndex + refreshIconText.length(), configIconMarkerIndex));
- myPane.insertIcon(LeetCodeEditorIcons.CONFIG);
- myPane.replaceSelection(message.substring(configIconMarkerIndex + configIconText.length()));
- return myPane;
- }
-
- private static class MyTableModel extends DefaultTableModel {
-
- private NumberFormat nf = NumberFormat.getPercentInstance();
-
- public static String[] columnName = {"Status", "Title", "Acceptance", "Difficulty", "Frequency"};
- private static String[] columnNameShort = {"STAT", "Title", "AC", "DD", "F"};
-
- public MyTableModel() {
- super(new Object[]{"info"}, 1);
- nf.setMinimumFractionDigits(1);
- nf.setMaximumFractionDigits(1);
- }
-
- public Object getValue(Question question, int columnIndex) {
- if (columnIndex == 0) {
- return question.getStatusSign();
- }
- if (columnIndex == 1) {
- return question.getFormTitle();
- }
-
- if (columnIndex == 2) {
- return nf.format(question.getAcceptance());
- }
-
- if (columnIndex == 3) {
- Integer level = question.getLevel();
- if (level == 1) {
- return "Easy";
- } else if (level == 2) {
- return "Medium";
- } else if (level == 3) {
- return "Hard";
- } else {
- return level;
- }
- }
- if (columnIndex == 4) {
- return nf.format(question.getFrequency());
- }
- return null;
- }
-
- @Override
- public boolean isCellEditable(int row, int column) {
- return false;
- }
-
- public void updateData(List questionList) {
- if (questionList == null) {
- questionList = new ArrayList<>();
- }
- Object[][] dataVector = new Object[questionList.size()][columnName.length];
- for (int i = 0; i < questionList.size(); i++) {
- Object[] line = new Object[columnName.length];
- for (int j = 0; j < columnName.length; j++) {
- line[j] = getValue(questionList.get(i), j);
- }
- dataVector[i] = line;
- }
- setDataVector(dataVector, MyTableModel.columnNameShort);
- }
- }
-}
diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/NavigatorTableData.java b/src/main/java/com/shuzijun/leetcode/plugin/window/NavigatorTableData.java
new file mode 100644
index 00000000..a460fda1
--- /dev/null
+++ b/src/main/java/com/shuzijun/leetcode/plugin/window/NavigatorTableData.java
@@ -0,0 +1,441 @@
+package com.shuzijun.leetcode.plugin.window;
+
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.progress.Task;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.io.FileUtilRt;
+import com.intellij.ui.components.JBPanel;
+import com.intellij.ui.components.JBScrollPane;
+import com.intellij.ui.table.JBTable;
+import com.intellij.util.messages.MessageBusConnection;
+import com.shuzijun.leetcode.plugin.listener.ConfigNotifier;
+import com.shuzijun.leetcode.plugin.listener.QuestionStatusNotifier;
+import com.shuzijun.leetcode.plugin.model.Config;
+import com.shuzijun.leetcode.plugin.model.Graphql;
+import com.shuzijun.leetcode.plugin.model.PageInfo;
+import com.shuzijun.leetcode.plugin.model.Question;
+import com.shuzijun.leetcode.plugin.utils.LogUtils;
+import com.shuzijun.leetcode.plugin.window.navigator.TopNavigatorTable;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.table.JTableHeader;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.text.*;
+import java.awt.*;
+import java.awt.event.ItemEvent;
+import java.awt.event.MouseEvent;
+import java.io.InputStream;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * @author shuzijun
+ */
+public abstract class NavigatorTableData extends JPanel implements Disposable {
+
+
+ protected static volatile Color defColor = null;
+
+ protected Color Level1 = new Color(92, 184, 92);
+ protected Color Level2 = new Color(240, 173, 78);
+ protected Color Level3 = new Color(217, 83, 79);
+
+ private final MyJBTable myTable;
+ private final MyTableModel myTableModel;
+ private final Project project;
+ private List myList;
+ private final PageInfo myPageInfo;
+ private final PagePanel myPagePanel;
+ private final JComponent firstToolTip;
+ private boolean first = true;
+
+ public NavigatorTableData(Project project) {
+ super(new BorderLayout());
+ this.project = project;
+ this.myTableModel = createMyTableModel();
+ this.myTable = createMyTable(myTableModel, project);
+ this.myPageInfo = createMyPageInfo();
+ this.myPagePanel = createMyPagePanel(myPageInfo, project);
+ this.firstToolTip = firstToolTip();
+ this.add(firstToolTip, BorderLayout.CENTER);
+ MessageBusConnection messageBusConnection = ApplicationManager.getApplication().getMessageBus().connect(this);
+ messageBusConnection.subscribe(ConfigNotifier.TOPIC, (oldConfig, newConfig) -> loaColor(newConfig));
+ messageBusConnection.subscribe(QuestionStatusNotifier.QUESTION_STATUS_TOPIC, question -> {
+ if (myList != null) {
+ for (T q : myList) {
+ if (dataNotifier(q, question)) {
+ refreshData();
+ break;
+ }
+ }
+
+ }
+ });
+
+ }
+
+ protected abstract boolean dataNotifier(T myData, Question question);
+
+ protected PageInfo createMyPageInfo() {
+ return new PageInfo<>(1, 50);
+ }
+
+ protected abstract PagePanel createMyPagePanel(PageInfo myPageInfo, Project project);
+
+ protected abstract MyJBTable createMyTable(MyTableModel myTableModel, Project project);
+
+ protected abstract MyTableModel createMyTableModel();
+
+ private void loaColor(Config config) {
+ if (config != null) {
+ Color[] colors = config.getFormatLevelColour();
+ Level1 = colors[0];
+ Level2 = colors[1];
+ Level3 = colors[2];
+ }
+ }
+
+
+ public T getSelectedRowData() {
+ int row = myTable.getSelectedRow();
+ if (row < 0 || myList == null || row >= myList.size()) {
+ return null;
+ }
+ return myList.get(row);
+ }
+
+
+ public PageInfo getPageInfo() {
+ return myPageInfo;
+ }
+
+ private void refreshData() {
+ ApplicationManager.getApplication().invokeLater(() -> {
+ this.myTableModel.updateData(myList);
+ setColumnWidth(myTable);
+ });
+ }
+
+ public void refreshData(String selectTitleSlug) {
+ ApplicationManager.getApplication().invokeLater(() -> {
+ if (first) {
+ this.remove(firstToolTip);
+ this.add(new JBScrollPane(myTable, JBScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JBScrollPane.HORIZONTAL_SCROLLBAR_NEVER), BorderLayout.CENTER);
+ if (myPagePanel != null) {
+ this.add(myPagePanel, BorderLayout.SOUTH);
+ }
+ first = false;
+ }
+ this.myList = myPageInfo.getRows();
+ this.myTableModel.updateData(myList);
+ setColumnWidth(myTable);
+ myTable.requestFocusInWindow();
+ if (selectTitleSlug != null) {
+ selectedRow(selectTitleSlug);
+ }
+ if (myPagePanel != null) {
+ if (myPageInfo.getPageTotal() != this.myPagePanel.page.getItemCount()) {
+ this.myPagePanel.page.removeAllItems();
+ for (int i = 1; i <= myPageInfo.getPageTotal(); i++) {
+ this.myPagePanel.page.addItem(i);
+ }
+ }
+ this.myPagePanel.page.setSelectedItem(myPageInfo.getPageIndex());
+ }
+ });
+
+ }
+
+ public boolean selectedRow(String titleSlug) {
+ if (myList == null || myList.size() == 0) {
+ return false;
+ }
+ for (int i = 0; i < myList.size(); i++) {
+ if (compareSlug(myList.get(i), titleSlug)) {
+ int finalI = i;
+ ApplicationManager.getApplication().invokeLater(() -> {
+ myTable.setRowSelectionInterval(finalI, finalI);
+ myTable.scrollRectToVisible(myTable.getCellRect(finalI, 0, true));
+ });
+
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public PagePanel getPagePanel() {
+ return myPagePanel;
+ }
+
+ protected abstract void setColumnWidth(MyJBTable myJBTable);
+
+ public abstract boolean compareSlug(T myData, String titleSlug);
+
+ protected abstract JTextPane firstToolTip();
+
+ @Override
+ public void dispose() {
+ }
+
+ protected JTextPane createTip(String type, List icons, List styleList) {
+ String cn = Locale.getDefault().getLanguage().equals(Locale.CHINESE.getLanguage()) ? "_cn" : "";
+ JTextPane myPane = new JTextPane();
+ myPane.setOpaque(false);
+ try (InputStream inputStream = Graphql.GraphqlBuilder.class.getResourceAsStream("/template/" + type + cn + ".txt")) {
+ if (inputStream == null) {
+ LogUtils.LOG.error("/template/" + type + cn + ".txt Path is empty");
+ } else {
+ String templateTxt = new String(FileUtilRt.loadBytes(inputStream));
+ int startIndex = 0;
+ for (int i = 0; i < icons.size(); i++) {
+ String placeholder = "{" + i + "}";
+ int endIndex = templateTxt.indexOf(placeholder);
+ if (endIndex == -1) {
+ continue;
+ }
+ myPane.replaceSelection(templateTxt.substring(startIndex, endIndex));
+ myPane.insertIcon(icons.get(i));
+ startIndex = endIndex + placeholder.length();
+ }
+ myPane.replaceSelection(templateTxt.substring(startIndex));
+
+ StyledDocument document = myPane.getStyledDocument();
+ for (MyStyle myStyle : styleList) {
+ document.setCharacterAttributes(myStyle.offset, myStyle.length, myStyle.s, false);
+ }
+ }
+ } catch (Exception e) {
+ LogUtils.LOG.error("/template/" + type + cn + ".txt Loading exception", e);
+ }
+ return myPane;
+ }
+
+ protected static abstract class MyTableModel extends DefaultTableModel {
+
+ protected NumberFormat nf = NumberFormat.getPercentInstance();
+
+ protected String[] columnName;
+ protected String[] columnNameShort;
+
+ public MyTableModel(String[] columnName, String[] columnNameShort) {
+ super(new Object[]{"info"}, 1);
+ this.columnName = columnName;
+ this.columnNameShort = columnNameShort;
+ nf.setMinimumFractionDigits(1);
+ nf.setMaximumFractionDigits(1);
+ }
+
+ public abstract Object getValue(T question, int columnIndex);
+
+ @Override
+ public boolean isCellEditable(int row, int column) {
+ return false;
+ }
+
+ public void updateData(List questionList) {
+ if (questionList == null) {
+ questionList = new ArrayList<>();
+ }
+ Object[][] dataVector = new Object[questionList.size()][columnName.length];
+ for (int i = 0; i < questionList.size(); i++) {
+ Object[] line = new Object[columnName.length];
+ for (int j = 0; j < columnName.length; j++) {
+ line[j] = getValue(questionList.get(i), j);
+ }
+ dataVector[i] = line;
+ }
+ setDataVector(dataVector, columnNameShort);
+ }
+ }
+
+ protected static abstract class MyJBTable extends JBTable {
+
+ private final MyTableModel myTableModel;
+
+ public MyJBTable(MyTableModel model) {
+ super(model);
+ this.myTableModel = model;
+ }
+
+ @Override
+ public String getToolTipText(MouseEvent e) {
+ int row = this.rowAtPoint(e.getPoint());
+ int col = this.columnAtPoint(e.getPoint());
+ String tipTextString = null;
+ if (row > -1 && col == 1) {
+ Object value = this.getValueAt(row, col);
+ if (null != value && !"".equals(value)) tipTextString = value.toString();
+ }
+ return tipTextString;
+ }
+
+ @Override
+ protected @NotNull JTableHeader createDefaultTableHeader() {
+ return new JTableHeader(columnModel) {
+ public String getToolTipText(MouseEvent e) {
+ Point p = e.getPoint();
+ int index = columnModel.getColumnIndexAtX(p.x);
+ int realIndex = columnModel.getColumn(index).getModelIndex();
+ return myTableModel.columnName[realIndex];
+ }
+ };
+ }
+
+ @Override
+ public @NotNull Component prepareRenderer(@NotNull TableCellRenderer renderer, int row, int column) {
+ Component component = super.prepareRenderer(renderer, row, column);
+ if (defColor == null) {
+ synchronized (TopNavigatorTable.class) {
+ if (defColor == null) {
+ defColor = component.getForeground();
+ }
+ }
+ }
+ DefaultTableModel model = (DefaultTableModel) this.getModel();
+ Object value = model.getValueAt(row, column);
+ prepareRenderer(component, value, row, column);
+ return component;
+ }
+
+
+ protected abstract void prepareRenderer(Component component, Object value, int row, int column);
+ }
+
+ public static abstract class PagePanel extends JBPanel {
+ protected JComboBox pageSizeBox;
+ protected JButton previous;
+ protected JButton next;
+ protected JButton go;
+ protected JComboBox page;
+
+ public PagePanel(Project project, PageInfo pageInfo) {
+ super(new BorderLayout());
+ pageSizeBox = new JComboBox(pageSizeData());
+ pageSizeBox.setPreferredSize(new Dimension(60, -1));
+ pageSizeBox.setSelectedItem(pageInfo.getPageSize());
+ pageSizeBox.addItemListener(e -> {
+ if (e.getStateChange() == ItemEvent.SELECTED) {
+ pageInfo.setPageSize((Integer) e.getItem());
+ }
+ });
+ add(pageSizeBox, BorderLayout.WEST);
+
+ JPanel control = new JPanel(new BorderLayout());
+ previous = new JButton("<");
+ previous.setToolTipText("Previous");
+ previous.setPreferredSize(new Dimension(50, -1));
+ previous.setMaximumSize(new Dimension(50, -1));
+ previous.addActionListener(event -> {
+ if (page.getItemCount() <= 0 || (int) page.getSelectedItem() < 2) {
+ } else {
+ pageInfo.setPageIndex((int) page.getSelectedItem() - 1);
+ ProgressManager.getInstance().run(new Task.Backgroundable(project, "Previous", false) {
+ @Override
+ public void run(@NotNull ProgressIndicator progressIndicator) {
+ previousRunnable();
+ }
+ });
+ }
+
+ });
+ control.add(previous, BorderLayout.WEST);
+ next = new JButton(">");
+ next.setToolTipText("Next");
+ next.setPreferredSize(new Dimension(50, -1));
+ next.setMaximumSize(new Dimension(50, -1));
+ next.addActionListener(event -> {
+ if (page.getItemCount() <= 0 || (int) page.getSelectedItem() >= page.getItemCount()) {
+ return;
+ } else {
+ pageInfo.setPageIndex((int) page.getSelectedItem() + 1);
+ ProgressManager.getInstance().run(new Task.Backgroundable(project, "Next", false) {
+ @Override
+ public void run(@NotNull ProgressIndicator progressIndicator) {
+ nextRunnable();
+ }
+ });
+ }
+
+ });
+ control.add(next, BorderLayout.EAST);
+ page = new JComboBox();
+ control.add(page, BorderLayout.CENTER);
+ add(control, BorderLayout.CENTER);
+
+ go = new JButton("Go");
+ go.setPreferredSize(new Dimension(50, -1));
+ go.setMaximumSize(new Dimension(50, -1));
+ go.addActionListener(event -> {
+ if (page.getItemCount() <= 0) {
+ return;
+ } else {
+ pageInfo.setPageIndex((int) page.getSelectedItem());
+ ProgressManager.getInstance().run(new Task.Backgroundable(project, "Go to", false) {
+ @Override
+ public void run(@NotNull ProgressIndicator progressIndicator) {
+ goRunnable();
+ }
+ });
+ }
+
+ });
+ add(go, BorderLayout.EAST);
+ }
+
+ public abstract Integer[] pageSizeData();
+
+ public abstract void previousRunnable();
+
+ public abstract void nextRunnable();
+
+ public abstract void goRunnable();
+
+ public int getPageIndex() {
+ if (page.getItemCount() <= 0) {
+ return 1;
+ } else {
+ return (int) page.getSelectedItem();
+ }
+ }
+
+ public void focusedPageSize() {
+ pageSizeBox.requestFocusInWindow();
+ }
+
+ public void focusedPage() {
+ page.requestFocusInWindow();
+ }
+
+ public void clickPrevious() {
+ previous.doClick();
+ }
+
+ public void clickNext() {
+ next.doClick();
+ }
+
+ public void clickGo() {
+ go.doClick();
+ }
+ }
+
+ public static class MyStyle {
+ private int offset;
+ private int length;
+ private AttributeSet s;
+
+ public MyStyle(int offset, int length, AttributeSet s) {
+ this.offset = offset;
+ this.length = length;
+ this.s = s;
+ }
+ }
+}
diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/NavigatorTabsPanel.java b/src/main/java/com/shuzijun/leetcode/plugin/window/NavigatorTabsPanel.java
new file mode 100644
index 00000000..bf29c680
--- /dev/null
+++ b/src/main/java/com/shuzijun/leetcode/plugin/window/NavigatorTabsPanel.java
@@ -0,0 +1,260 @@
+package com.shuzijun.leetcode.plugin.window;
+
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.SimpleToolWindowPanel;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.wm.ToolWindow;
+import com.intellij.ui.tabs.TabInfo;
+import com.intellij.ui.tabs.impl.JBTabsImpl;
+import com.intellij.util.messages.MessageBusConnection;
+import com.shuzijun.leetcode.plugin.listener.ConfigNotifier;
+import com.shuzijun.leetcode.plugin.listener.LoginNotifier;
+import com.shuzijun.leetcode.plugin.listener.QuestionStatusNotifier;
+import com.shuzijun.leetcode.plugin.manager.QuestionManager;
+import com.shuzijun.leetcode.plugin.model.Config;
+import com.shuzijun.leetcode.plugin.model.User;
+import com.shuzijun.leetcode.plugin.setting.PersistentConfig;
+import com.shuzijun.leetcode.plugin.setting.StatisticsData;
+import com.shuzijun.leetcode.plugin.utils.DataKeys;
+import com.shuzijun.leetcode.plugin.utils.LogUtils;
+import com.shuzijun.leetcode.plugin.utils.URLUtils;
+import com.shuzijun.leetcode.plugin.window.navigator.AllNavigatorPanel;
+import com.shuzijun.leetcode.plugin.window.navigator.NavigatorPanel;
+import com.shuzijun.leetcode.plugin.window.navigator.TopNavigatorPanel;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @author shuzijun
+ */
+public class NavigatorTabsPanel extends SimpleToolWindowPanel implements Disposable {
+
+ private static final DisposableMap NAVIGATOR_TABS_PANEL_DISPOSABLE_MAP = new DisposableMap<>();
+
+ static {
+ Disposer.register(ApplicationManager.getApplication(), NAVIGATOR_TABS_PANEL_DISPOSABLE_MAP);
+ }
+
+ private String id = UUID.randomUUID().toString();
+
+ private SimpleToolWindowPanel[] navigatorPanels;
+ private TabInfo[] tabInfos;
+
+ private JBTabsImpl tabs;
+
+ private int toggleIndex = 0;
+
+ private volatile Map userCache = new ConcurrentHashMap<>();
+
+ public NavigatorTabsPanel(ToolWindow toolWindow, Project project) {
+ super(Boolean.TRUE, Boolean.TRUE);
+
+ navigatorPanels = new SimpleToolWindowPanel[3];
+ tabInfos = new TabInfo[3];
+
+ tabs = new JBTabsImpl(project);
+ tabs.setHideTabs(true);
+
+ NavigatorPanel navigatorPanel = new NavigatorPanel(toolWindow, project);
+ navigatorPanels[0] = navigatorPanel;
+
+ TabInfo tabInfo = new TabInfo(navigatorPanel);
+ tabInfo.setText("page");
+ tabInfos[0] = tabInfo;
+ tabs.addTab(tabInfo);
+
+ AllNavigatorPanel allNavigatorPanel = new AllNavigatorPanel(toolWindow, project);
+ navigatorPanels[1] = allNavigatorPanel;
+
+ TabInfo allTabInfo = new TabInfo(allNavigatorPanel);
+ allTabInfo.setText("all");
+ tabInfos[1] = allTabInfo;
+ tabs.addTab(allTabInfo);
+
+ TopNavigatorPanel topNavigatorPanel = new TopNavigatorPanel(toolWindow, project);
+ navigatorPanels[2] = topNavigatorPanel;
+
+ TabInfo topTabInfo = new TabInfo(topNavigatorPanel);
+ topTabInfo.setText("codeTop");
+ tabInfos[2] = topTabInfo;
+ tabs.addTab(topTabInfo);
+
+ Config config = PersistentConfig.getInstance().getInitConfig();
+ if (config != null) {
+ for (int i = 0; i < tabInfos.length; i++) {
+ if (tabInfos[i].getText().equalsIgnoreCase(config.getNavigatorName())) {
+ tabs.select(tabInfos[i], true);
+ toggleIndex = i;
+ break;
+ }
+ }
+ }
+
+ setContent(tabs);
+
+ ApplicationManager.getApplication().executeOnPooledThread(() -> {
+ User user = getUser();
+ if (user.isSignedIn()) {
+ WindowFactory.updateTitle(project, user.getUsername());
+ StatisticsData.refresh(project);
+ } else {
+ WindowFactory.updateTitle(project, "No login");
+ }
+ });
+ MessageBusConnection messageBusConnection = ApplicationManager.getApplication().getMessageBus().connect(this);
+ messageBusConnection.subscribe(LoginNotifier.TOPIC, new LoginNotifier() {
+ @Override
+ public void login(Project notifierProject, String host) {
+ User user = getUser();
+ if (user.isSignedIn()) {
+ WindowFactory.updateTitle(project, user.getUsername());
+ StatisticsData.refresh(project);
+ } else {
+ WindowFactory.updateTitle(project, "No login");
+ }
+
+ }
+
+ @Override
+ public void logout(Project notifierProject, String host) {
+ WindowFactory.updateTitle(project, "No login");
+ }
+ });
+ messageBusConnection.subscribe(ConfigNotifier.TOPIC, new ConfigNotifier() {
+ @Override
+ public void change(Config oldConfig, Config newConfig) {
+ if (oldConfig != null && !oldConfig.getUrl().equalsIgnoreCase(newConfig.getUrl())) {
+ User user = getUser();
+ if (user.isSignedIn()) {
+ WindowFactory.updateTitle(project, user.getUsername());
+ StatisticsData.refresh(project);
+ } else {
+ WindowFactory.updateTitle(project, "No login");
+ }
+ }
+ }
+ });
+ messageBusConnection.subscribe(QuestionStatusNotifier.QUESTION_STATUS_TOPIC, question -> StatisticsData.refresh(project));
+
+ for (SimpleToolWindowPanel n : navigatorPanels) {
+ if (n != null && navigatorPanel instanceof Disposable) {
+ Disposer.register(this, (Disposable) n);
+ }
+ }
+
+ NAVIGATOR_TABS_PANEL_DISPOSABLE_MAP.put(id, this);
+
+ }
+
+ public void toggle() {
+ toggleIndex = (toggleIndex + 1) % 3;
+ tabs.select(tabInfos[toggleIndex], true);
+ Config config = PersistentConfig.getInstance().getInitConfig();
+ if (config != null) {
+ config.setNavigatorName(tabInfos[toggleIndex].getText());
+ PersistentConfig.getInstance().setInitConfig(config);
+ }
+ }
+
+ @NotNull
+ public User getUser() {
+ Config config = PersistentConfig.getInstance().getInitConfig();
+ if (config == null) {
+ return new User();
+ } else if (userCache.containsKey(config.getUrl())) {
+ return userCache.get(config.getUrl());
+ } else {
+ String otherKey = null;
+ for (Object key : NAVIGATOR_TABS_PANEL_DISPOSABLE_MAP.keySet()) {
+ if (!key.equals(id)) {
+ otherKey = (String) key;
+ break;
+ }
+ }
+ if (otherKey == null || !((NavigatorTabsPanel) NAVIGATOR_TABS_PANEL_DISPOSABLE_MAP.get(otherKey)).userCache.containsKey(config.getUrl())) {
+ User user = QuestionManager.getUser();
+ userCache.put(config.getUrl(), user);
+ return user;
+ } else {
+ User user = ((NavigatorTabsPanel) NAVIGATOR_TABS_PANEL_DISPOSABLE_MAP.get(otherKey)).userCache.get(config.getUrl());
+ userCache.put(config.getUrl(), user);
+ return user;
+ }
+ }
+ }
+
+ @Override
+ public Object getData(String dataId) {
+ for (SimpleToolWindowPanel navigatorPanel : navigatorPanels) {
+ Object object = navigatorPanel.getData(dataId);
+ if (object != null) {
+ return object;
+ }
+ }
+ if (DataKeys.LEETCODE_PROJECTS_TABS.is(dataId)) {
+ return this;
+ }
+ if (DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION.is(dataId)) {
+ SimpleToolWindowPanel panel = navigatorPanels[toggleIndex];
+ if (panel instanceof NavigatorPanelAction) {
+ return ((NavigatorPanelAction) panel).getNavigatorAction();
+ }
+ }
+
+ return super.getData(dataId);
+ }
+
+ @Override
+ public void dispose() {
+ NAVIGATOR_TABS_PANEL_DISPOSABLE_MAP.remove(id);
+ for (SimpleToolWindowPanel navigatorPanel : navigatorPanels) {
+ if (navigatorPanel != null && navigatorPanel instanceof Disposable) {
+ ((Disposable) navigatorPanel).dispose();
+ }
+ }
+ }
+
+ public static synchronized void loadUser(boolean login) {
+ User user = null;
+ if (login) {
+ for (int i = 0; i < 10; i++) {
+ user = QuestionManager.getUser();
+ if (!user.isSignedIn()) {
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException ignore) {
+ }
+ } else {
+ break;
+ }
+ if(i == 9){
+ LogUtils.LOG.warn("User data is not synchronized");
+ }
+ }
+ } else {
+ user = new User();
+ }
+ Collection collection = NAVIGATOR_TABS_PANEL_DISPOSABLE_MAP.values();
+ for (NavigatorTabsPanel navigatorTabsPanel : collection) {
+ navigatorTabsPanel.userCache.put(URLUtils.getLeetcodeHost(), user);
+ }
+ }
+
+ public static class DisposableMap extends HashMap implements Disposable {
+ @Override
+ public void dispose() {
+ for (Object value : values()) {
+ if (value instanceof Disposable) {
+ ((Disposable) value).dispose();
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/WindowFactory.java b/src/main/java/com/shuzijun/leetcode/plugin/window/WindowFactory.java
index f6410bc8..c254cdd1 100644
--- a/src/main/java/com/shuzijun/leetcode/plugin/window/WindowFactory.java
+++ b/src/main/java/com/shuzijun/leetcode/plugin/window/WindowFactory.java
@@ -3,8 +3,10 @@
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.ToolWindow;
+import com.intellij.openapi.wm.ToolWindowAnchor;
import com.intellij.openapi.wm.ToolWindowFactory;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.ui.content.Content;
@@ -21,7 +23,7 @@
/**
* @author shuzijun
*/
-public class WindowFactory implements ToolWindowFactory {
+public class WindowFactory implements ToolWindowFactory, DumbAware {
public static String ID = PluginConstant.TOOL_WINDOW_ID;
@@ -29,30 +31,45 @@ public class WindowFactory implements ToolWindowFactory {
public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
ContentFactory contentFactory = ContentFactory.SERVICE.getInstance();
- JComponent navigatorPanel= new NavigatorPanel(toolWindow,project);
+ JComponent navigatorPanel = new NavigatorTabsPanel(toolWindow, project);
Content content = contentFactory.createContent(navigatorPanel, "", false);
toolWindow.getContentManager().addContent(content);
- if(PersistentConfig.getInstance().getInitConfig()!=null && !PersistentConfig.getInstance().getInitConfig().getShowToolIcon()){
- toolWindow.setIcon(LeetCodeEditorIcons.EMPEROR_NEW_CLOTHES);
+ if (PersistentConfig.getInstance().getInitConfig() != null) {
+ if (!PersistentConfig.getInstance().getInitConfig().getShowToolIcon()) {
+ toolWindow.setIcon(LeetCodeEditorIcons.EMPEROR_NEW_CLOTHES);
+ }
+ if (!PersistentConfig.getInstance().getInitConfig().isLeftQuestionEditor()) {
+ toolWindow.setAnchor(ToolWindowAnchor.RIGHT, null);
+ }
+
}
}
+
+ @NotNull
public static DataContext getDataContext(@NotNull Project project) {
AtomicReference dataContext = new AtomicReference<>();
ApplicationManager.getApplication().invokeAndWait(() -> {
ToolWindow leetcodeToolWindows = ToolWindowManager.getInstance(project).getToolWindow(ID);
- dataContext.set(DataManager.getInstance().getDataContext(leetcodeToolWindows.getContentManager().getContent(0).getComponent()));
+ if (leetcodeToolWindows == null) {
+ dataContext.set(DataContext.EMPTY_CONTEXT);
+ } else {
+ dataContext.set(DataManager.getInstance().getDataContext(leetcodeToolWindows.getContentManager().getContent(0).getComponent()));
+ }
});
return dataContext.get();
}
public static void updateTitle(@NotNull Project project, String userName) {
ToolWindow leetcodeToolWindows = ToolWindowManager.getInstance(project).getToolWindow(ID);
- if (StringUtils.isNotBlank(userName)) {
- leetcodeToolWindows.setTitle("[" + userName + "]");
- } else {
- leetcodeToolWindows.setTitle("");
- }
+ ApplicationManager.getApplication().invokeLater(() -> {
+ if (StringUtils.isNotBlank(userName)) {
+ leetcodeToolWindows.setTitle("[" + userName + "]");
+ } else {
+ leetcodeToolWindows.setTitle("");
+ }
+ });
+
}
public static void activateToolWindow(@NotNull Project project) {
diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/SolutionPanel.java b/src/main/java/com/shuzijun/leetcode/plugin/window/dialog/SolutionPanel.java
similarity index 81%
rename from src/main/java/com/shuzijun/leetcode/plugin/window/SolutionPanel.java
rename to src/main/java/com/shuzijun/leetcode/plugin/window/dialog/SolutionPanel.java
index bd117d07..01ce3c70 100644
--- a/src/main/java/com/shuzijun/leetcode/plugin/window/SolutionPanel.java
+++ b/src/main/java/com/shuzijun/leetcode/plugin/window/dialog/SolutionPanel.java
@@ -1,4 +1,4 @@
-package com.shuzijun.leetcode.plugin.window;
+package com.shuzijun.leetcode.plugin.window.dialog;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
@@ -12,6 +12,8 @@
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import java.awt.*;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseListener;
import java.util.List;
/**
@@ -24,7 +26,8 @@ public class SolutionPanel extends DialogWrapper {
public SolutionPanel(@Nullable Project project, TableModel tableModel) {
super(project, true);
- this.jpanel = new JBPanel(new BorderLayout());;
+ this.jpanel = new JBPanel(new BorderLayout());
+
jpanel.setPreferredSize(new Dimension(600, 400));
table = new JBTable(tableModel);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
@@ -34,24 +37,34 @@ public SolutionPanel(@Nullable Project project, TableModel tableModel) {
table.getColumnModel().getColumn(0).setPreferredWidth(350);
table.getColumnModel().getColumn(1).setPreferredWidth(200);
table.getColumnModel().getColumn(2).setPreferredWidth(700);
- jpanel.add(new JBScrollPane(table, JBScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JBScrollPane.HORIZONTAL_SCROLLBAR_NEVER), BorderLayout.CENTER);
+ jpanel.add(new JBScrollPane(table, JBScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JBScrollPane.HORIZONTAL_SCROLLBAR_NEVER), BorderLayout.CENTER);
setModal(true);
init();
}
+ public void addTableMouseListener(MouseListener l) {
+ this.table.addMouseListener(l);
+ }
+
+ public void addTableKeyListener(KeyListener l) {
+ this.table.addKeyListener(l);
+ }
+
+ @Override
+ public @Nullable JComponent getPreferredFocusedComponent() {
+ return table;
+ }
+
@Nullable
@Override
protected JComponent createCenterPanel() {
return jpanel;
}
- @NotNull
@Override
- protected Action getOKAction() {
- Action action = super.getOKAction();
- action.putValue(Action.NAME, "&Show detail");
- return action;
+ protected Action @NotNull [] createActions() {
+ return new Action[]{getCancelAction()};
}
public int getSelectedRow() {
@@ -75,7 +88,6 @@ public TableModel(List solutionList) {
}
-
@Override
public int getRowCount() {
return data.length;
diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/SubmissionsPanel.java b/src/main/java/com/shuzijun/leetcode/plugin/window/dialog/SubmissionsPanel.java
similarity index 86%
rename from src/main/java/com/shuzijun/leetcode/plugin/window/SubmissionsPanel.java
rename to src/main/java/com/shuzijun/leetcode/plugin/window/dialog/SubmissionsPanel.java
index 5631df89..d6830b99 100644
--- a/src/main/java/com/shuzijun/leetcode/plugin/window/SubmissionsPanel.java
+++ b/src/main/java/com/shuzijun/leetcode/plugin/window/dialog/SubmissionsPanel.java
@@ -1,4 +1,4 @@
-package com.shuzijun.leetcode.plugin.window;
+package com.shuzijun.leetcode.plugin.window.dialog;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
@@ -12,6 +12,8 @@
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import java.awt.*;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseListener;
import java.text.DateFormat;
import java.util.Date;
import java.util.List;
@@ -47,18 +49,28 @@ public SubmissionsPanel(@Nullable Project project, TableModel tableModel) {
init();
}
+ public void addTableMouseListener(MouseListener l) {
+ this.table.addMouseListener(l);
+ }
+
+ public void addTableKeyListener(KeyListener l) {
+ this.table.addKeyListener(l);
+ }
+
+ @Override
+ public @Nullable JComponent getPreferredFocusedComponent() {
+ return table;
+ }
+
@Nullable
@Override
protected JComponent createCenterPanel() {
return jpanel;
}
- @NotNull
@Override
- protected Action getOKAction() {
- Action action = super.getOKAction();
- action.putValue(Action.NAME, "&Show detail");
- return action;
+ protected Action @NotNull [] createActions() {
+ return new Action[]{getCancelAction()};
}
public int getSelectedRow() {
diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/TestcasePanel.java b/src/main/java/com/shuzijun/leetcode/plugin/window/dialog/TestcasePanel.java
similarity index 62%
rename from src/main/java/com/shuzijun/leetcode/plugin/window/TestcasePanel.java
rename to src/main/java/com/shuzijun/leetcode/plugin/window/dialog/TestcasePanel.java
index 21df6d2a..d3ee1456 100644
--- a/src/main/java/com/shuzijun/leetcode/plugin/window/TestcasePanel.java
+++ b/src/main/java/com/shuzijun/leetcode/plugin/window/dialog/TestcasePanel.java
@@ -1,26 +1,29 @@
-package com.shuzijun.leetcode.plugin.window;
+package com.shuzijun.leetcode.plugin.window.dialog;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.ui.components.JBPanel;
import com.intellij.ui.components.JBScrollPane;
+import com.shuzijun.leetcode.plugin.model.Question;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
+import java.awt.event.ActionEvent;
/**
* @author shuzijun
*/
public class TestcasePanel extends DialogWrapper {
-
+ private Question question;
private JPanel jpanel;
private JTextArea caseText;
- public TestcasePanel(@Nullable Project project) {
+ public TestcasePanel(@Nullable Project project, Question question) {
super(project, true);
+ this.question = question;
jpanel = new JBPanel();
jpanel.setLayout(new BorderLayout());
caseText = new JTextArea();
@@ -46,6 +49,25 @@ protected Action getOKAction() {
return action;
}
+ @Override
+ protected Action @NotNull [] createActions() {
+ return new Action[]{new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ caseText.setText(question.getExampleTestcases());
+ }
+
+ @Override
+ public Object getValue(String key) {
+ if(Action.NAME.equals(key)){
+ return "&Use Example Testcases";
+ }else {
+ return super.getValue(key);
+ }
+ }
+ },getOKAction(),getCancelAction()};
+ }
+
public String testcaseText() {
return caseText.getText();
}
diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/HttpLogin.java b/src/main/java/com/shuzijun/leetcode/plugin/window/login/HttpLogin.java
similarity index 62%
rename from src/main/java/com/shuzijun/leetcode/plugin/window/HttpLogin.java
rename to src/main/java/com/shuzijun/leetcode/plugin/window/login/HttpLogin.java
index b1839934..a97120c2 100644
--- a/src/main/java/com/shuzijun/leetcode/plugin/window/HttpLogin.java
+++ b/src/main/java/com/shuzijun/leetcode/plugin/window/login/HttpLogin.java
@@ -1,4 +1,4 @@
-package com.shuzijun.leetcode.plugin.window;
+package com.shuzijun.leetcode.plugin.window.login;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
@@ -7,11 +7,16 @@
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
-import com.shuzijun.leetcode.plugin.manager.ViewManager;
+import com.shuzijun.leetcode.plugin.listener.LoginNotifier;
+import com.shuzijun.leetcode.plugin.manager.NavigatorAction;
import com.shuzijun.leetcode.plugin.model.Config;
+import com.shuzijun.leetcode.plugin.model.HttpRequest;
import com.shuzijun.leetcode.plugin.model.PluginConstant;
+import com.shuzijun.leetcode.plugin.model.User;
import com.shuzijun.leetcode.plugin.setting.PersistentConfig;
import com.shuzijun.leetcode.plugin.utils.*;
+import com.shuzijun.leetcode.plugin.window.NavigatorTabsPanel;
+import com.shuzijun.leetcode.plugin.window.WindowFactory;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
@@ -26,7 +31,7 @@
* @author shuzijun
*/
public class HttpLogin {
- public static boolean ajaxLogin(Config config, NavigatorTable navigatorTable, Project project) {
+ public static boolean ajaxLogin(Config config, NavigatorAction navigatorAction, Project project) {
if (!URLUtils.isCn()) {
return Boolean.FALSE;
@@ -38,21 +43,15 @@ public static boolean ajaxLogin(Config config, NavigatorTable navigatorTable, Pr
try {
HttpEntity ent = MultipartEntityBuilder.create()
- .addTextBody("csrfmiddlewaretoken", HttpRequestUtils.getToken() == null ? "": HttpRequestUtils.getToken())
+ .addTextBody("csrfmiddlewaretoken", HttpRequestUtils.getToken() == null ? "" : HttpRequestUtils.getToken())
.addTextBody("login", config.getLoginName())
.addTextBody("password", PersistentConfig.getInstance().getPassword(config.getLoginName()))
.addTextBody("next", "/problems")
.build();
- HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeLogin(), ent.getContentType().getValue());
- httpRequest.setBody(IOUtils.toString(ent.getContent(), "UTF-8"));
- httpRequest.addHeader("x-requested-with", "XMLHttpRequest");
- httpRequest.addHeader("accept", "*/*");
- HttpResponse response = HttpRequestUtils.executePost(httpRequest);
-
- if (response == null) {
- MessageUtils.getInstance(project).showWarnMsg("warning", PropertiesUtils.getInfo("request.failed"));
- return Boolean.FALSE;
- }
+ HttpResponse response = HttpRequest.builderPost(URLUtils.getLeetcodeLogin(), ent.getContentType().getValue())
+ .body(IOUtils.toString(ent.getContent(), "UTF-8"))
+ .addHeader("x-requested-with", "XMLHttpRequest")
+ .addHeader("accept", "*/*").request();
String body = response.getBody();
@@ -62,8 +61,9 @@ public static boolean ajaxLogin(Config config, NavigatorTable navigatorTable, Pr
JSONArray jsonArray = jsonObject.getJSONObject("form").getJSONArray("errors");
if (jsonArray.isEmpty()) {
MessageUtils.getInstance(project).showInfoMsg("info", PropertiesUtils.getInfo("login.success"));
+ NavigatorTabsPanel.loadUser(true);
+ ApplicationManager.getApplication().getMessageBus().syncPublisher(LoginNotifier.TOPIC).login(project, config.getUrl());
examineEmail(project);
- ViewManager.loadServiceData(navigatorTable, project);
return Boolean.TRUE;
} else {
MessageUtils.getInstance(project).showInfoMsg("info", StringUtils.join(jsonArray, ","));
@@ -71,8 +71,9 @@ public static boolean ajaxLogin(Config config, NavigatorTable navigatorTable, Pr
}
} else if (StringUtils.isBlank(body)) {
MessageUtils.getInstance(project).showInfoMsg("info", PropertiesUtils.getInfo("login.success"));
+ NavigatorTabsPanel.loadUser(true);
+ ApplicationManager.getApplication().getMessageBus().syncPublisher(LoginNotifier.TOPIC).login(project, config.getUrl());
examineEmail(project);
- ViewManager.loadServiceData(navigatorTable, project);
return Boolean.TRUE;
} else {
HttpRequestUtils.resetHttpclient();
@@ -81,9 +82,13 @@ public static boolean ajaxLogin(Config config, NavigatorTable navigatorTable, Pr
return Boolean.FALSE;
}
} else if (response.getStatusCode() == 400) {
- LogUtils.LOG.error("login 400:" + body);
- JSONObject jsonObject = JSONObject.parseObject(body);
- MessageUtils.getInstance(project).showInfoMsg("info", StringUtils.join(jsonObject.getJSONObject("form").getJSONArray("errors"), ","));
+ LogUtils.LOG.info("login 400:" + body);
+ try {
+ JSONObject jsonObject = JSONObject.parseObject(body);
+ MessageUtils.getInstance(project).showInfoMsg("info", StringUtils.join(jsonObject.getJSONObject("form").getJSONArray("errors"), ","));
+ } catch (Exception ignore) {
+
+ }
return Boolean.FALSE;
} else {
HttpRequestUtils.resetHttpclient();
@@ -102,27 +107,12 @@ public static void examineEmail(Project project) {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
public void run() {
- HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(), "application/json");
try {
- httpRequest.setBody("{\"operationName\":\"user\",\"variables\":{},\"query\":\"query user {\\n user {\\n socialAccounts\\n username\\n emails {\\n email\\n primary\\n verified\\n __typename\\n }\\n phone\\n profile {\\n rewardStats\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}");
- httpRequest.addHeader("Accept", "application/json");
- HttpResponse response = HttpRequestUtils.executePost(httpRequest);
- if (response != null && response.getStatusCode() == 200) {
-
- String body = response.getBody();
-
- JSONArray jsonArray = JSONObject.parseObject(body).getJSONObject("data").getJSONObject("user").getJSONArray("emails");
- if (jsonArray != null && jsonArray.size() > 0) {
- for (int i = 0; i < jsonArray.size(); i++) {
- JSONObject object = jsonArray.getJSONObject(i);
- if (object.getBoolean("verified")) {
- return;
- }
- }
-
- }
- MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("user.email"));
+ User user = WindowFactory.getDataContext(project).getData(DataKeys.LEETCODE_PROJECTS_TABS).getUser();
+ if (user.isVerified() || user.isPhoneVerified()) {
+ return;
}
+ MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("user.email"));
} catch (Exception i) {
LogUtils.LOG.error("验证邮箱错误");
}
@@ -130,15 +120,16 @@ public void run() {
});
}
- public static void loginSuccess(NavigatorTable navigatorTable, Project project, List cookieList) {
- ProgressManager.getInstance().run(new Task.Backgroundable(project, PluginConstant.ACTION_PREFIX+".loginSuccess", false) {
+ public static void loginSuccess(Project project, List cookieList) {
+ ProgressManager.getInstance().run(new Task.Backgroundable(project, PluginConstant.ACTION_PREFIX + ".loginSuccess", false) {
@Override
public void run(@NotNull ProgressIndicator progressIndicator) {
Config config = PersistentConfig.getInstance().getInitConfig();
config.addCookie(config.getUrl() + config.getLoginName(), CookieUtils.httpCookieToJSONString(cookieList));
PersistentConfig.getInstance().setInitConfig(config);
MessageUtils.getInstance(project).showInfoMsg("info", PropertiesUtils.getInfo("login.success"));
- ViewManager.loadServiceData(navigatorTable, project);
+ NavigatorTabsPanel.loadUser(true);
+ ApplicationManager.getApplication().getMessageBus().syncPublisher(LoginNotifier.TOPIC).login(project, config.getUrl());
examineEmail(project);
}
});
@@ -146,7 +137,7 @@ public void run(@NotNull ProgressIndicator progressIndicator) {
public static boolean isEnabledJcef() {
Config config = PersistentConfig.getInstance().getInitConfig();
- return config != null && config.getJcef() && isSupportedJcef();
+ return config != null && !config.isCookie() && isSupportedJcef();
}
public static boolean isSupportedJcef() {
@@ -154,7 +145,8 @@ public static boolean isSupportedJcef() {
Class> JBCefAppClass = Class.forName("com.intellij.ui.jcef.JBCefApp");
Method method = JBCefAppClass.getMethod("isSupported");
return (boolean) method.invoke(null);
- } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException |
+ InvocationTargetException e) {
return Boolean.FALSE;
}
}
diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/login/LoginPanel.java b/src/main/java/com/shuzijun/leetcode/plugin/window/login/LoginPanel.java
new file mode 100644
index 00000000..5b26d816
--- /dev/null
+++ b/src/main/java/com/shuzijun/leetcode/plugin/window/login/LoginPanel.java
@@ -0,0 +1,211 @@
+package com.shuzijun.leetcode.plugin.window.login;
+
+import com.intellij.ide.BrowserUtil;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.progress.Task;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.ui.components.JBScrollPane;
+import com.intellij.ui.components.JBTextArea;
+import com.intellij.ui.jcef.JCEFHtmlPanel;
+import com.intellij.util.ui.JBUI;
+import com.intellij.util.ui.components.BorderLayoutPanel;
+import com.shuzijun.leetcode.plugin.model.PluginConstant;
+import com.shuzijun.leetcode.plugin.utils.*;
+import org.apache.commons.lang.StringUtils;
+import org.cef.browser.CefBrowser;
+import org.cef.browser.CefFrame;
+import org.cef.callback.CefCookieVisitor;
+import org.cef.handler.CefLoadHandler;
+import org.cef.handler.CefLoadHandlerAdapter;
+import org.cef.misc.BoolRef;
+import org.cef.network.CefCookie;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.net.HttpCookie;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author shuzijun
+ */
+public class LoginPanel extends DialogWrapper {
+
+ private BorderLayoutPanel panel = JBUI.Panels.simplePanel();
+
+ private JTextArea cookieText = new JBTextArea();
+
+ private JcefPanel jcefPanel;
+
+ private Project project;
+
+ private Action okAction;
+
+ public LoginPanel(@Nullable Project project) {
+ super(project, null, false, IdeModalityType.IDE, !HttpLogin.isEnabledJcef());
+ this.project = project;
+ if (HttpLogin.isEnabledJcef()) {
+ okAction = new OkAction() {
+ };
+ jcefPanel = new JcefPanel(project, okAction);
+ jcefPanel.getComponent().setMinimumSize(new Dimension(1000, 500));
+ jcefPanel.getComponent().setPreferredSize(new Dimension(1000, 500));
+ panel.addToCenter(new JBScrollPane(jcefPanel.getComponent(), JBScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JBScrollPane.HORIZONTAL_SCROLLBAR_NEVER));
+
+ } else {
+ cookieText.setLineWrap(true);
+ cookieText.setMinimumSize(new Dimension(400, 200));
+ cookieText.setPreferredSize(new Dimension(400, 200));
+ panel.addToCenter(new JBScrollPane(cookieText, JBScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JBScrollPane.HORIZONTAL_SCROLLBAR_NEVER));
+ okAction = new OkAction() {
+ @Override
+ protected void doAction(ActionEvent e) {
+ String cookiesString = cookieText.getText();
+ if (StringUtils.isBlank(cookiesString)) {
+ JOptionPane.showMessageDialog(null, "cookie is null");
+ return;
+ }
+ final List cookieList = new ArrayList<>();
+ String[] cookies = cookiesString.split(";");
+ for (String cookieString : cookies) {
+ String[] cookie = cookieString.trim().split("=");
+ if (cookie.length >= 2) {
+ try {
+ HttpCookie basicClientCookie = new HttpCookie(cookie[0], cookie[1]);
+ basicClientCookie.setDomain("." + URLUtils.getLeetcodeHost());
+ basicClientCookie.setPath("/");
+ cookieList.add(basicClientCookie);
+ } catch (IllegalArgumentException ignore) {
+
+ }
+ }
+ }
+ HttpRequestUtils.setCookie(cookieList);
+
+ ProgressManager.getInstance().run(new Task.Backgroundable(project, PluginConstant.ACTION_PREFIX + ".loginSuccess", false) {
+ @Override
+ public void run(@NotNull ProgressIndicator progressIndicator) {
+ if (HttpRequestUtils.isLogin(project)) {
+ HttpLogin.loginSuccess(project, cookieList);
+ } else {
+ JOptionPane.showMessageDialog(null, PropertiesUtils.getInfo("login.failed"));
+ }
+
+ }
+ });
+ super.doAction(e);
+ }
+ };
+ okAction.putValue(Action.NAME, "login");
+ }
+
+ setModal(false);
+ init();
+ setTitle("login");
+ }
+
+ @Override
+ protected @Nullable JComponent createCenterPanel() {
+ return panel;
+ }
+
+ @NotNull
+ @Override
+ protected Action getOKAction() {
+ return okAction;
+ }
+
+ @NotNull
+ @Override
+ protected Action[] createActions() {
+ Action helpAction = new AbstractAction("help") {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ BrowserUtil.browse("https://github.com/shuzijun/leetcode-editor/blob/master/doc/LoginHelp.md");
+ }
+
+ };
+ Action[] actions = new Action[]{helpAction, this.getOKAction(), this.getCancelAction()};
+ return actions;
+ }
+
+
+ private static class JcefPanel extends JCEFHtmlPanel {
+
+
+ private CefLoadHandlerAdapter cefLoadHandler;
+
+ private Project project;
+
+ private Action okAction;
+
+ public JcefPanel(Project project, Action okAction) {
+ super(null, null);
+ this.project = project;
+ this.okAction = okAction;
+ getJBCefClient().addLoadHandler(cefLoadHandler = new CefLoadHandlerAdapter() {
+
+ boolean successDispose = false;
+
+ @Override
+ public void onLoadError(CefBrowser browser, CefFrame frame, CefLoadHandler.ErrorCode errorCode, String errorText, String failedUrl) {
+ if (!successDispose) {
+ MessageUtils.getInstance(project).showWarnMsg("", "The page failed to load, please check the network and open it again");
+ }
+ }
+
+ @Override
+ public void onLoadingStateChange(CefBrowser browser, boolean isLoading, boolean canGoBack, boolean canGoForward) {
+
+ getJBCefCookieManager().getCefCookieManager().visitAllCookies(new CefCookieVisitor() {
+
+ private List