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 [![Release](https://github.com/shuzijun/leetcode-editor/workflows/Release/badge.svg)](https://github.com/shuzijun/leetcode-editor/releases) [![Snapshot](https://github.com/shuzijun/leetcode-editor/workflows/Snapshot/badge.svg)](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] + +

demo

+ +--- + ## Introduction - Do Leetcode exercises in IDE, support `leetcode.com` and `leetcode.cn`, to meet the basic needs of doing exercises. - Support theoretically: IntelliJ IDEA PhpStorm WebStorm PyCharm RubyMine AppCode CLion GoLand DataGrip Rider MPS Android Studio. - be with you! - + Do Leetcode exercises in IDE, support `leetcode.com` and `leetcode.cn`, meet the needs of problem solving and debugging. + Support theoretically: **IntelliJ IDEA**,**PhpStorm**,**WebStorm**,**PyCharm**,**RubyMine**,**AppCode**,**CLion**,**GoLand**,**DataGrip**,**Rider MPS**,**Android Studio**. + + - [English Document][gh:en-doc] + - [中文文档][gh:zh-doc] + + - Useful Links + - [Login Help][gh:login-help] + - [Custom Code][gh:custom-code] ([demo][gh:leetcode-question]) -## How to use -

- demo -

+## Getting Started +

start

+ ## Local debugging -

- demo -

+

loacl

+ -### Installation([help](https://www.jetbrains.com/help/idea/2019.2/managing-plugins.html)) -- **Install via plug-in library** [leetcode-editor](https://plugins.jetbrains.com/plugin/12132-leetcode-editor) -- **Install by downloading the file** [releases](https://github.com/shuzijun/leetcode-editor/releases) -- **If you are willing to donate to this project, you can choose the pro version** [leetcode-editor-pro](https://plugins.jetbrains.com/plugin/17166-leetcode-editor-pro) +### Installation([help][managing-plugins]) +- **Install via plug-in library** [leetcode-editor][plugin-homepage] +- **Install by downloading the file** [releases][gh:releases] +- **If you are willing to donate to this project, you can choose the pro version** [leetcode-editor-pro][plugin-homepage-pro] ### Configuration (configuration for first installation) -

- settings -

+

config

+ - **Configuration path**: `File` -> `settings`->`tools`->`leetcode plugin` - **`URL options`**: `leetcode.com`OR`leetcode.cn` @@ -41,36 +53,27 @@ - **`Password`**: Login password - **`Temp File Path`**: Temporary file storage catalogue - **`proxy(HTTP Proxy)`**: HTTP Proxy,config path:`File` -> `settings`->`Appearance & Behavior`->`System Settings`->`HTTP Proxy` - - **`Custom code template`**: Custom code template ([details](https://github.com/shuzijun/leetcode-editor/blob/master/doc/CustomCode.md)) ([demo](https://github.com/shuzijun/leetcode-question)) + - **`Custom code template`**: Custom code template ([details][gh:custom-code]) ([demo][gh:leetcode-question]) - **`LevelColour`**: Customize the difficulty color of the question, it will take effect after restart -### Window (Icon in the lower right corner of the main window![icon](https://raw.githubusercontent.com/shuzijun/leetcode-editor/master/doc/LeetCodeIcon.png)) - -

- window -

+### Window + +

window

- **Toolbar**: - - ![login](https://raw.githubusercontent.com/shuzijun/leetcode-editor/master/doc/login.png)**`Sign in`**:The login accounts of the two websites are not interoperable and the corresponding users need to be configured when switching websites. - - ![logout](https://raw.githubusercontent.com/shuzijun/leetcode-editor/master/doc/logout.png)**`Sign out`**:Exit the current account, if you encounter a login error, try to exit first. - - ![refresh](https://raw.githubusercontent.com/shuzijun/leetcode-editor/master/doc/refresh.png)**`Refresh`**:You can also refresh and load questions if you are not logged in, but you cannot submit it. - - ![find](https://raw.githubusercontent.com/shuzijun/leetcode-editor/master/doc/find.png)**`Find`**:Input the content and press Enter to search , press again to search for the next one. It can only search under the question bank node. - - ![collapse](https://raw.githubusercontent.com/shuzijun/leetcode-editor/master/doc/collapseAll.png)**`Collapse`**:Collapse all nodes. - - ![config](https://raw.githubusercontent.com/shuzijun/leetcode-editor/master/doc/config.png)**`Settings`**:Quick jump to the configuration page. - - ![clear](https://raw.githubusercontent.com/shuzijun/leetcode-editor/master/doc/clear.png)**`Clear`**:Clean up the files in the configured cache directories. The cache directories of the two websites are different and only the current configured websites are cleaned up. Carefully clean up cases without submitting. - -- **Tree**: - - **`Problems`**:All questions - - **`Difficulty`**:Classification of difficulties - - **`Tags`**:Classification of types - - **`Explore`**:Explore content, only contains titles of the questions, exclusive content that needs to pay ; some questions are loaded in order - - **`Color`**:The color represents the difficulty of the question - - **`Symbol`**:The symbols of “√” and “?” represent the status of the current questions, and explores with the beginning of “$” needs to pay or that cannot be viewed due to other causes. - + - ![login][icon:login]**`Sign in`**:The login accounts of the two websites are not interoperable and the corresponding users need to be configured when switching websites. + - ![logout][icon:logout]**`Sign out`**:Exit the current account, if you encounter a login error, try to exit first. + - ![refresh][icon:refresh]**`Refresh`**:You can also refresh and load questions if you are not logged in, but you cannot submit it. + - ![pick][icon:pick]**`pick`**:Open a problem randomly. + - ![find][icon:find]**`Find`**:Open filter panel. You can search, filter and sort. + - ![progress][icon:progress]**`Session`**:Open the Session panel. You can view or switch sessions. + - ![toggle][icon:toggle]**`Toggle List`**:Switch to other list windows, including "All Problem List" , "Paginated Problem List" , "CodeTop Problem List". + - ![config][icon:config]**`Settings`**:Quick jump to the configuration page. + - ![clear][icon:clear]**`Clear`**:Clean up the files in the configured cache directories. The cache directories of the two websites are different and only the current configured websites are cleaned up. Carefully clean up cases without submitting. + ### Menu -

- menu -

+

menu

+ - **Menu (right-click on the questions)**: - **`open question`**:Open the question or double click on the question @@ -83,5 +86,65 @@ - **`Clear cache`**:Clean up the current question - **`Timer`**:Timer, when it is turned on, it will prompt the problem solving time in the status bar in the lower right corner +
+ - **Editor Menu(Right-click on Editor to appear)**: - Function as above + Function as above + +
+ +- **Question Editor**: + - **`Content`**:Show content(Rely on Markdown) + - **`Solution`**:show solution + - **`Submissions`**:View the submission record + - **`Note`**:Show note + +### Support and Donations +* [donate][shuzijun-donate] + + +[plugin-logo]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/META-INF/pluginIcon.svg + +[badge:plugin-homepage]: https://img.shields.io/badge/Plugin%20Home-Leetcode%20Editor-blue?logo=jetbrains&style=flat-square +[badge:plugin-homepage-pro]: https://img.shields.io/badge/Pro%20Plugin%20Home-Leetcode%20Editor%20Pro-blue?logo=jetbrains&style=flat-square&color=blueviolet +[badge:release]: https://img.shields.io/github/workflow/status/shuzijun/leetcode-editor/Release?style=flat-square&logo=github&&label=Release%20Build +[badge:snapshot]: https://img.shields.io/github/workflow/status/shuzijun/leetcode-editor/Snapshot?style=flat-square&logo=github&&label=Snapshot%20Build +[badge:license]: https://img.shields.io/github/license/shuzijun/leetcode-editor.svg?style=flat-square&&label=License +[badge:downloads]: https://img.shields.io/jetbrains/plugin/d/12132?style=flat-square&label=Plugin%20Downloads&logo=jetbrains +[badge:version]: https://img.shields.io/jetbrains/plugin/v/12132?label=Plugin%20Version&logo=jetbrains&style=flat-square +[badge:pro-version]: https://img.shields.io/jetbrains/plugin/v/17166?label=Pro%20Plugin%20Version&logo=jetbrains&style=flat-square&color=blueviolet +[badge:en-doc]: https://img.shields.io/badge/Docs-English%20Document-blue?logo=docs&style=flat-square +[badge:zh-doc]: https://img.shields.io/badge/Docs-中文文档-blue?logo=docs&style=flat-square +[badge:donate]: https://img.shields.io/badge/Docs-donate-ff69c4?logo=docs&style=flat-square +[badge:referrals]: https://img.shields.io/badge/Docs-referrals-ff69c4?logo=docs&style=flat-square + +[icon:leetcode]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/LeetCode_dark.svg +[icon:login]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/login_dark.svg +[icon:logout]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/logout_dark.svg +[icon:refresh]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/refresh_dark.svg +[icon:pick]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/random_dark.svg +[icon:find]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/find_dark.svg +[icon:progress]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/progress_dark.svg +[icon:toggle]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/toggle_dark.svg +[icon:config]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/config_lc_dark.svg +[icon:clear]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/clear_dark.svg + +[gh:leetcode-editor]: https://github.com/shuzijun/leetcode-editor +[gh:releases]: https://github.com/shuzijun/leetcode-editor/releases +[gh:snapshot]: https://github.com/shuzijun/leetcode-editor/actions?query=workflow%3ASnapshot +[gh:license]: https://github.com/shuzijun/leetcode-editor/blob/master/LICENSE +[gh:en-doc]: #Introduction +[gh:zh-doc]: https://github.com/shuzijun/leetcode-editor/blob/master/README_ZH.md +[gh:login-help]: https://github.com/shuzijun/leetcode-editor/blob/master/doc/LoginHelp.md +[gh:custom-code]: https://github.com/shuzijun/leetcode-editor/blob/master/doc/CustomCode.md +[gh:leetcode-question]: https://github.com/shuzijun/leetcode-question +[gh:question]: https://github.com/shuzijun/leetcode-editor/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98 + +[plugin-homepage]: https://plugins.jetbrains.com/plugin/12132-leetcode-editor +[plugin-versions]: https://plugins.jetbrains.com/plugin/12132-leetcode-editor/versions +[plugin-homepage-pro]: https://plugins.jetbrains.com/plugin/17166-leetcode-editor-pro +[plugin-versions-pro]: https://plugins.jetbrains.com/plugin/17166-leetcode-editor-pro/versions +[managing-plugins]: https://www.jetbrains.com/help/idea/managing-plugins.html + +[shuzijun-donate]: https://shuzijun.cn/donate.html +[shuzijun-referrals]: https://shuzijun.cn/referrals.html \ No newline at end of file diff --git a/README_ZH.md b/README_ZH.md index e23226a9..2519b955 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -1,38 +1,51 @@ -# leetcode-editor [![Release](https://github.com/shuzijun/leetcode-editor/workflows/Release/badge.svg)](https://github.com/shuzijun/leetcode-editor/releases) [![Snapshot](https://github.com/shuzijun/leetcode-editor/workflows/Snapshot/badge.svg)](https://github.com/shuzijun/leetcode-editor/actions?query=workflow%3ASnapshot) +# [![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] + +

demo

+ +--- - - [English Document](https://github.com/shuzijun/leetcode-editor/blob/master/README.md) - - [中文文档](#简介) - - - 有用的链接 - - [登录帮助](https://github.com/shuzijun/leetcode-editor/blob/master/doc/LoginHelp_ZH.md) - - [自定义代码生成](https://github.com/shuzijun/leetcode-editor/blob/master/doc/CustomCode_ZH.md) ([示例](https://github.com/shuzijun/leetcode-question)) - ## 简介 - 在IDE中解决LeetCode问题,支持`leetcode.com`与`leetcode.cn`,满足基本的做题需求。 - 理论上支持: IntelliJ IDEA PhpStorm WebStorm PyCharm RubyMine AppCode CLion GoLand DataGrip Rider MPS Android Studio。 - [be with you!](http://shuzijun.cn/leetcode-editor/monitor.html) + 在IDE中解决LeetCode问题,支持`leetcode.com`与`leetcode.cn`,满足做题和调试的需求。 + 理论上支持: **IntelliJ IDEA**,**PhpStorm**,**WebStorm**,**PyCharm**,**RubyMine**,**AppCode**,**CLion**,**GoLand**,**DataGrip**,**Rider MPS**,**Android Studio**。 - -## 使用方式 -

- demo -

+ - [English Document][gh:en-doc] + - [中文文档][gh:zh-doc] + + - 有用的链接 + - [登录帮助][gh:login-help] + - [自定义代码生成][gh:custom-code-zh] ([示例][gh:leetcode-question]) + + +## 开始使用 +

start

+ ## 本地调试 -

- demo -

+

loacl

+ -### 安装 -- **通过插件库安装** [leetcode-editor](https://plugins.jetbrains.com/plugin/12132-leetcode-editor) -- **下载文件安装** [releases](https://github.com/shuzijun/leetcode-editor/releases) -- **如果您想捐助此项目,可以选择pro版本** [leetcode-editor-pro](https://plugins.jetbrains.com/plugin/17166-leetcode-editor-pro) +### 安装([help][managing-plugins]) +- **通过插件库安装** [leetcode-editor][plugin-homepage] +- **下载文件安装** [releases][gh:releases] +- **如果您想捐助此项目,可以选择Pro版本** [leetcode-editor-pro][plugin-homepage-pro] ### 配置(第一次安装需要先配置) -

- settings -

+

config

+ - **配置路径**: `File` -> `settings`->`tools`->`leetcode plugin` - **`URL可选项`**: `leetcode.com`与`leetcode.cn` @@ -41,37 +54,28 @@ - **`Password`**: 登录密码 - **`Temp File Path`**: 临时文件存放目录 - **`proxy(HTTP Proxy)`**: 使用http代理,配置路径:`File` -> `settings`->`Appearance & Behavior`->`System Settings`->`HTTP Proxy` - - **`Custom code template`**: 自定义代码生成模板 ([详细介绍](https://github.com/shuzijun/leetcode-editor/blob/master/doc/CustomCode_ZH.md))([示例](https://github.com/shuzijun/leetcode-question)) + - **`Custom code template`**: 自定义代码生成模板 ([详细介绍][gh:custom-code-zh])([示例][gh:leetcode-question]) - **`LevelColour`**: 自定义题目难度颜色,重启后生效 - **`English Content`**: 题目显示英文描述 -### 窗口(主窗口右下角![icon](https://raw.githubusercontent.com/shuzijun/leetcode-editor/master/doc/LeetCodeIcon.png)) - -

- window -

+### 窗口 + +

window

- **工具栏**: - - ![login](https://raw.githubusercontent.com/shuzijun/leetcode-editor/master/doc/login.png)**`登录`**:两个网站的登录帐号不互通,切换网站需配置对应的用户 - - ![logout](https://raw.githubusercontent.com/shuzijun/leetcode-editor/master/doc/logout.png)**`退出`**:退出当前账户,如遇到登录错误,尝试先进行退出 - - ![refresh](https://raw.githubusercontent.com/shuzijun/leetcode-editor/master/doc/refresh.png)**`刷新`**:在未登录的情况下也可查看刷新加载题目,但是无法提交 - - ![find](https://raw.githubusercontent.com/shuzijun/leetcode-editor/master/doc/find.png)**`查找`**:输入内容后回车搜索,再次回车搜索下一个,只会搜索题库节点下 - - ![collapse](https://raw.githubusercontent.com/shuzijun/leetcode-editor/master/doc/collapseAll.png)**`折叠`**:折叠全部节点. - - ![config](https://raw.githubusercontent.com/shuzijun/leetcode-editor/master/doc/config.png)**`配置`**:快捷跳转到配置界面 - - ![clear](https://raw.githubusercontent.com/shuzijun/leetcode-editor/master/doc/clear.png)**`清理`**:清理配置的缓存目录下的文件,两个网站对应的缓存目录不同,只会清理当前配置的网站下的。部分题目未提交的情况下慎重清理 - -- **树**: - - **`Problems`**:全部题目 - - **`Difficulty`**:难度分类 - - **`Tags`**:类型分类 - - **`Explore`**:探索内容,只包含题目,收费内容不支持;部分题目加载有顺序限制 - - **`颜色`**:题目颜色代表题目难度 - - **`符号`**:题目前`√`与`?`代表当前题目解答状态,探索下有 `$` 开头的为付费或者其他情况下无法查看的 - + - ![login][icon:login]**`登录`**:两个网站的登录帐号不互通,切换网站需配置对应的用户 + - ![logout][icon:logout]**`退出`**:退出当前账户,如遇到登录错误,尝试先进行退出 + - ![refresh][icon:refresh]**`刷新`**:在未登录的情况下也可查看刷新加载题目,但是无法提交 + - ![pick][icon:pick]**`随机`**:随机一个题目 + - ![find][icon:find]**`查找`**:打开筛选面板,可以进行搜索、过滤或者排序. + - ![progress][icon:progress]**`会话`**:打开进度面板,可以查看或者切换进度. + - ![toggle][icon:toggle]**`切换列表`**:切换到其他列表窗口,包括"所有题目列表"、"分页题目列表"、"CodeTop题目列表". + - ![config][icon:config]**`配置`**:快捷跳转到配置界面 + - ![clear][icon:clear]**`清理`**:清理配置的缓存目录下的文件,两个网站对应的缓存目录不同,只会清理当前配置的网站下的。部分题目未提交的情况下慎重清理 + ### 菜单 -

- menu -

+

menu

+ - **菜单(在题目上右击出现)**: - **`open question`**:打开题目,在题目上双击也可以打开 @@ -83,9 +87,73 @@ - **`favorite`**:添加或移除收藏 - **`Clear cache`**:清理当前题目 - **`Timer`**:计时器,开启后在右下角状态栏提示解题时间 - + +
+ - **Editor菜单(在Editor上右击出现)**: - 功能同上 + 功能同上 + +
+ +- **问题编辑器**: + - **`Content`**:查看描述,包含图片 + - **`Solution`**:查看解答 + - **`Submissions`**:查看提交记录 + - **`Note`**:查看笔记 ### 常见问题 - [常见问题](https://github.com/shuzijun/leetcode-editor/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98) + [常见问题][gh:question] + +### 支持和捐赠 +* [捐赠][shuzijun-donate] +* [内推][shuzijun-referrals] + + +[plugin-logo]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/META-INF/pluginIcon.svg + +[badge:plugin-homepage]: https://img.shields.io/badge/Plugin%20Home-Leetcode%20Editor-blue?logo=jetbrains&style=flat-square +[badge:plugin-homepage-pro]: https://img.shields.io/badge/Pro%20Plugin%20Home-Leetcode%20Editor%20Pro-blue?logo=jetbrains&style=flat-square&color=blueviolet +[badge:release]: https://img.shields.io/github/workflow/status/shuzijun/leetcode-editor/Release?style=flat-square&logo=github&label=Release%20Build +[badge:snapshot]: https://img.shields.io/github/workflow/status/shuzijun/leetcode-editor/Snapshot?style=flat-square&logo=github&label=Snapshot%20Build +[badge:license]: https://img.shields.io/github/license/shuzijun/leetcode-editor.svg?style=flat-square&&label=License +[badge:downloads]: https://img.shields.io/jetbrains/plugin/d/12132?style=flat-square&label=Plugin%20Downloads&logo=jetbrains +[badge:version]: https://img.shields.io/jetbrains/plugin/v/12132?label=Plugin%20Version&logo=jetbrains&style=flat-square +[badge:pro-version]: https://img.shields.io/jetbrains/plugin/v/17166?label=Pro%20Plugin%20Version&logo=jetbrains&style=flat-square&color=blueviolet +[badge:en-doc]: https://img.shields.io/badge/Docs-English%20Document-blue?logo=docs&style=flat-square +[badge:zh-doc]: https://img.shields.io/badge/Docs-中文文档-blue?logo=docs&style=flat-square +[badge:donate]: https://img.shields.io/badge/Docs-捐赠-ff69c4?logo=docs&style=flat-square +[badge:referrals]: https://img.shields.io/badge/Docs-内推-ff69c4?logo=docs&style=flat-square + + +[icon:leetcode]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/LeetCode_dark.svg +[icon:login]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/login_dark.svg +[icon:logout]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/logout_dark.svg +[icon:refresh]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/refresh_dark.svg +[icon:pick]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/random_dark.svg +[icon:find]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/find_dark.svg +[icon:progress]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/progress_dark.svg +[icon:toggle]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/toggle_dark.svg +[icon:config]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/config_lc_dark.svg +[icon:clear]: https://cdn.jsdelivr.net/gh/shuzijun/leetcode-editor@master/src/main/resources/icons/clear_dark.svg + + + +[gh:leetcode-editor]: https://github.com/shuzijun/leetcode-editor +[gh:releases]: https://github.com/shuzijun/leetcode-editor/releases +[gh:snapshot]: https://github.com/shuzijun/leetcode-editor/actions?query=workflow%3ASnapshot +[gh:license]: https://github.com/shuzijun/leetcode-editor/blob/master/LICENSE +[gh:en-doc]: https://github.com/shuzijun/leetcode-editor/blob/master/README.md +[gh:zh-doc]: #简介 +[gh:login-help]: https://github.com/shuzijun/leetcode-editor/blob/master/doc/LoginHelp_ZH.md +[gh:custom-code-zh]: https://github.com/shuzijun/leetcode-editor/blob/master/doc/CustomCode_ZH.md +[gh:leetcode-question]: https://github.com/shuzijun/leetcode-question +[gh:question]: https://github.com/shuzijun/leetcode-editor/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98 + +[plugin-homepage]: https://plugins.jetbrains.com/plugin/12132-leetcode-editor +[plugin-versions]: https://plugins.jetbrains.com/plugin/12132-leetcode-editor/versions +[plugin-homepage-pro]: https://plugins.jetbrains.com/plugin/17166-leetcode-editor-pro +[plugin-versions-pro]: https://plugins.jetbrains.com/plugin/17166-leetcode-editor-pro/versions +[managing-plugins]: https://www.jetbrains.com/help/idea/managing-plugins.html + +[shuzijun-donate]: https://shuzijun.cn/donate.html +[shuzijun-referrals]: https://shuzijun.cn/referrals.html diff --git a/action/README.md b/action/README.md new file mode 100644 index 00000000..46f184e5 --- /dev/null +++ b/action/README.md @@ -0,0 +1 @@ +Redirect https://github.com/shuzijun/leetcode-editor-action \ No newline at end of file diff --git a/action/README_ZH.md b/action/README_ZH.md new file mode 100644 index 00000000..46f184e5 --- /dev/null +++ b/action/README_ZH.md @@ -0,0 +1 @@ +Redirect https://github.com/shuzijun/leetcode-editor-action \ No newline at end of file diff --git a/build.gradle b/build.gradle index 938d0c28..80e160d9 100644 --- a/build.gradle +++ b/build.gradle @@ -1,15 +1,19 @@ plugins { id 'java-library' - id 'org.jetbrains.intellij' version '1.0' + id 'org.jetbrains.intellij' version '1.7.0-SNAPSHOT' + id 'org.jetbrains.changelog' version "1.3.1" id "de.undercouch.download" version "4.0.2" } -group 'com.shuzijun.leetcode' -version (System.getenv('LD_VERSION')==null ? project.plugin_version :System.getenv('LD_VERSION')) + (project.build_env.isEmpty() ? "" : "-") + project.build_env +apply plugin: 'org.jetbrains.changelog' + +group project.pluginGroup +version (System.getenv('LD_VERSION')==null ? project.pluginVersion :System.getenv('LD_VERSION')) sourceCompatibility = 11 targetCompatibility = 11 + repositories { mavenCentral() } @@ -31,47 +35,37 @@ dependencies { // See https://github.com/JetBrains/gradle-intellij-plugin/ intellij { - pluginName = 'leetcode-editor' - version = project.intellij_version - type = 'IU' + pluginName = project.pluginName + version = project.platformVersion + type = project.platformType downloadSources = true updateSinceUntilBuild = false buildSearchableOptions.enabled = false ideaDependencyCachePath = "$gradle.gradleUserHomeDir/caches/modules-2/files-2.1/com.jetbrains.intellij.idea" - /* localPath project.idea_local_path - alternativeIdePath project.idea_local_path*/ - /*plugins = project.intellij_plugins.split(",").toList()*/ + runIde { - jvmArgs = ["-Dfile.encoding=utf-8"] + jvmArgs = project.runIdeJvmArgs.split(',').toList() } -/* prepareSandbox { - from("src/main/natives" + (project.build_env.isEmpty() ? "" : "-") + project.build_env) { into(getPluginName() + '/natives') } - }*/ - -} - -tasks.withType(JavaCompile) { - options.encoding = "UTF-8" -} + patchPluginXml { + sinceBuild = project.pluginSinceBuild + untilBuild = project.pluginUntilBuild + changeNotes.set(provider { changelog.get(project.version+".0").toHTML() }) + } + publishPlugin { + dependsOn("patchChangelog") + token = System.getenv("PUBLISH_TOKEN") + } +} +changelog { -/* -task downloadJCEF(type: Copy) { - if (project.build_env.isEmpty()) { - return - } - def tempFile = new File(buildDir, "/download/natives-" + project.build_env + ".zip") - download { - src("https://github.com/shuzijun/leetcode-editor/releases/download/" + project.jcef_version + "/natives-" + project.build_env + ".zip") - dest tempFile - } +} - from zipTree(tempFile) - into "src/main/" +tasks.withType(JavaCompile) { + options.encoding = "UTF-8" } -*/ diff --git a/doc/2020.jpg b/doc/2020.jpg deleted file mode 100644 index 9c02b393..00000000 Binary files a/doc/2020.jpg and /dev/null differ diff --git a/doc/CustomCode.md b/doc/CustomCode.md index 42fbbc00..b282eeb7 100644 --- a/doc/CustomCode.md +++ b/doc/CustomCode.md @@ -2,6 +2,5 @@ The custom code generation template can be configured to generate the code format freely, the IDE can debug the code locally.[demo](https://github.com/shuzijun/leetcode-question) - [English Document]() - [中文文档](https://github.com/shuzijun/leetcode-editor/blob/master/doc/CustomCode_ZH.md) -

- demo -

+

loacl

+ diff --git a/doc/CustomCode_ZH.md b/doc/CustomCode_ZH.md index 66085e95..e84a5375 100644 --- a/doc/CustomCode_ZH.md +++ b/doc/CustomCode_ZH.md @@ -2,14 +2,11 @@ 通过配置自定义代码生成模板可以自由生成代码格式,配合IDE可在本地调试代码。[示例工程](https://github.com/shuzijun/leetcode-question) - [English Document](https://github.com/shuzijun/leetcode-editor/blob/master/doc/CustomCode.md) - [中文文档](#配置) -

- demo -

+

loacl

+ ## 配置 -

- customConfig -

+

config

- **Custom code template**: 开启使用自定义模板,否则使用默认生成格式 - **CodeFileName**: 生成文件的名称,默认为题目标题 diff --git a/doc/LeetCodeIcon.png b/doc/LeetCodeIcon.png deleted file mode 100644 index 02c82adc..00000000 Binary files a/doc/LeetCodeIcon.png and /dev/null differ diff --git a/doc/clear.png b/doc/clear.png deleted file mode 100644 index 418839e6..00000000 Binary files a/doc/clear.png and /dev/null differ diff --git a/doc/collapseAll.png b/doc/collapseAll.png deleted file mode 100644 index 521c7ad3..00000000 Binary files a/doc/collapseAll.png and /dev/null differ diff --git a/doc/config-3.0.jpg b/doc/config-3.0.jpg new file mode 100644 index 00000000..111e99b1 Binary files /dev/null and b/doc/config-3.0.jpg differ diff --git a/doc/config-3.0.png b/doc/config-3.0.png deleted file mode 100644 index 952781e5..00000000 Binary files a/doc/config-3.0.png and /dev/null differ diff --git a/doc/config.png b/doc/config.png deleted file mode 100644 index 4b1f5da6..00000000 Binary files a/doc/config.png and /dev/null differ diff --git a/doc/customConfig-100.gif b/doc/customConfig-100.gif index 42d382b5..ff9adfd1 100644 Binary files a/doc/customConfig-100.gif and b/doc/customConfig-100.gif differ diff --git a/doc/customConfig.png b/doc/customConfig.png deleted file mode 100644 index e49111bc..00000000 Binary files a/doc/customConfig.png and /dev/null differ diff --git a/doc/find.png b/doc/find.png deleted file mode 100644 index 9861cfe7..00000000 Binary files a/doc/find.png and /dev/null differ diff --git a/doc/leetcode-editor-3.0.gif b/doc/leetcode-editor-3.0.gif index 7a4eac71..6cb9e2b4 100644 Binary files a/doc/leetcode-editor-3.0.gif and b/doc/leetcode-editor-3.0.gif differ diff --git a/doc/leetcode-editor-6.3.zip b/doc/leetcode-editor-6.3.zip deleted file mode 100644 index d15ed929..00000000 Binary files a/doc/leetcode-editor-6.3.zip and /dev/null differ diff --git a/doc/leetcode-editor.gif b/doc/leetcode-editor.gif deleted file mode 100644 index 410102c5..00000000 Binary files a/doc/leetcode-editor.gif and /dev/null differ diff --git a/doc/leetcode-editor.zip b/doc/leetcode-editor.zip deleted file mode 100644 index 86d8f429..00000000 Binary files a/doc/leetcode-editor.zip and /dev/null differ diff --git a/doc/login.png b/doc/login.png deleted file mode 100644 index 0b6b9d16..00000000 Binary files a/doc/login.png and /dev/null differ diff --git a/doc/logout.png b/doc/logout.png deleted file mode 100644 index db4a34c7..00000000 Binary files a/doc/logout.png and /dev/null differ diff --git a/doc/menu-3.0.jpg b/doc/menu-3.0.jpg new file mode 100644 index 00000000..8843f1c0 Binary files /dev/null and b/doc/menu-3.0.jpg differ diff --git a/doc/menu-3.0.png b/doc/menu-3.0.png deleted file mode 100644 index 15117855..00000000 Binary files a/doc/menu-3.0.png and /dev/null differ diff --git a/doc/menu.png b/doc/menu.png deleted file mode 100644 index 2a19c8c8..00000000 Binary files a/doc/menu.png and /dev/null differ diff --git a/doc/refresh.png b/doc/refresh.png deleted file mode 100644 index d8427365..00000000 Binary files a/doc/refresh.png and /dev/null differ diff --git a/doc/setting.png b/doc/setting.png deleted file mode 100644 index 598bc9b8..00000000 Binary files a/doc/setting.png and /dev/null differ diff --git a/doc/settings.png b/doc/settings.png deleted file mode 100644 index c3e98727..00000000 Binary files a/doc/settings.png and /dev/null differ diff --git a/doc/window-3.0.jpg b/doc/window-3.0.jpg new file mode 100644 index 00000000..96f1d9c9 Binary files /dev/null and b/doc/window-3.0.jpg differ diff --git a/doc/window-3.0.png b/doc/window-3.0.png deleted file mode 100644 index 4a6572be..00000000 Binary files a/doc/window-3.0.png and /dev/null differ diff --git a/doc/window.png b/doc/window.png deleted file mode 100644 index 14d29338..00000000 Binary files a/doc/window.png and /dev/null differ diff --git a/doc/window1.png b/doc/window1.png deleted file mode 100644 index 999873d3..00000000 Binary files a/doc/window1.png and /dev/null differ diff --git a/doc/window2.png b/doc/window2.png deleted file mode 100644 index 14d29338..00000000 Binary files a/doc/window2.png and /dev/null differ diff --git a/gradle.properties b/gradle.properties index b62aa109..ff86e6f1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,12 @@ -plugin_version = 8.1 -idea_local_path = -# '' | windows | mac | linux -build_env = -jcef_version = v6.0-jcef-beta.1 -intellij_version = 2021.1 -intellij_plugins = org.intellij.plugins.markdown:211.6693.44 +pluginGroup = com.shuzijun.leetcode +pluginName = leetcode-editor +pluginVersion = 8.2 + +pluginSinceBuild = 202.0 +pluginUntilBuild = + +platformType = IU +platformVersion = 2022.1 + +# ,-Dide.browser.jcef.log.level=verbose,-Duser.language=en-US +runIdeJvmArgs = -Dfile.encoding=utf-8,-Duser.language=en-US \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index cac17e51..6f44d0a8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,11 @@ -rootProject.name = 'leetcode-editor' - +pluginManagement { + repositories { + maven { + url 'https://oss.sonatype.org/content/repositories/snapshots/' + } + gradlePluginPortal() + } +} +rootProject.name = 'leetcode-editor' diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/AbstractAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/AbstractAction.java index d4da4398..737a2aa9 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/AbstractAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/AbstractAction.java @@ -9,10 +9,7 @@ import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.PluginConstant; import com.shuzijun.leetcode.plugin.setting.PersistentConfig; -import com.shuzijun.leetcode.plugin.utils.MTAUtils; -import com.shuzijun.leetcode.plugin.utils.MessageUtils; -import com.shuzijun.leetcode.plugin.utils.PropertiesUtils; -import com.shuzijun.leetcode.plugin.utils.UpdateUtils; +import com.shuzijun.leetcode.plugin.utils.*; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/AbstractEditAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/AbstractEditAction.java index d9817c94..e16313ba 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/AbstractEditAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/AbstractEditAction.java @@ -1,14 +1,20 @@ package com.shuzijun.leetcode.plugin.actions.editor; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.fileEditor.TextEditorWithPreview; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; import com.shuzijun.leetcode.plugin.actions.AbstractAction; -import com.shuzijun.leetcode.plugin.manager.ViewManager; +import com.shuzijun.leetcode.plugin.editor.ConvergePreview; +import com.shuzijun.leetcode.plugin.editor.QuestionEditorWithPreview; +import com.shuzijun.leetcode.plugin.manager.QuestionManager; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.LeetcodeEditor; import com.shuzijun.leetcode.plugin.model.Question; +import com.shuzijun.leetcode.plugin.setting.PersistentConfig; import com.shuzijun.leetcode.plugin.setting.ProjectConfig; import com.shuzijun.leetcode.plugin.utils.MessageUtils; import com.shuzijun.leetcode.plugin.utils.PropertiesUtils; @@ -34,11 +40,11 @@ public void actionPerformed(AnActionEvent anActionEvent, Config config) { MessageUtils.getInstance(anActionEvent.getProject()).showInfoMsg("info", PropertiesUtils.getInfo("tree.null")); return; } - if(!URLUtils.equalsHost(leetcodeEditor.getHost())){ + if (!URLUtils.equalsHost(leetcodeEditor.getHost())) { MessageUtils.getInstance(anActionEvent.getProject()).showInfoMsg("info", PropertiesUtils.getInfo("tree.host")); return; } - Question question = ViewManager.getQuestionByTitleSlug(leetcodeEditor.getTitleSlug(), null, anActionEvent.getProject()); + Question question = QuestionManager.getQuestionByTitleSlug(leetcodeEditor.getTitleSlug(), anActionEvent.getProject()); if (question == null) { MessageUtils.getInstance(anActionEvent.getProject()).showInfoMsg("info", PropertiesUtils.getInfo("tree.null")); return; @@ -50,4 +56,23 @@ public void actionPerformed(AnActionEvent anActionEvent, Config config) { } public abstract void actionPerformed(AnActionEvent anActionEvent, Config config, Question question); + + protected boolean openConvergeEditor(AnActionEvent anActionEvent, ConvergePreview.TabSelectFileEditorState state) { + FileEditor fileEditor = FileEditorManager.getInstance(anActionEvent.getProject()).getSelectedEditor(); + if (fileEditor != null && fileEditor instanceof QuestionEditorWithPreview) { + QuestionEditorWithPreview questionEditorWithPreview = (QuestionEditorWithPreview) fileEditor; + FileEditor previewEditor = questionEditorWithPreview.getPreviewEditor(); + if (previewEditor instanceof ConvergePreview) { + ConvergePreview convergePreview = (ConvergePreview) previewEditor; + ApplicationManager.getApplication().invokeLater(() -> { + convergePreview.setState(state); + if ((questionEditorWithPreview.getLayout() == TextEditorWithPreview.Layout.SHOW_PREVIEW && PersistentConfig.getInstance().getInitConfig().isLeftQuestionEditor()) || (questionEditorWithPreview.getLayout() == TextEditorWithPreview.Layout.SHOW_EDITOR && !PersistentConfig.getInstance().getInitConfig().isLeftQuestionEditor())) { + questionEditorWithPreview.setState(new TextEditorWithPreview.MyFileEditorState(TextEditorWithPreview.Layout.SHOW_EDITOR_AND_PREVIEW, null, null)); + } + }); + return true; + } + } + return false; + } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/OpenContentAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/OpenContentAction.java index a90d51be..d5830995 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/OpenContentAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/OpenContentAction.java @@ -2,6 +2,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.project.Project; +import com.shuzijun.leetcode.plugin.editor.ConvergePreview; import com.shuzijun.leetcode.plugin.manager.CodeManager; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Question; @@ -13,8 +14,11 @@ public class OpenContentAction extends AbstractEditAction { @Override public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { + if (config.getConvergeEditor() && openConvergeEditor(anActionEvent, new ConvergePreview.TabSelectFileEditorState("Content"))) { + return; + } Project project = anActionEvent.getProject(); - CodeManager.openContent(question, project, true); + CodeManager.openContent(question.getTitleSlug(), project, true); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/OpenSolutionAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/OpenSolutionAction.java index e39eeecd..b8ff5e21 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/OpenSolutionAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/OpenSolutionAction.java @@ -7,18 +7,23 @@ 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.openapi.vfs.VirtualFile; +import com.shuzijun.leetcode.plugin.editor.ConvergePreview; import com.shuzijun.leetcode.plugin.manager.ArticleManager; -import com.shuzijun.leetcode.plugin.manager.ViewManager; +import com.shuzijun.leetcode.plugin.manager.QuestionManager; import com.shuzijun.leetcode.plugin.model.*; import com.shuzijun.leetcode.plugin.setting.ProjectConfig; import com.shuzijun.leetcode.plugin.utils.URLUtils; -import com.shuzijun.leetcode.plugin.window.SolutionPanel; +import com.shuzijun.leetcode.plugin.window.dialog.SolutionPanel; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.util.List; -import java.util.concurrent.atomic.AtomicReference; /** * @author shuzijun @@ -36,21 +41,11 @@ public void update(@NotNull AnActionEvent anActionEvent) { anActionEvent.getPresentation().setEnabled(false); return; } - Question question = ViewManager.getCaCheQuestionByTitleSlug(leetcodeEditor.getTitleSlug(), null, anActionEvent.getProject()); + Question question = QuestionManager.getQuestionByTitleSlug(leetcodeEditor.getTitleSlug(), anActionEvent.getProject()); if (question != null) { anActionEvent.getPresentation().setEnabled(!Constant.ARTICLE_LIVE_NONE.equals(question.getArticleLive())); } else { - ProgressManager.getInstance().run(new Task.Backgroundable(anActionEvent.getProject(), "Get Question", false) { - @Override - public void run(@NotNull ProgressIndicator progressIndicator) { - Question question = ViewManager.getQuestionByTitleSlug(leetcodeEditor.getTitleSlug(), null, anActionEvent.getProject()); - if (question == null) { - anActionEvent.getPresentation().setEnabled(false); - return; - } - anActionEvent.getPresentation().setEnabled(!Constant.ARTICLE_LIVE_NONE.equals(question.getArticleLive())); - } - }); + anActionEvent.getPresentation().setEnabled(false); } } @@ -58,28 +53,61 @@ public void run(@NotNull ProgressIndicator progressIndicator) { public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { Project project = anActionEvent.getProject(); if (Constant.ARTICLE_LIVE_ONE.equals(question.getArticleLive())) { - ArticleManager.openArticle(question, project); + if (config.getConvergeEditor() && openConvergeEditor(anActionEvent, new ConvergePreview.TabSelectFileEditorState("Solution"))) { + return; + } + ArticleManager.openArticle(question.getTitleSlug(), question.getArticleSlug(), project, true); } else if (Constant.ARTICLE_LIVE_LIST.equals(question.getArticleLive())) { - List solutionList = ArticleManager.getSolutionList(question, anActionEvent.getProject()); + List solutionList = ArticleManager.getSolutionList(question.getTitleSlug(), anActionEvent.getProject()); if (solutionList.isEmpty()) { return; } - AtomicReference solution = new AtomicReference<>(); - ApplicationManager.getApplication().invokeAndWait(() -> { + + ApplicationManager.getApplication().invokeLater(() -> { SolutionPanel.TableModel tableModel = new SolutionPanel.TableModel(solutionList); SolutionPanel dialog = new SolutionPanel(anActionEvent.getProject(), tableModel); dialog.setTitle(question.getFormTitle() + " Solutions"); + dialog.addTableMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) { + int row = dialog.getSelectedRow(); + openArticle(anActionEvent, config, question, solutionList, row); + dialog.close(DialogWrapper.CANCEL_EXIT_CODE); + } + } + }); + dialog.addTableKeyListener(new KeyAdapter() { + @Override + public void keyTyped(KeyEvent e) { + if (e.getKeyChar() == KeyEvent.VK_ENTER) { + int row = dialog.getSelectedRow(); + openArticle(anActionEvent, config, question, solutionList, row); + dialog.close(DialogWrapper.CANCEL_EXIT_CODE); + } - if (dialog.showAndGet()) { - solution.set(solutionList.get(dialog.getSelectedRow())); - } + } + }); + dialog.show(); }); - if (solution.get() != null) { - question.setArticleSlug(solution.get().getSlug()); - ArticleManager.openArticle(question, project); - } } + } + private void openArticle(AnActionEvent anActionEvent, Config config, Question question, List solutionList, int row) { + Solution solution = solutionList.get(row); + if (solution != null) { + if (config.getConvergeEditor() && openConvergeEditor(anActionEvent, new ConvergePreview.TabSelectFileEditorState("Solution", solution.getSlug()))) { + return; + } + ProgressManager.getInstance().run(new Task.Backgroundable(anActionEvent.getProject(), anActionEvent.getActionManager().getId(this), false) { + @Override + public void run(@NotNull ProgressIndicator progressIndicator) { + question.setArticleSlug(solution.getSlug()); + ArticleManager.openArticle(question.getTitleSlug(), question.getArticleSlug(), anActionEvent.getProject(), true); + } + }); + + } } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/PositionAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/PositionAction.java new file mode 100644 index 00000000..db641c3c --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/PositionAction.java @@ -0,0 +1,60 @@ +package com.shuzijun.leetcode.plugin.actions.editor; + + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.ArrayUtil; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; +import com.shuzijun.leetcode.plugin.model.Config; +import com.shuzijun.leetcode.plugin.model.LeetcodeEditor; +import com.shuzijun.leetcode.plugin.model.Question; +import com.shuzijun.leetcode.plugin.setting.ProjectConfig; +import com.shuzijun.leetcode.plugin.utils.DataKeys; +import com.shuzijun.leetcode.plugin.window.WindowFactory; +import org.jetbrains.annotations.NotNull; + +/** + * @author shuzijun + */ +public class PositionAction extends AbstractEditAction { + + @Override + public void update(@NotNull AnActionEvent e) { + if (e.getProject() == null) { + return; + } + NavigatorAction navigatorAction = WindowFactory.getDataContext(e.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); + if (navigatorAction ==null || !navigatorAction.position(null)) { + e.getPresentation().setEnabled(false); + return; + } + VirtualFile vf = ArrayUtil.getFirstElement(FileEditorManager.getInstance(e.getProject()).getSelectedFiles()); + if (vf == null) { + e.getPresentation().setEnabled(false); + return; + } + LeetcodeEditor leetcodeEditor = ProjectConfig.getInstance(e.getProject()).getEditor(vf.getPath()); + if (leetcodeEditor == null) { + e.getPresentation().setEnabled(false); + return; + } + e.getPresentation().setEnabled(true); + } + + @Override + public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { + NavigatorAction navigatorAction = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); + if (navigatorAction == null) { + return; + } + + if (navigatorAction.position(question.getTitleSlug())) { + ApplicationManager.getApplication().invokeLater(() -> { + WindowFactory.activateToolWindow(anActionEvent.getProject()); + }); + } + + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/PullNoteAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/PullNoteAction.java index 4fc5bcfb..945abac9 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/PullNoteAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/PullNoteAction.java @@ -1,6 +1,7 @@ package com.shuzijun.leetcode.plugin.actions.editor; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.shuzijun.leetcode.plugin.editor.ConvergePreview; import com.shuzijun.leetcode.plugin.manager.NoteManager; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Question; @@ -11,8 +12,11 @@ public class PullNoteAction extends AbstractEditAction { @Override - public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question){ - NoteManager.pull(question,anActionEvent.getProject()); - NoteManager.show(question,anActionEvent.getProject()); + public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { + NoteManager.pull(question.getTitleSlug(), anActionEvent.getProject()); + if (config.getConvergeEditor() && openConvergeEditor(anActionEvent, new ConvergePreview.TabSelectFileEditorState("Note"))) { + return; + } + NoteManager.show(question.getTitleSlug(), anActionEvent.getProject(), true); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/PushNoteAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/PushNoteAction.java index 40d78f66..329cf8c6 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/PushNoteAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/PushNoteAction.java @@ -11,7 +11,7 @@ public class PushNoteAction extends AbstractEditAction { @Override - public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question){ - NoteManager.push(question,anActionEvent.getProject()); + public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { + NoteManager.push(question.getTitleSlug(), anActionEvent.getProject()); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/RunCodeAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/RunCodeAction.java index 36174a0b..4a2c1796 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/RunCodeAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/RunCodeAction.java @@ -12,6 +12,6 @@ public class RunCodeAction extends AbstractEditAction { @Override public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { - CodeManager.RunCodeCode(question, anActionEvent.getProject()); + CodeManager.RunCodeCode(question.getTitleSlug(), anActionEvent.getProject()); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/ShowNoteAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/ShowNoteAction.java index 575df12a..c6af5422 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/ShowNoteAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/ShowNoteAction.java @@ -1,6 +1,7 @@ package com.shuzijun.leetcode.plugin.actions.editor; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.shuzijun.leetcode.plugin.editor.ConvergePreview; import com.shuzijun.leetcode.plugin.manager.NoteManager; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Question; @@ -8,10 +9,13 @@ /** * @author shuzijun */ -public class ShowNoteAction extends AbstractEditAction { +public class ShowNoteAction extends AbstractEditAction { @Override - public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question){ - NoteManager.show(question,anActionEvent.getProject()); + public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { + if (config.getConvergeEditor() && openConvergeEditor(anActionEvent, new ConvergePreview.TabSelectFileEditorState("Note"))) { + return; + } + NoteManager.show(question.getTitleSlug(), anActionEvent.getProject(), true); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/SubmissionsAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/SubmissionsAction.java index f7b33ba2..f558112d 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/SubmissionsAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/SubmissionsAction.java @@ -2,14 +2,23 @@ import com.intellij.openapi.actionSystem.AnActionEvent; 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.ui.DialogWrapper; +import com.shuzijun.leetcode.plugin.editor.ConvergePreview; import com.shuzijun.leetcode.plugin.manager.SubmissionManager; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Question; import com.shuzijun.leetcode.plugin.model.Submission; -import com.shuzijun.leetcode.plugin.window.SubmissionsPanel; +import com.shuzijun.leetcode.plugin.window.dialog.SubmissionsPanel; +import org.jetbrains.annotations.NotNull; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.util.List; -import java.util.concurrent.atomic.AtomicReference; /** * @author shuzijun @@ -18,25 +27,52 @@ public class SubmissionsAction extends AbstractEditAction { @Override public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { - List submissionList = SubmissionManager.getSubmissionService(question, anActionEvent.getProject()); + List submissionList = SubmissionManager.getSubmissionService(question.getTitleSlug(), anActionEvent.getProject()); if (submissionList == null || submissionList.isEmpty()) { return; } - - AtomicReference submission = new AtomicReference<>(); - ApplicationManager.getApplication().invokeAndWait(()->{ + ApplicationManager.getApplication().invokeLater(() -> { SubmissionsPanel.TableModel tableModel = new SubmissionsPanel.TableModel(submissionList); SubmissionsPanel dialog = new SubmissionsPanel(anActionEvent.getProject(), tableModel); dialog.setTitle(question.getFormTitle() + " Submissions"); + dialog.addTableMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) { + int row = dialog.getSelectedRow(); + openSubmission(anActionEvent, config, question, submissionList, row); + dialog.close(DialogWrapper.CANCEL_EXIT_CODE); + } + } + }); + dialog.addTableKeyListener(new KeyAdapter() { + @Override + public void keyTyped(KeyEvent e) { + if (e.getKeyChar() == KeyEvent.VK_ENTER) { + int row = dialog.getSelectedRow(); + openSubmission(anActionEvent, config, question, submissionList, row); + dialog.close(DialogWrapper.CANCEL_EXIT_CODE); + } - if (dialog.showAndGet()) { - submission.set(submissionList.get(dialog.getSelectedRow())); + } + }); + dialog.show(); + }); + } + private void openSubmission(AnActionEvent anActionEvent, Config config, Question question, List submissionList, int row) { + Submission submission = submissionList.get(row); + if (submission != null) { + if (config.getConvergeEditor() && openConvergeEditor(anActionEvent, new ConvergePreview.TabSelectFileEditorState("Submissions", submission.getId()))) { + return; } - }); - if(submission.get() !=null){ - SubmissionManager.openSubmission(submission.get(), question, anActionEvent.getProject()); - } + ProgressManager.getInstance().run(new Task.Backgroundable(anActionEvent.getProject(), anActionEvent.getActionManager().getId(this), false) { + @Override + public void run(@NotNull ProgressIndicator progressIndicator) { + SubmissionManager.openSubmission(submission, question.getTitleSlug(), anActionEvent.getProject(), true); + } + }); + } } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/SubmitAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/SubmitAction.java index d2983ddd..5f45c069 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/SubmitAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/SubmitAction.java @@ -12,6 +12,6 @@ public class SubmitAction extends AbstractEditAction { @Override public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { - CodeManager.SubmitCode(question, anActionEvent.getProject()); + CodeManager.SubmitCode(question.getTitleSlug(), anActionEvent.getProject()); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/TestcaseAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/TestcaseAction.java index dafabd82..c4a210fb 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/TestcaseAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/editor/TestcaseAction.java @@ -3,13 +3,11 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.ApplicationManager; import com.shuzijun.leetcode.plugin.manager.CodeManager; -import com.shuzijun.leetcode.plugin.model.CodeTypeEnum; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Question; -import com.shuzijun.leetcode.plugin.setting.PersistentConfig; import com.shuzijun.leetcode.plugin.utils.MessageUtils; import com.shuzijun.leetcode.plugin.utils.PropertiesUtils; -import com.shuzijun.leetcode.plugin.window.TestcasePanel; +import com.shuzijun.leetcode.plugin.window.dialog.TestcasePanel; import org.apache.commons.lang.StringUtils; import java.util.concurrent.atomic.AtomicReference; @@ -20,15 +18,9 @@ public class TestcaseAction extends AbstractEditAction { @Override public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { - if (StringUtils.isBlank(question.getTestCase())) { - String codeType = PersistentConfig.getInstance().getInitConfig().getCodeType(); - CodeTypeEnum codeTypeEnum = CodeTypeEnum.getCodeTypeEnum(codeType); - - CodeManager.setTestCaeAndLang(question, codeTypeEnum, anActionEvent.getProject()); - } AtomicReference text = new AtomicReference<>(TestcaseAction.class.getName()); ApplicationManager.getApplication().invokeAndWait(() -> { - TestcasePanel dialog = new TestcasePanel(anActionEvent.getProject()); + TestcasePanel dialog = new TestcasePanel(anActionEvent.getProject(), question); dialog.setTitle(question.getFormTitle() + " Testcase"); dialog.setText(question.getTestCase()); if (dialog.showAndGet()) { @@ -41,7 +33,7 @@ public void actionPerformed(AnActionEvent anActionEvent, Config config, Question return; } else { question.setTestCase(text.get()); - CodeManager.RunCodeCode(question, anActionEvent.getProject()); + CodeManager.RunCodeCode(question.getTitleSlug(), anActionEvent.getProject()); } } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/ClearAllAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/ClearAllAction.java index b7d3a52e..a09864a1 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/ClearAllAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/ClearAllAction.java @@ -3,6 +3,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.vfs.LocalFileSystem; @@ -23,7 +24,7 @@ /** * @author shuzijun */ -public class ClearAllAction extends AbstractAction { +public class ClearAllAction extends AbstractAction implements DumbAware { @Override public void actionPerformed(AnActionEvent anActionEvent, Config config) { diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/ConfigAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/ConfigAction.java index 1f876f0c..f510c9a2 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/ConfigAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/ConfigAction.java @@ -3,12 +3,13 @@ import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.options.ShowSettingsUtil; +import com.intellij.openapi.project.DumbAware; import com.shuzijun.leetcode.plugin.model.PluginConstant; /** * @author shuzijun */ -public class ConfigAction extends AnAction { +public class ConfigAction extends AnAction implements DumbAware { @Override public void actionPerformed(AnActionEvent anActionEvent) { ShowSettingsUtil.getInstance().showSettingsDialog(anActionEvent.getProject(), PluginConstant.APPLICATION_CONFIGURABLE_DISPLAY_NAME); diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/FindAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/FindAction.java index 094072d2..81435804 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/FindAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/FindAction.java @@ -2,6 +2,8 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.ToggleAction; +import com.intellij.openapi.project.DumbAware; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; import com.shuzijun.leetcode.plugin.utils.DataKeys; import com.shuzijun.leetcode.plugin.window.WindowFactory; @@ -10,8 +12,9 @@ /** * @author shuzijun */ -public class FindAction extends ToggleAction { +public class FindAction extends ToggleAction implements DumbAware { + private int i = 0; @Override public boolean isSelected(AnActionEvent anActionEvent) { @@ -19,7 +22,11 @@ public boolean isSelected(AnActionEvent anActionEvent) { //Why is it null? return false; } - JPanel panel = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_TERRFIND); + NavigatorAction navigatorAction = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); + if (navigatorAction == null) { + return false; + } + JPanel panel = navigatorAction.queryPanel(); if (panel == null) { return false; } @@ -28,7 +35,11 @@ public boolean isSelected(AnActionEvent anActionEvent) { @Override public void setSelected(AnActionEvent anActionEvent, boolean b) { - JPanel panel = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_TERRFIND); + NavigatorAction navigatorAction = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); + if (navigatorAction == null) { + return; + } + JPanel panel = navigatorAction.queryPanel(); if (panel == null) { return; } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/FindActionGroup.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/FindActionGroup.java index b94f9c5a..34c04e58 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/FindActionGroup.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/FindActionGroup.java @@ -2,14 +2,16 @@ import com.google.common.collect.Lists; import com.intellij.openapi.actionSystem.ActionGroup; -import com.intellij.openapi.actionSystem.ActionToolbar; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.shuzijun.leetcode.plugin.manager.ViewManager; +import com.intellij.openapi.project.DumbAware; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; import com.shuzijun.leetcode.plugin.model.Constant; +import com.shuzijun.leetcode.plugin.model.Find; import com.shuzijun.leetcode.plugin.model.PluginConstant; import com.shuzijun.leetcode.plugin.model.Tag; import com.shuzijun.leetcode.plugin.utils.DataKeys; +import com.shuzijun.leetcode.plugin.window.WindowFactory; import icons.LeetCodeEditorIcons; import java.util.List; @@ -17,7 +19,9 @@ /** * @author shuzijun */ -public class FindActionGroup extends ActionGroup { +public class FindActionGroup extends ActionGroup implements DumbAware { + + private int i = 0; @Override public boolean displayTextInToolbar() { @@ -26,34 +30,31 @@ public boolean displayTextInToolbar() { @Override public void update(AnActionEvent e) { - ActionToolbar findToolbar = e.getDataContext().getData(DataKeys.LEETCODE_TOOLBAR_FIND); + NavigatorAction navigatorAction = WindowFactory.getDataContext(e.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); + String id = e.getActionManager().getId(this); - List tags = getTags(id); + List tags = getTags(id, navigatorAction.getFind()); if (tags != null && !tags.isEmpty()) { for (Tag tag : tags) { if (tag.isSelect()) { e.getPresentation().setIcon(LeetCodeEditorIcons.FILTER); - findToolbar.getComponent().updateUI(); + navigatorAction.updateUI(); return; } } } e.getPresentation().setIcon(null); - if (findToolbar != null && findToolbar.getComponent() != null) { - findToolbar.getComponent().updateUI(); - } + navigatorAction.updateUI(); } @Override public AnAction[] getChildren(AnActionEvent anActionEvent) { - List anActionList = Lists.newArrayList(); - String id = anActionEvent.getActionManager().getId(this); - - List tags = getTags(id); + NavigatorAction navigatorAction = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); + List tags = getTags(id, navigatorAction.getFind()); if (tags != null && !tags.isEmpty()) { for (Tag tag : tags) { @@ -65,43 +66,35 @@ public AnAction[] getChildren(AnActionEvent anActionEvent) { return anActions; } - private List getTags(String id) { - List tags = null; - if (PluginConstant.LEETCODE_FIND_DIFFICULTY.equals(id)) { - tags = ViewManager.getFilter(Constant.FIND_TYPE_DIFFICULTY); - } else if (PluginConstant.LEETCODE_FIND_STATUS.equals(id)) { - tags = ViewManager.getFilter(Constant.FIND_TYPE_STATUS); - } else if (PluginConstant.LEETCODE_FIND_LISTS.equals(id)) { - tags = ViewManager.getFilter(Constant.FIND_TYPE_LISTS); - } else if (PluginConstant.LEETCODE_FIND_TAGS.equals(id)) { - tags = ViewManager.getFilter(Constant.FIND_TYPE_TAGS); - } else if (PluginConstant.LEETCODE_FIND_CATEGORY.equals(id)) { - tags = ViewManager.getFilter(Constant.FIND_TYPE_CATEGORY); - } - - return tags; + private List getTags(String id, Find find) { + return find.getFilter(getKey(id)); } private boolean onlyOne(String id) { if (PluginConstant.LEETCODE_FIND_TAGS.equals(id)) { return false; } + if (PluginConstant.LEETCODE_ALL_FIND_TAGS.equals(id)) { + return false; + } return true; } private String getFilterKey(String id) { - if (PluginConstant.LEETCODE_FIND_DIFFICULTY.equals(id)) { - return "difficulty"; - } else if (PluginConstant.LEETCODE_FIND_STATUS.equals(id)) { - return "status"; - } else if (PluginConstant.LEETCODE_FIND_LISTS.equals(id)) { + String key = getKey(id); + if (Constant.FIND_TYPE_LISTS.equalsIgnoreCase(key)) { return "listId"; - } else if (PluginConstant.LEETCODE_FIND_TAGS.equals(id)) { - return "tags"; - } else if (PluginConstant.LEETCODE_FIND_CATEGORY.equals(id)) { + } else if (Constant.FIND_TYPE_CATEGORY.equalsIgnoreCase(key)) { return "categorySlug"; + } else if (Constant.CODETOP_FIND_TYPE_COMPANY.equalsIgnoreCase(key)) { + return "listId"; + } else { + return key; } - return ""; + } + + private String getKey(String id) { + return id.replace(PluginConstant.LEETCODE_FIND_PREFIX, "").replace(PluginConstant.LEETCODE_ALL_FIND_PREFIX, "").replace(PluginConstant.LEETCODE_CODETOP_FIND_PREFIX, ""); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/FindClearAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/FindClearAction.java index d705eb18..0c7e790e 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/FindClearAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/FindClearAction.java @@ -2,27 +2,25 @@ import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.DumbAware; import com.shuzijun.leetcode.plugin.actions.AbstractAction; -import com.shuzijun.leetcode.plugin.manager.ViewManager; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.utils.DataKeys; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; import com.shuzijun.leetcode.plugin.window.WindowFactory; /** * @author shuzijun */ -public class FindClearAction extends AbstractAction { +public class FindClearAction extends AbstractAction implements DumbAware { @Override public void actionPerformed(AnActionEvent anActionEvent, Config config) { - NavigatorTable navigatorTable = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_TREE); - if (navigatorTable == null) { + NavigatorAction navigatorAction = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); + if (navigatorAction == null) { return; - } else { - navigatorTable.getPageInfo().clearFilter(); } - ViewManager.loadServiceData(navigatorTable,anActionEvent.getProject()); + navigatorAction.findClear(); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/FindTagAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/FindTagAction.java index 0d7d33be..7050c312 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/FindTagAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/FindTagAction.java @@ -5,11 +5,11 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; -import com.shuzijun.leetcode.plugin.manager.ViewManager; +import com.intellij.openapi.project.DumbAware; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; import com.shuzijun.leetcode.plugin.model.PluginConstant; import com.shuzijun.leetcode.plugin.model.Tag; import com.shuzijun.leetcode.plugin.utils.DataKeys; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; import com.shuzijun.leetcode.plugin.window.WindowFactory; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -19,7 +19,7 @@ /** * @author shuzijun */ -public class FindTagAction extends ToggleAction { +public class FindTagAction extends ToggleAction implements DumbAware { private Tag tag; @@ -48,24 +48,15 @@ public void setSelected(AnActionEvent anActionEvent, boolean b) { typeTags.forEach(tag -> tag.setSelect(false)); } tag.setSelect(b); - NavigatorTable navigatorTable = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_TREE); - if (navigatorTable == null) { + + NavigatorAction navigatorAction = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); + if (navigatorAction == null) { return; } ProgressManager.getInstance().run(new Task.Backgroundable(anActionEvent.getProject(), PluginConstant.PLUGIN_NAME + "." + tag.getName(), false) { @Override public void run(@NotNull ProgressIndicator progressIndicator) { - if ("categorySlug".equals(filterKey)) { - if (b) { - navigatorTable.getPageInfo().setCategorySlug(tag.getSlug()); - } else { - navigatorTable.getPageInfo().setCategorySlug(""); - } - } else { - navigatorTable.getPageInfo().disposeFilters(filterKey, tag.getSlug(), b); - } - navigatorTable.getPageInfo().setPageIndex(1); - ViewManager.loadServiceData(navigatorTable, anActionEvent.getProject()); + navigatorAction.findChange(filterKey, b, tag); } }); } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/HelpAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/HelpAction.java index a149770a..fe6aecdf 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/HelpAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/HelpAction.java @@ -3,12 +3,13 @@ import com.intellij.ide.BrowserUtil; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.DumbAware; /** * @author shuzijun */ -public class HelpAction extends AnAction { +public class HelpAction extends AnAction implements DumbAware { @Override public void actionPerformed(AnActionEvent anActionEvent) { BrowserUtil.browse("https://github.com/shuzijun/leetcode-editor"); diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/LoginAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/LoginAction.java index 4fd5e5b9..129e0ef6 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/LoginAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/LoginAction.java @@ -2,12 +2,18 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.DumbAware; import com.shuzijun.leetcode.plugin.actions.AbstractAction; -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.setting.PersistentConfig; import com.shuzijun.leetcode.plugin.utils.*; -import com.shuzijun.leetcode.plugin.window.*; +import com.shuzijun.leetcode.plugin.window.NavigatorTabsPanel; +import com.shuzijun.leetcode.plugin.window.WindowFactory; +import com.shuzijun.leetcode.plugin.window.login.HttpLogin; +import com.shuzijun.leetcode.plugin.window.login.LoginPanel; import org.apache.commons.lang.StringUtils; import java.net.HttpCookie; @@ -16,27 +22,26 @@ /** * @author shuzijun */ -public class LoginAction extends AbstractAction { +public class LoginAction extends AbstractAction implements DumbAware { @Override - public void actionPerformed(AnActionEvent anActionEvent, Config config) { + public synchronized void actionPerformed(AnActionEvent anActionEvent, Config config) { - NavigatorTable navigatorTable = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_TREE); + NavigatorAction navigatorAction = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); if (StringUtils.isBlank(HttpRequestUtils.getToken())) { - HttpRequest httpRequest = HttpRequest.get(URLUtils.getLeetcodeVerify()); - HttpResponse response = HttpRequestUtils.executeGet(httpRequest); - if (response == null) { - MessageUtils.getInstance(anActionEvent.getProject()).showWarnMsg("warning", PropertiesUtils.getInfo("request.failed")); - return; - } + HttpResponse response = HttpRequest.builderGet(URLUtils.getLeetcodeVerify()).request(); if (response.getStatusCode() != 200) { MessageUtils.getInstance(anActionEvent.getProject()).showWarnMsg("warning", PropertiesUtils.getInfo("request.failed")); return; } } else { - if (HttpRequestUtils.isLogin()) { + if (HttpRequestUtils.isLogin(anActionEvent.getProject())) { MessageUtils.getInstance(anActionEvent.getProject()).showWarnMsg("info", PropertiesUtils.getInfo("login.exist")); + NavigatorTabsPanel.loadUser(true); + if (navigatorAction.getPageInfo().getRowTotal() == 0) { + ApplicationManager.getApplication().getMessageBus().syncPublisher(LoginNotifier.TOPIC).login(anActionEvent.getProject(), config.getUrl()); + } return; } } @@ -49,9 +54,10 @@ public void actionPerformed(AnActionEvent anActionEvent, Config config) { if (StringUtils.isNotBlank(config.getCookie(config.getUrl() + config.getLoginName()))) { List cookieList = CookieUtils.toHttpCookie(config.getCookie(config.getUrl() + config.getLoginName())); HttpRequestUtils.setCookie(cookieList); - if (HttpRequestUtils.isLogin()) { + if (HttpRequestUtils.isLogin(anActionEvent.getProject())) { MessageUtils.getInstance(anActionEvent.getProject()).showInfoMsg("login", PropertiesUtils.getInfo("login.success")); - ViewManager.loadServiceData(navigatorTable, anActionEvent.getProject()); + NavigatorTabsPanel.loadUser(true); + ApplicationManager.getApplication().getMessageBus().syncPublisher(LoginNotifier.TOPIC).login(anActionEvent.getProject(), config.getUrl()); return; } else { config.addCookie(config.getUrl() + config.getLoginName(), null); @@ -59,17 +65,12 @@ public void actionPerformed(AnActionEvent anActionEvent, Config config) { } } - if (!HttpLogin.ajaxLogin(config, navigatorTable, anActionEvent.getProject())) { - ApplicationManager.getApplication().invokeAndWait(new Runnable() { + if (!HttpLogin.ajaxLogin(config, navigatorAction, anActionEvent.getProject())) { + ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { - LoginFrame loginFrame; - if (HttpLogin.isEnabledJcef()) { - loginFrame = new JcefLogin(anActionEvent.getProject(), navigatorTable); - } else { - loginFrame = new CookieLogin(anActionEvent.getProject(), navigatorTable); - } - loginFrame.loadComponent(); + LoginPanel loginPanel = new LoginPanel(anActionEvent.getProject()); + loginPanel.show(); } }); } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/LogoutAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/LogoutAction.java index 36e97a2d..7778d7bd 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/LogoutAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/LogoutAction.java @@ -1,28 +1,26 @@ package com.shuzijun.leetcode.plugin.actions.toolbar; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.DumbAware; import com.shuzijun.leetcode.plugin.actions.AbstractAction; -import com.shuzijun.leetcode.plugin.manager.ViewManager; +import com.shuzijun.leetcode.plugin.listener.LoginNotifier; import com.shuzijun.leetcode.plugin.model.Config; +import com.shuzijun.leetcode.plugin.model.HttpRequest; import com.shuzijun.leetcode.plugin.utils.*; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; -import com.shuzijun.leetcode.plugin.window.WindowFactory; +import com.shuzijun.leetcode.plugin.window.NavigatorTabsPanel; /** * @author shuzijun */ -public class LogoutAction extends AbstractAction { +public class LogoutAction extends AbstractAction implements DumbAware { @Override public void actionPerformed(AnActionEvent anActionEvent, Config config) { - HttpRequest httpRequest = HttpRequest.get(URLUtils.getLeetcodeLogout()); - HttpResponse httpResponse = HttpRequestUtils.executeGet(httpRequest); + HttpResponse httpResponse = HttpRequest.builderGet(URLUtils.getLeetcodeLogout()).request(); HttpRequestUtils.resetHttpclient(); MessageUtils.getInstance(anActionEvent.getProject()).showInfoMsg("info", PropertiesUtils.getInfo("login.out")); - NavigatorTable navigatorTable = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_TREE); - if(navigatorTable == null){ - return; - } - ViewManager.loadServiceData(navigatorTable, anActionEvent.getProject()); + NavigatorTabsPanel.loadUser(false); + ApplicationManager.getApplication().getMessageBus().syncPublisher(LoginNotifier.TOPIC).logout(anActionEvent.getProject(), config.getUrl()); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/PickAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/PickAction.java index bb30ae63..60d3243e 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/PickAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/PickAction.java @@ -1,24 +1,23 @@ package com.shuzijun.leetcode.plugin.actions.toolbar; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.DumbAware; import com.shuzijun.leetcode.plugin.actions.AbstractAction; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; import com.shuzijun.leetcode.plugin.manager.ViewManager; -import com.shuzijun.leetcode.plugin.model.CodeTypeEnum; import com.shuzijun.leetcode.plugin.model.Config; -import com.shuzijun.leetcode.plugin.utils.MessageUtils; -import com.shuzijun.leetcode.plugin.utils.PropertiesUtils; +import com.shuzijun.leetcode.plugin.utils.DataKeys; +import com.shuzijun.leetcode.plugin.window.WindowFactory; /** * @author shuzijun */ -public class PickAction extends AbstractAction { +public class PickAction extends AbstractAction implements DumbAware { + private int i = 0; + @Override public void actionPerformed(AnActionEvent anActionEvent, Config config) { - CodeTypeEnum codeTypeEnum = CodeTypeEnum.getCodeTypeEnum(config.getCodeType()); - if (codeTypeEnum == null) { - MessageUtils.getInstance(anActionEvent.getProject()).showWarnMsg("info", PropertiesUtils.getInfo("config.code")); - return; - } - ViewManager.pick(codeTypeEnum, anActionEvent.getProject()); + NavigatorAction navigatorAction = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); + ViewManager.pick(anActionEvent.getProject(), navigatorAction.getPageInfo()); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/ProgressAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/ProgressAction.java index 12cf0c3a..570c5587 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/ProgressAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/ProgressAction.java @@ -2,18 +2,19 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.shuzijun.leetcode.plugin.actions.AbstractAction; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; import com.shuzijun.leetcode.plugin.manager.SessionManager; -import com.shuzijun.leetcode.plugin.manager.ViewManager; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Session; +import com.shuzijun.leetcode.plugin.setting.StatisticsData; import com.shuzijun.leetcode.plugin.utils.DataKeys; import com.shuzijun.leetcode.plugin.utils.HttpRequestUtils; import com.shuzijun.leetcode.plugin.utils.MessageUtils; import com.shuzijun.leetcode.plugin.utils.PropertiesUtils; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; import com.shuzijun.leetcode.plugin.window.ProgressPanel; import com.shuzijun.leetcode.plugin.window.WindowFactory; import org.jetbrains.annotations.Nullable; @@ -25,11 +26,11 @@ /** * @author shuzijun */ -public class ProgressAction extends AbstractAction { +public class ProgressAction extends AbstractAction implements DumbAware { @Override public void actionPerformed(AnActionEvent anActionEvent, Config config) { - if (!HttpRequestUtils.isLogin()) { + if (!HttpRequestUtils.isLogin(anActionEvent.getProject())) { MessageUtils.getInstance(anActionEvent.getProject()).showWarnMsg("info", PropertiesUtils.getInfo("login.not")); return; } @@ -52,9 +53,10 @@ public void actionPerformed(AnActionEvent anActionEvent, Config config) { return; } else { if (SessionManager.switchSession(anActionEvent.getProject(), session.getId())) { - NavigatorTable navigatorTable = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_TREE); - navigatorTable.getPageInfo().clear(); - ViewManager.loadServiceData(navigatorTable, anActionEvent.getProject()); + NavigatorAction navigatorAction = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); + navigatorAction.getFind().operationType(""); + navigatorAction.findClear(); + StatisticsData.refresh(anActionEvent.getProject()); actionPerformed(anActionEvent, config); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/RefreshAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/RefreshAction.java index db4d81f3..9ef8d9f2 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/RefreshAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/RefreshAction.java @@ -1,24 +1,23 @@ package com.shuzijun.leetcode.plugin.actions.toolbar; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.DumbAware; import com.shuzijun.leetcode.plugin.actions.AbstractAction; -import com.shuzijun.leetcode.plugin.manager.ViewManager; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.utils.DataKeys; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; import com.shuzijun.leetcode.plugin.window.WindowFactory; /** * @author shuzijun */ -public class RefreshAction extends AbstractAction { +public class RefreshAction extends AbstractAction implements DumbAware { @Override public void actionPerformed(AnActionEvent anActionEvent, Config config) { - NavigatorTable navigatorTable = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_TREE); - navigatorTable.getPageInfo().clear(); - ViewManager.loadServiceData(navigatorTable, anActionEvent.getProject()); - + NavigatorAction navigatorAction = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); + navigatorAction.getFind().operationType(""); + navigatorAction.findClear(); } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/ShareAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/ShareAction.java new file mode 100644 index 00000000..ec296a53 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/ShareAction.java @@ -0,0 +1,17 @@ +package com.shuzijun.leetcode.plugin.actions.toolbar; + +import com.intellij.ide.BrowserUtil; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.DumbAware; +import com.shuzijun.leetcode.plugin.actions.AbstractAction; +import com.shuzijun.leetcode.plugin.model.Config; + +/** + * @author shuzijun + */ +public class ShareAction extends AbstractAction implements DumbAware { + @Override + public void actionPerformed(AnActionEvent anActionEvent, Config config) { + BrowserUtil.browse("https://codetop.cc/?utm_source=leetcode_editor"); + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/SortAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/SortAction.java index 7bd28eb2..9396ccde 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/SortAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/SortAction.java @@ -1,15 +1,14 @@ package com.shuzijun.leetcode.plugin.actions.toolbar; -import com.intellij.openapi.actionSystem.ActionToolbar; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.DumbAware; import com.shuzijun.leetcode.plugin.actions.AbstractAction; -import com.shuzijun.leetcode.plugin.manager.ViewManager; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Constant; import com.shuzijun.leetcode.plugin.model.PluginConstant; import com.shuzijun.leetcode.plugin.model.Sort; import com.shuzijun.leetcode.plugin.utils.DataKeys; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; import com.shuzijun.leetcode.plugin.window.WindowFactory; import icons.LeetCodeEditorIcons; import org.jetbrains.annotations.NotNull; @@ -17,7 +16,7 @@ /** * @author shuzijun */ -public class SortAction extends AbstractAction { +public class SortAction extends AbstractAction implements DumbAware { @Override public boolean displayTextInToolbar() { @@ -26,11 +25,11 @@ public boolean displayTextInToolbar() { @Override public void update(@NotNull AnActionEvent e) { - Sort sort = getSort(e); + NavigatorAction navigatorAction = WindowFactory.getDataContext(e.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); + Sort sort = getSort(e, navigatorAction); if (sort == null) { return; } - ActionToolbar sortToolbar = e.getDataContext().getData(DataKeys.LEETCODE_TOOLBAR_SORT); if (sort.getType() == Constant.SORT_ASC) { e.getPresentation().setIcon(LeetCodeEditorIcons.SORT_ASC); } else if (sort.getType() == Constant.SORT_DESC) { @@ -38,42 +37,32 @@ public void update(@NotNull AnActionEvent e) { } else { e.getPresentation().setIcon(null); } - if (sortToolbar != null && sortToolbar.getComponent() != null) { - sortToolbar.getComponent().updateUI(); - } + navigatorAction.updateUI(); super.update(e); } @Override public void actionPerformed(AnActionEvent anActionEvent, Config config) { - NavigatorTable navigatorTable = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_TREE); - if (navigatorTable == null || ViewManager.getFilter(Constant.FIND_TYPE_DIFFICULTY) == null) { + NavigatorAction navigatorAction = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); + if (navigatorAction == null) { return; } - Sort sort = getSort(anActionEvent); + Sort sort = getSort(anActionEvent, navigatorAction); if (sort == null) { return; } - ViewManager.operationType(getKey(anActionEvent)); - if (sort.getType() == 0) { - navigatorTable.getPageInfo().disposeFilters("orderBy", "", false); - navigatorTable.getPageInfo().disposeFilters("sortOrder", "", false); - } else if (sort.getType() == 1) { - navigatorTable.getPageInfo().disposeFilters("orderBy", sort.getSlug(), true); - navigatorTable.getPageInfo().disposeFilters("sortOrder", "DESCENDING", true); - } else if (sort.getType() == 2) { - navigatorTable.getPageInfo().disposeFilters("orderBy", sort.getSlug(), true); - navigatorTable.getPageInfo().disposeFilters("sortOrder", "ASCENDING", true); - } - ViewManager.loadServiceData(navigatorTable, anActionEvent.getProject()); + navigatorAction.getFind().operationType(getKey(anActionEvent)); + navigatorAction.sort(sort); } - private Sort getSort(AnActionEvent anActionEvent) { - return ViewManager.getSort(getKey(anActionEvent)); + private Sort getSort(AnActionEvent anActionEvent, NavigatorAction navigatorAction) { + return navigatorAction.getFind().getSort(getKey(anActionEvent)); } private String getKey(AnActionEvent anActionEvent) { - return anActionEvent.getActionManager().getId(this).replace(PluginConstant.LEETCODE_SORT_PREFIX, ""); + return anActionEvent.getActionManager().getId(this).replace(PluginConstant.LEETCODE_SORT_PREFIX, "") + .replace(PluginConstant.LEETCODE_CODETOP_SORT_PREFIX, "") + .replace(PluginConstant.LEETCODE_ALL_SORT_PREFIX, ""); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/ToggleListAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/ToggleListAction.java new file mode 100644 index 00000000..7322bb25 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/ToggleListAction.java @@ -0,0 +1,25 @@ +package com.shuzijun.leetcode.plugin.actions.toolbar; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.DumbAware; +import com.shuzijun.leetcode.plugin.actions.AbstractAction; +import com.shuzijun.leetcode.plugin.model.Config; +import com.shuzijun.leetcode.plugin.utils.DataKeys; +import com.shuzijun.leetcode.plugin.window.NavigatorTabsPanel; +import com.shuzijun.leetcode.plugin.window.WindowFactory; + +/** + * @author shuzijun + */ +public class ToggleListAction extends AbstractAction implements DumbAware { + @Override + public void actionPerformed(AnActionEvent anActionEvent, Config config) { + NavigatorTabsPanel navigatorTabs = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_TABS); + if (navigatorTabs == null) { + return; + } + ApplicationManager.getApplication().invokeLater(() -> navigatorTabs.toggle()); + + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/page/AbstractPageAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/page/AbstractPageAction.java new file mode 100644 index 00000000..89ad323c --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/page/AbstractPageAction.java @@ -0,0 +1,27 @@ +package com.shuzijun.leetcode.plugin.actions.toolbar.page; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.DumbAware; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; +import com.shuzijun.leetcode.plugin.utils.DataKeys; +import com.shuzijun.leetcode.plugin.window.WindowFactory; + +/** + * @author shuzijun + */ +public abstract class AbstractPageAction extends AnAction implements DumbAware { + + @Override + public void actionPerformed(AnActionEvent anActionEvent) { + + NavigatorAction navigatorAction = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); + if (navigatorAction == null) { + return; + } + + actionPerformed(anActionEvent, navigatorAction); + } + + public abstract void actionPerformed(AnActionEvent anActionEvent, NavigatorAction navigatorAction); +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/page/GoAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/page/GoAction.java new file mode 100644 index 00000000..cbce4da9 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/page/GoAction.java @@ -0,0 +1,14 @@ +package com.shuzijun.leetcode.plugin.actions.toolbar.page; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; + +/** + * @author shuzijun + */ +public class GoAction extends AbstractPageAction { + @Override + public void actionPerformed(AnActionEvent anActionEvent, NavigatorAction navigatorAction) { + navigatorAction.getPagePanel().clickGo(); + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/page/NextAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/page/NextAction.java new file mode 100644 index 00000000..459814d5 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/page/NextAction.java @@ -0,0 +1,14 @@ +package com.shuzijun.leetcode.plugin.actions.toolbar.page; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; + +/** + * @author shuzijun + */ +public class NextAction extends AbstractPageAction { + @Override + public void actionPerformed(AnActionEvent anActionEvent, NavigatorAction navigatorAction) { + navigatorAction.getPagePanel().clickNext(); + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/page/PageBoxAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/page/PageBoxAction.java new file mode 100644 index 00000000..83e5782e --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/page/PageBoxAction.java @@ -0,0 +1,14 @@ +package com.shuzijun.leetcode.plugin.actions.toolbar.page; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; + +/** + * @author shuzijun + */ +public class PageBoxAction extends AbstractPageAction { + @Override + public void actionPerformed(AnActionEvent anActionEvent, NavigatorAction navigatorAction) { + navigatorAction.getPagePanel().focusedPage(); + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/page/PageSizeBoxAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/page/PageSizeBoxAction.java new file mode 100644 index 00000000..51011928 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/page/PageSizeBoxAction.java @@ -0,0 +1,14 @@ +package com.shuzijun.leetcode.plugin.actions.toolbar.page; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; + +/** + * @author shuzijun + */ +public class PageSizeBoxAction extends AbstractPageAction { + @Override + public void actionPerformed(AnActionEvent anActionEvent, NavigatorAction navigatorAction) { + navigatorAction.getPagePanel().focusedPageSize(); + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/page/PreviousAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/page/PreviousAction.java new file mode 100644 index 00000000..e0e28f46 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/toolbar/page/PreviousAction.java @@ -0,0 +1,14 @@ +package com.shuzijun.leetcode.plugin.actions.toolbar.page; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; + +/** + * @author shuzijun + */ +public class PreviousAction extends AbstractPageAction { + @Override + public void actionPerformed(AnActionEvent anActionEvent, NavigatorAction navigatorAction) { + navigatorAction.getPagePanel().clickPrevious(); + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/AbstractTreeAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/AbstractTreeAction.java index 2da2f317..865687ff 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/AbstractTreeAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/AbstractTreeAction.java @@ -1,31 +1,37 @@ package com.shuzijun.leetcode.plugin.actions.tree; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.DumbAware; import com.shuzijun.leetcode.plugin.actions.AbstractAction; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; +import com.shuzijun.leetcode.plugin.manager.QuestionManager; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Question; +import com.shuzijun.leetcode.plugin.model.QuestionView; import com.shuzijun.leetcode.plugin.utils.DataKeys; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; import com.shuzijun.leetcode.plugin.window.WindowFactory; /** * @author shuzijun */ -public abstract class AbstractTreeAction extends AbstractAction { +public abstract class AbstractTreeAction extends AbstractAction implements DumbAware { @Override public void actionPerformed(AnActionEvent anActionEvent, Config config) { - WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_TREE); - NavigatorTable navigatorTable = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_TREE); - if (navigatorTable == null) { + NavigatorAction navigatorAction = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); + if (navigatorAction == null) { return; } - Question question = navigatorTable.getSelectedRowData(); + QuestionView questionView = navigatorAction.getSelectedRowData(); + if (questionView == null) { + return; + } + Question question = QuestionManager.getQuestionByTitleSlug(questionView.getTitleSlug(), anActionEvent.getProject()); if (question == null) { return; } - actionPerformed(anActionEvent, config, navigatorTable, question); + actionPerformed(anActionEvent, config, question); } - public abstract void actionPerformed(AnActionEvent anActionEvent, Config config, NavigatorTable navigatorTable, Question question); + public abstract void actionPerformed(AnActionEvent anActionEvent, Config config, Question question); } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/ClearOneAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/ClearOneAction.java index e9fd27a8..9cb5425b 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/ClearOneAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/ClearOneAction.java @@ -12,7 +12,6 @@ import com.shuzijun.leetcode.plugin.utils.MessageUtils; import com.shuzijun.leetcode.plugin.utils.PropertiesUtils; import com.shuzijun.leetcode.plugin.utils.VelocityUtils; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; import java.io.File; @@ -21,7 +20,7 @@ */ public class ClearOneAction extends AbstractTreeAction { @Override - public void actionPerformed(AnActionEvent anActionEvent, Config config, NavigatorTable navigatorTable, Question question) { + public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { String codeType = config.getCodeType(); CodeTypeEnum codeTypeEnum = CodeTypeEnum.getCodeTypeEnum(codeType); diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/FavoriteAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/FavoriteAction.java index b8e407ef..40de3526 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/FavoriteAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/FavoriteAction.java @@ -2,17 +2,18 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.ToggleAction; -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.DumbAware; import com.shuzijun.leetcode.plugin.manager.FavoriteManager; -import com.shuzijun.leetcode.plugin.manager.ViewManager; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; +import com.shuzijun.leetcode.plugin.manager.QuestionManager; import com.shuzijun.leetcode.plugin.model.PluginConstant; import com.shuzijun.leetcode.plugin.model.Question; +import com.shuzijun.leetcode.plugin.model.QuestionView; import com.shuzijun.leetcode.plugin.model.Tag; import com.shuzijun.leetcode.plugin.utils.DataKeys; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; import com.shuzijun.leetcode.plugin.window.WindowFactory; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -20,7 +21,7 @@ /** * @author shuzijun */ -public class FavoriteAction extends ToggleAction { +public class FavoriteAction extends ToggleAction implements DumbAware { private Tag tag; @@ -32,18 +33,12 @@ public FavoriteAction(@Nullable String text, Tag tag) { @Override public boolean isSelected(AnActionEvent anActionEvent) { - NavigatorTable navigatorTable = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_TREE); - final Question question = navigatorTable.getSelectedRowData(); - if (question == null) { + NavigatorAction navigatorAction = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); + final QuestionView questionView = navigatorAction.getSelectedRowData(); + if (questionView == null) { return false; } - Question cacheQuestion = ViewManager.getCaCheQuestionByTitleSlug(question.getTitleSlug(), null, anActionEvent.getProject()); - if (cacheQuestion == null) { - try { - cacheQuestion = ApplicationManager.getApplication().executeOnPooledThread(() -> ViewManager.getQuestionByTitleSlug(question.getTitleSlug(), null, anActionEvent.getProject())).get(); - } catch (Exception e) { - } - } + Question cacheQuestion = QuestionManager.getQuestionByTitleSlug(questionView.getTitleSlug(), anActionEvent.getProject()); if (cacheQuestion == null) { return false; } @@ -52,9 +47,9 @@ public boolean isSelected(AnActionEvent anActionEvent) { @Override public void setSelected(AnActionEvent anActionEvent, boolean b) { - NavigatorTable navigatorTable = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_TREE); - Question question = navigatorTable.getSelectedRowData(); - if (question == null) { + NavigatorAction navigatorAction = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); + QuestionView questionView = navigatorAction.getSelectedRowData(); + if (questionView == null) { return; } @@ -62,9 +57,9 @@ public void setSelected(AnActionEvent anActionEvent, boolean b) { @Override public void run(@NotNull ProgressIndicator progressIndicator) { if (b) { - FavoriteManager.addQuestionToFavorite(tag, question, anActionEvent.getProject()); + FavoriteManager.addQuestionToFavorite(tag, questionView.getTitleSlug(), anActionEvent.getProject()); } else { - FavoriteManager.removeQuestionFromFavorite(tag, question, anActionEvent.getProject()); + FavoriteManager.removeQuestionFromFavorite(tag, questionView.getTitleSlug(), anActionEvent.getProject()); } } }); diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/FavoriteActionGroup.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/FavoriteActionGroup.java index 5defd477..ba1874c4 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/FavoriteActionGroup.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/FavoriteActionGroup.java @@ -4,22 +4,25 @@ import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.shuzijun.leetcode.plugin.manager.ViewManager; +import com.intellij.openapi.project.DumbAware; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; import com.shuzijun.leetcode.plugin.model.Constant; import com.shuzijun.leetcode.plugin.model.Tag; +import com.shuzijun.leetcode.plugin.utils.DataKeys; +import com.shuzijun.leetcode.plugin.window.WindowFactory; import java.util.List; /** * @author shuzijun */ -public class FavoriteActionGroup extends ActionGroup { +public class FavoriteActionGroup extends ActionGroup implements DumbAware { @Override public AnAction[] getChildren(AnActionEvent anActionEvent) { - + NavigatorAction navigatorAction = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); List anActionList = Lists.newArrayList(); - List tags = ViewManager.getFilter(Constant.FIND_TYPE_LISTS); + List tags = navigatorAction.getFind().getFilter(Constant.FIND_TYPE_LISTS); if (tags != null && !tags.isEmpty()) { for (Tag tag : tags) { if (!"leetcode_favorites".equals(tag.getType())) { diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/OpenAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/OpenAction.java index 4072f70f..298cfc8d 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/OpenAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/OpenAction.java @@ -5,15 +5,14 @@ import com.shuzijun.leetcode.plugin.manager.CodeManager; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Question; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; /** * @author shuzijun */ public class OpenAction extends AbstractTreeAction { @Override - public void actionPerformed(AnActionEvent anActionEvent, Config config, NavigatorTable navigatorTable, Question question) { + public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { Project project = anActionEvent.getProject(); - CodeManager.openCode(question, project); + CodeManager.openCode(question.getTitleSlug(), project); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/OpenContentAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/OpenContentAction.java index 48e46ec8..770a7c97 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/OpenContentAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/OpenContentAction.java @@ -5,7 +5,6 @@ import com.shuzijun.leetcode.plugin.manager.CodeManager; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Question; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; /** * @author shuzijun @@ -13,8 +12,8 @@ public class OpenContentAction extends AbstractTreeAction { @Override - public void actionPerformed(AnActionEvent anActionEvent, Config config, NavigatorTable navigatorTable, Question question) { + public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { Project project = anActionEvent.getProject(); - CodeManager.openContent(question, project, true); + CodeManager.openContent(question.getTitleSlug(), project, true); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/OpenInWebAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/OpenInWebAction.java index 48199236..6a60e3c2 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/OpenInWebAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/OpenInWebAction.java @@ -5,14 +5,13 @@ import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Question; import com.shuzijun.leetcode.plugin.utils.URLUtils; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; /** * @author zzdcon */ public class OpenInWebAction extends AbstractTreeAction { @Override - public void actionPerformed(AnActionEvent anActionEvent, Config config, NavigatorTable navigatorTable, Question question) { + public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { BrowserUtil.browse(URLUtils.getLeetcodeProblems() + question.getTitleSlug()); } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/OpenSolutionAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/OpenSolutionAction.java index a1e2ffd5..4d135689 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/OpenSolutionAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/OpenSolutionAction.java @@ -2,20 +2,25 @@ import com.intellij.openapi.actionSystem.AnActionEvent; 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.shuzijun.leetcode.plugin.manager.ArticleManager; -import com.shuzijun.leetcode.plugin.model.Config; -import com.shuzijun.leetcode.plugin.model.Constant; -import com.shuzijun.leetcode.plugin.model.Question; -import com.shuzijun.leetcode.plugin.model.Solution; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; +import com.shuzijun.leetcode.plugin.manager.QuestionManager; +import com.shuzijun.leetcode.plugin.model.*; import com.shuzijun.leetcode.plugin.utils.DataKeys; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; -import com.shuzijun.leetcode.plugin.window.SolutionPanel; import com.shuzijun.leetcode.plugin.window.WindowFactory; +import com.shuzijun.leetcode.plugin.window.dialog.SolutionPanel; import org.jetbrains.annotations.NotNull; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.util.List; -import java.util.concurrent.atomic.AtomicReference; /** * @author shuzijun @@ -24,16 +29,20 @@ public class OpenSolutionAction extends AbstractTreeAction { @Override public void update(@NotNull AnActionEvent anActionEvent) { - NavigatorTable navigatorTable = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_TREE); - if (navigatorTable == null) { + NavigatorAction navigatorAction = WindowFactory.getDataContext(anActionEvent.getProject()).getData(DataKeys.LEETCODE_PROJECTS_NAVIGATORACTION); + if (navigatorAction == null) { anActionEvent.getPresentation().setEnabled(false); return; } - Question question = navigatorTable.getSelectedRowData(); - if (question == null) { + QuestionView questionView = navigatorAction.getSelectedRowData(); + if (questionView == null) { anActionEvent.getPresentation().setEnabled(false); return; } + Question question = QuestionManager.getQuestionByTitleSlug(questionView.getTitleSlug(), anActionEvent.getProject()); + if (question == null) { + return; + } if (Constant.ARTICLE_LIVE_NONE.equals(question.getArticleLive())) { anActionEvent.getPresentation().setEnabled(false); } else { @@ -42,31 +51,54 @@ public void update(@NotNull AnActionEvent anActionEvent) { } @Override - public void actionPerformed(AnActionEvent anActionEvent, Config config, NavigatorTable navigatorTable, Question question) { + public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { Project project = anActionEvent.getProject(); if (Constant.ARTICLE_LIVE_ONE.equals(question.getArticleLive())) { - ArticleManager.openArticle(question, project); + ArticleManager.openArticle(question.getTitleSlug(), question.getArticleSlug(), project, true); } else if (Constant.ARTICLE_LIVE_LIST.equals(question.getArticleLive())) { - List solutionList = ArticleManager.getSolutionList(question, anActionEvent.getProject()); + List solutionList = ArticleManager.getSolutionList(question.getTitleSlug(), anActionEvent.getProject()); if (solutionList.isEmpty()) { return; } - AtomicReference solution = new AtomicReference<>(); - ApplicationManager.getApplication().invokeAndWait(() -> { + ApplicationManager.getApplication().invokeLater(() -> { SolutionPanel.TableModel tableModel = new SolutionPanel.TableModel(solutionList); SolutionPanel dialog = new SolutionPanel(anActionEvent.getProject(), tableModel); dialog.setTitle(question.getFormTitle() + " Solutions"); + dialog.addTableMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) { + int row = dialog.getSelectedRow(); + openArticle(anActionEvent, config, question, solutionList, row); + dialog.close(DialogWrapper.CANCEL_EXIT_CODE); + } + } + }); + dialog.addTableKeyListener(new KeyAdapter() { + @Override + public void keyTyped(KeyEvent e) { + if (e.getKeyChar() == KeyEvent.VK_ENTER) { + int row = dialog.getSelectedRow(); + openArticle(anActionEvent, config, question, solutionList, row); + dialog.close(DialogWrapper.CANCEL_EXIT_CODE); + } - if (dialog.showAndGet()) { - solution.set(solutionList.get(dialog.getSelectedRow())); - } + } + }); + dialog.show(); }); - if(solution.get() !=null){ - question.setArticleSlug(solution.get().getSlug()); - ArticleManager.openArticle(question, project); - } - } + } + private void openArticle(AnActionEvent anActionEvent, Config config, Question question, List solutionList, int row) { + Solution solution = solutionList.get(row); + + ProgressManager.getInstance().run(new Task.Backgroundable(anActionEvent.getProject(), anActionEvent.getActionManager().getId(this), false) { + @Override + public void run(@NotNull ProgressIndicator progressIndicator) { + question.setArticleSlug(solution.getSlug()); + ArticleManager.openArticle(question.getTitleSlug(), question.getArticleSlug(), anActionEvent.getProject(), true); + } + }); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/PullNoteAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/PullNoteAction.java index e0880ea2..0a789204 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/PullNoteAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/PullNoteAction.java @@ -4,16 +4,15 @@ import com.shuzijun.leetcode.plugin.manager.NoteManager; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Question; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; /** * @author shuzijun */ -public class PullNoteAction extends AbstractTreeAction { +public class PullNoteAction extends AbstractTreeAction { @Override - public void actionPerformed(AnActionEvent anActionEvent, Config config, NavigatorTable navigatorTable, Question question) { - NoteManager.pull(question,anActionEvent.getProject()); - NoteManager.show(question,anActionEvent.getProject()); + public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { + NoteManager.pull(question.getTitleSlug(), anActionEvent.getProject()); + NoteManager.show(question.getTitleSlug(), anActionEvent.getProject(), true); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/PushNoteAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/PushNoteAction.java index 1012a81b..b906bf2e 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/PushNoteAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/PushNoteAction.java @@ -4,15 +4,14 @@ import com.shuzijun.leetcode.plugin.manager.NoteManager; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Question; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; /** * @author shuzijun */ -public class PushNoteAction extends AbstractTreeAction { +public class PushNoteAction extends AbstractTreeAction { @Override - public void actionPerformed(AnActionEvent anActionEvent, Config config, NavigatorTable navigatorTable, Question question) { - NoteManager.push(question,anActionEvent.getProject()); + public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { + NoteManager.push(question.getTitleSlug(), anActionEvent.getProject()); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/ResetTimeAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/ResetTimeAction.java index 45ef6761..54fe5015 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/ResetTimeAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/ResetTimeAction.java @@ -5,14 +5,13 @@ import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Question; import com.shuzijun.leetcode.plugin.timer.TimerBarWidget; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; /** * @author shuzijun */ public class ResetTimeAction extends AbstractTreeAction { @Override - public void actionPerformed(AnActionEvent anActionEvent, Config config, NavigatorTable navigatorTable, Question question) { + public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { TimerBarWidget timerBarWidget = (TimerBarWidget) WindowManager.getInstance().getStatusBar(anActionEvent.getProject()).getWidget(TimerBarWidget.ID); if (timerBarWidget != null) { timerBarWidget.reset(); diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/RunCodeAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/RunCodeAction.java index 9bad79fc..aefda44a 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/RunCodeAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/RunCodeAction.java @@ -4,14 +4,13 @@ import com.shuzijun.leetcode.plugin.manager.CodeManager; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Question; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; /** * @author shuzijun */ -public class RunCodeAction extends AbstractTreeAction { +public class RunCodeAction extends AbstractTreeAction { @Override - public void actionPerformed(AnActionEvent anActionEvent, Config config, NavigatorTable navigatorTable, Question question) { - CodeManager.RunCodeCode(question, anActionEvent.getProject()); + public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { + CodeManager.RunCodeCode(question.getTitleSlug(), anActionEvent.getProject()); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/ShowNoteAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/ShowNoteAction.java index 8a9d6c66..89a5ba9e 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/ShowNoteAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/ShowNoteAction.java @@ -4,15 +4,14 @@ import com.shuzijun.leetcode.plugin.manager.NoteManager; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Question; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; /** * @author shuzijun */ -public class ShowNoteAction extends AbstractTreeAction { +public class ShowNoteAction extends AbstractTreeAction { @Override - public void actionPerformed(AnActionEvent anActionEvent, Config config, NavigatorTable navigatorTable, Question question) { - NoteManager.show(question,anActionEvent.getProject()); + public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { + NoteManager.show(question.getTitleSlug(), anActionEvent.getProject(), true); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/StartTimeAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/StartTimeAction.java index 2e96c1b7..aa90f0dc 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/StartTimeAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/StartTimeAction.java @@ -5,14 +5,13 @@ import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Question; import com.shuzijun.leetcode.plugin.timer.TimerBarWidget; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; /** * @author shuzijun */ -public class StartTimeAction extends AbstractTreeAction { +public class StartTimeAction extends AbstractTreeAction { @Override - public void actionPerformed(AnActionEvent anActionEvent, Config config, NavigatorTable navigatorTable, Question question) { + public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { TimerBarWidget timerBarWidget = (TimerBarWidget) WindowManager.getInstance().getStatusBar(anActionEvent.getProject()).getWidget(TimerBarWidget.ID); if (timerBarWidget != null) { timerBarWidget.startTimer(question.getTitle()); diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/StopTimeAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/StopTimeAction.java index 533bb9e1..1f852a9a 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/StopTimeAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/StopTimeAction.java @@ -5,14 +5,13 @@ import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Question; import com.shuzijun.leetcode.plugin.timer.TimerBarWidget; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; /** * @author shuzijun */ -public class StopTimeAction extends AbstractTreeAction { +public class StopTimeAction extends AbstractTreeAction { @Override - public void actionPerformed(AnActionEvent anActionEvent, Config config, NavigatorTable navigatorTable, Question question) { + public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { TimerBarWidget timerBarWidget = (TimerBarWidget) WindowManager.getInstance().getStatusBar(anActionEvent.getProject()).getWidget(TimerBarWidget.ID); if (timerBarWidget != null) { timerBarWidget.stopTimer(); diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/SubmissionsAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/SubmissionsAction.java index 7eaa974b..97296707 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/SubmissionsAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/SubmissionsAction.java @@ -2,41 +2,72 @@ import com.intellij.openapi.actionSystem.AnActionEvent; 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.ui.DialogWrapper; import com.shuzijun.leetcode.plugin.manager.SubmissionManager; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Question; import com.shuzijun.leetcode.plugin.model.Submission; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; -import com.shuzijun.leetcode.plugin.window.SubmissionsPanel; +import com.shuzijun.leetcode.plugin.window.dialog.SubmissionsPanel; +import org.jetbrains.annotations.NotNull; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.util.List; -import java.util.concurrent.atomic.AtomicReference; /** * @author shuzijun */ public class SubmissionsAction extends AbstractTreeAction { @Override - public void actionPerformed(AnActionEvent anActionEvent, Config config, NavigatorTable navigatorTable, Question question) { + public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { - List submissionList = SubmissionManager.getSubmissionService(question, anActionEvent.getProject()); + List submissionList = SubmissionManager.getSubmissionService(question.getTitleSlug(), anActionEvent.getProject()); if (submissionList == null || submissionList.isEmpty()) { return; } - AtomicReference submission = new AtomicReference<>(); - ApplicationManager.getApplication().invokeAndWait(() -> { + ApplicationManager.getApplication().invokeLater(() -> { SubmissionsPanel.TableModel tableModel = new SubmissionsPanel.TableModel(submissionList); SubmissionsPanel dialog = new SubmissionsPanel(anActionEvent.getProject(), tableModel); dialog.setTitle(question.getFormTitle() + " Submissions"); + dialog.addTableMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) { + int row = dialog.getSelectedRow(); + openSubmission(anActionEvent, config, question, submissionList, row); + dialog.close(DialogWrapper.CANCEL_EXIT_CODE); + } + } + }); + dialog.addTableKeyListener(new KeyAdapter() { + @Override + public void keyTyped(KeyEvent e) { + if (e.getKeyChar() == KeyEvent.VK_ENTER) { + int row = dialog.getSelectedRow(); + openSubmission(anActionEvent, config, question, submissionList, row); + dialog.close(DialogWrapper.CANCEL_EXIT_CODE); + } - if (dialog.showAndGet()) { - submission.set(submissionList.get(dialog.getSelectedRow())); - } + } + }); + dialog.show(); }); - if(submission.get() !=null){ - SubmissionManager.openSubmission(submission.get(), question, anActionEvent.getProject()); - } + } + private void openSubmission(AnActionEvent anActionEvent, Config config, Question question, List submissionList, int row) { + Submission submission = submissionList.get(row); + + ProgressManager.getInstance().run(new Task.Backgroundable(anActionEvent.getProject(), anActionEvent.getActionManager().getId(this), false) { + @Override + public void run(@NotNull ProgressIndicator progressIndicator) { + SubmissionManager.openSubmission(submission, question.getTitleSlug(), anActionEvent.getProject(), true); + } + }); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/SubmitAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/SubmitAction.java index b348c3f1..c3a32b6d 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/SubmitAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/SubmitAction.java @@ -4,14 +4,13 @@ import com.shuzijun.leetcode.plugin.manager.CodeManager; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Question; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; /** * @author shuzijun */ -public class SubmitAction extends AbstractTreeAction { +public class SubmitAction extends AbstractTreeAction { @Override - public void actionPerformed(AnActionEvent anActionEvent, Config config, NavigatorTable navigatorTable, Question question) { - CodeManager.SubmitCode(question, anActionEvent.getProject()); + public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { + CodeManager.SubmitCode(question.getTitleSlug(), anActionEvent.getProject()); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/TestcaseAction.java b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/TestcaseAction.java index 9f67251b..4ef59f0b 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/TestcaseAction.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/actions/tree/TestcaseAction.java @@ -3,14 +3,11 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.ApplicationManager; import com.shuzijun.leetcode.plugin.manager.CodeManager; -import com.shuzijun.leetcode.plugin.model.CodeTypeEnum; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Question; -import com.shuzijun.leetcode.plugin.setting.PersistentConfig; import com.shuzijun.leetcode.plugin.utils.MessageUtils; import com.shuzijun.leetcode.plugin.utils.PropertiesUtils; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; -import com.shuzijun.leetcode.plugin.window.TestcasePanel; +import com.shuzijun.leetcode.plugin.window.dialog.TestcasePanel; import org.apache.commons.lang.StringUtils; import java.util.concurrent.atomic.AtomicReference; @@ -20,16 +17,11 @@ */ public class TestcaseAction extends AbstractTreeAction { @Override - public void actionPerformed(AnActionEvent anActionEvent, Config config, NavigatorTable navigatorTable, Question question) { - if (StringUtils.isBlank(question.getTestCase())) { - String codeType = PersistentConfig.getInstance().getInitConfig().getCodeType(); - CodeTypeEnum codeTypeEnum = CodeTypeEnum.getCodeTypeEnum(codeType); + public void actionPerformed(AnActionEvent anActionEvent, Config config, Question question) { - CodeManager.setTestCaeAndLang(question, codeTypeEnum, anActionEvent.getProject()); - } AtomicReference text = new AtomicReference<>(TestcaseAction.class.getName()); ApplicationManager.getApplication().invokeAndWait(() -> { - TestcasePanel dialog = new TestcasePanel(anActionEvent.getProject()); + TestcasePanel dialog = new TestcasePanel(anActionEvent.getProject(), question); dialog.setTitle(question.getFormTitle() + " Testcase"); dialog.setText(question.getTestCase()); if (dialog.showAndGet()) { @@ -43,7 +35,7 @@ public void actionPerformed(AnActionEvent anActionEvent, Config config, Navigato return; } else { question.setTestCase(text.get()); - CodeManager.RunCodeCode(question, anActionEvent.getProject()); + CodeManager.RunCodeCode(question.getTitleSlug(), anActionEvent.getProject()); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/editor/ContentProvider.java b/src/main/java/com/shuzijun/leetcode/plugin/editor/ContentProvider.java deleted file mode 100644 index b074a18d..00000000 --- a/src/main/java/com/shuzijun/leetcode/plugin/editor/ContentProvider.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.shuzijun.leetcode.plugin.editor; - -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import org.jetbrains.annotations.NotNull; - -/** - * @author shuzijun - */ -public class ContentProvider extends LCVProvider{ - - @Override - public boolean accept(@NotNull Project project, @NotNull VirtualFile file) { - return true; - } -} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/editor/ConvergePreview.java b/src/main/java/com/shuzijun/leetcode/plugin/editor/ConvergePreview.java new file mode 100644 index 00000000..95750d13 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/editor/ConvergePreview.java @@ -0,0 +1,281 @@ +package com.shuzijun.leetcode.plugin.editor; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.fileEditor.*; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.UserDataHolderBase; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.pom.Navigatable; +import com.intellij.ui.tabs.TabInfo; +import com.intellij.ui.tabs.TabsListener; +import com.intellij.ui.tabs.impl.JBEditorTabs; +import com.intellij.util.messages.MessageBusConnection; +import com.intellij.util.ui.JBUI; +import com.shuzijun.leetcode.plugin.listener.LoginNotifier; +import com.shuzijun.leetcode.plugin.model.LeetcodeEditor; +import com.shuzijun.leetcode.plugin.model.PluginConstant; +import com.shuzijun.leetcode.plugin.setting.ProjectConfig; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.beans.PropertyChangeListener; + +/** + * @author shuzijun + */ +public class ConvergePreview extends UserDataHolderBase implements TextEditor { + + private final Project project; + private final FileEditor[] fileEditors; + private final String[] names; + private final TabInfo[] tabInfos; + private final VirtualFile file; + + + private JComponent myComponent; + private JBEditorTabs jbEditorTabs; + + private LeetcodeEditor leetcodeEditor; + + public ConvergePreview(@NotNull FileEditor[] fileEditors, String[] names, Project project, VirtualFile file) { + this.project = project; + this.fileEditors = fileEditors; + this.names = names; + this.tabInfos = new TabInfo[names.length]; + this.file = file; + + this.leetcodeEditor = ProjectConfig.getInstance(project).getEditor(file.getPath()); + + + MessageBusConnection settingsConnection = ApplicationManager.getApplication().getMessageBus().connect(this); + settingsConnection.subscribe(LoginNotifier.TOPIC, new LoginNotifier() { + @Override + public void login(Project project, String host) { + if (host.equals(leetcodeEditor.getHost())) { + for (int i = 0; i < names.length; i++) { + fileEditors[i].setState(LoginState.getState(true, tabInfos[i] == jbEditorTabs.getSelectedInfo())); + } + } + } + + @Override + public void logout(Project project, String host) { + if (host.equals(leetcodeEditor.getHost())) { + for (int i = 0; i < names.length; i++) { + fileEditors[i].setState(LoginState.getState(false, tabInfos[i] == jbEditorTabs.getSelectedInfo())); + } + } + } + }); + } + + @Override + public @NotNull JComponent getComponent() { + if (myComponent == null) { + jbEditorTabs = new JBEditorTabs(project, IdeFocusManager.getInstance(project), this); + for (int i = 0; i < fileEditors.length; i++) { + TabInfo tabInfo = new TabInfo(fileEditors[i].getComponent()); + tabInfo.setText(names[i]); + tabInfos[i] = tabInfo; + jbEditorTabs.addTab(tabInfo); + } + jbEditorTabs.addListener(new TabsListener() { + @Override + public void selectionChanged(TabInfo oldSelection, TabInfo newSelection) { + for (int i = 0; i < names.length; i++) { + if (newSelection.getText().equals(names[i])) { + fileEditors[i].setState(TabFileEditorState.TabFileEditorLoadState); + break; + } + } + } + }); + + + myComponent = JBUI.Panels.simplePanel(jbEditorTabs); + } + return myComponent; + } + + @Override + public @Nullable JComponent getPreferredFocusedComponent() { + return fileEditors[0].getPreferredFocusedComponent(); + } + + @Override + public @NotNull String getName() { + return PluginConstant.LEETCODE_EDITOR_TAB_VIEW; + } + + @Override + public void setState(@NotNull FileEditorState state) { + if (state instanceof TabSelectFileEditorState) { + if (jbEditorTabs != null) { + String name = ((TabSelectFileEditorState) state).getName(); + for (int i = 0; i < names.length; i++) { + if (name.equals(names[i])) { + fileEditors[i].setState(state); + jbEditorTabs.select(tabInfos[i], true); + } + } + } + } + } + + @Override + public boolean isModified() { + return false; + } + + @Override + public boolean isValid() { + return true; + } + + @Override + public void addPropertyChangeListener(@NotNull PropertyChangeListener listener) { + + } + + @Override + public void removePropertyChangeListener(@NotNull PropertyChangeListener listener) { + + } + + @Override + public @Nullable FileEditorLocation getCurrentLocation() { + return fileEditors[0].getCurrentLocation(); + } + + @Override + public void dispose() { + for (FileEditor fileEditor : fileEditors) { + Disposer.dispose(fileEditor); + } + } + + + @Override + public @Nullable VirtualFile getFile() { + return file; + } + + @Override + public Editor getEditor() { + return null; + } + + @Override + public boolean canNavigateTo(@NotNull Navigatable navigatable) { + return false; + } + + @Override + public void navigateTo(@NotNull Navigatable navigatable) { + + } + + public static class TabFileEditorState implements FileEditorState { + + private boolean load = false; + + public TabFileEditorState(boolean load) { + this.load = load; + } + + public boolean isLoad() { + return load; + } + + @Override + public boolean canBeMergedWith(@NotNull FileEditorState otherState, @NotNull FileEditorStateLevel level) { + return false; + } + + public static TabFileEditorState TabFileEditorLoadState = new TabFileEditorState(true); + + + } + + public static class TabSelectFileEditorState implements FileEditorState { + + private String name; + + private String childrenState; + + public TabSelectFileEditorState(String name) { + this.name = name; + } + + public TabSelectFileEditorState(String name, String childrenState) { + this.name = name; + this.childrenState = childrenState; + } + + public String getName() { + return name; + } + + public String getChildrenState() { + return childrenState; + } + + @Override + public boolean canBeMergedWith(@NotNull FileEditorState otherState, @NotNull FileEditorStateLevel level) { + return false; + } + + } + + public static class LoginState implements FileEditorState { + + public static LoginState NoLoginNoSelect = new LoginState(false, false); + public static LoginState NoLoginSelect = new LoginState(false, true); + public static LoginState LoginNoSelect = new LoginState(true, false); + public static LoginState LoginSelect = new LoginState(true, true); + + public static LoginState getState(boolean login, boolean select) { + if (login) { + if (select) { + return LoginSelect; + } else { + return LoginNoSelect; + } + } else { + if (select) { + return NoLoginSelect; + } else { + return NoLoginNoSelect; + } + } + } + + private boolean login; + + private boolean select; + + public LoginState(boolean login, boolean select) { + this.login = login; + this.select = select; + } + + public boolean isLogin() { + return login; + } + + public boolean isSelect() { + return select; + } + + @Override + public boolean canBeMergedWith(@NotNull FileEditorState otherState, @NotNull FileEditorStateLevel level) { + return false; + } + + } + +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/editor/ConvergeProvider.java b/src/main/java/com/shuzijun/leetcode/plugin/editor/ConvergeProvider.java new file mode 100644 index 00000000..f5ccfacb --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/editor/ConvergeProvider.java @@ -0,0 +1,89 @@ +package com.shuzijun.leetcode.plugin.editor; + +import com.intellij.openapi.fileEditor.*; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.stream.Collectors; + +/** + * @author shuzijun + */ +public class ConvergeProvider implements AsyncFileEditorProvider, DumbAware { + + + @NotNull + protected final FileEditorProvider[] editorProviders; + protected final String[] names; + + @NotNull + private final String myEditorTypeId; + + public ConvergeProvider(@NotNull FileEditorProvider[] editorProviders, @NotNull String[] names) { + this.editorProviders = editorProviders; + this.names = names; + this.myEditorTypeId = "tab-provider[" + Arrays.stream(editorProviders).map(FileEditorProvider::getEditorTypeId).collect(Collectors.joining(";")) + "]"; + } + + + @NotNull + @Override + public AsyncFileEditorProvider.Builder createEditorAsync(@NotNull final Project project, @NotNull final VirtualFile file) { + final Builder[] builders = new Builder[editorProviders.length]; + for (int i = 0; i < editorProviders.length; i++) { + builders[i] = getBuilderFromEditorProvider(editorProviders[i], project, file); + } + return new Builder() { + @Override + public TextEditor build() { + FileEditor[] fileEditors = new FileEditor[editorProviders.length]; + for (int i = 0; i < builders.length; i++) { + fileEditors[i] = builders[i].build(); + } + return createSplitEditor(fileEditors,project,file); + } + }; + } + + protected TextEditor createSplitEditor(@NotNull FileEditor[] fileEditors, Project project, VirtualFile file) { + return new ConvergePreview(fileEditors, names, project, file); + } + + @Override + public boolean accept(@NotNull Project project, @NotNull VirtualFile file) { + return true; + } + + @Override + public @NotNull FileEditor createEditor(@NotNull Project project, @NotNull VirtualFile file) { + return createEditorAsync(project, file).build(); + } + + @Override + public @NotNull @NonNls String getEditorTypeId() { + return myEditorTypeId; + } + + @Override + public @NotNull FileEditorPolicy getPolicy() { + return FileEditorPolicy.HIDE_DEFAULT_EDITOR; + } + + @NotNull + public static Builder getBuilderFromEditorProvider(@NotNull final FileEditorProvider provider, @NotNull final Project project, @NotNull final VirtualFile file) { + if (provider instanceof AsyncFileEditorProvider) { + return ((AsyncFileEditorProvider) provider).createEditorAsync(project, file); + } else { + return new Builder() { + @Override + public FileEditor build() { + return provider.createEditor(project, file); + } + }; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/shuzijun/leetcode/plugin/editor/LCVPanel.java b/src/main/java/com/shuzijun/leetcode/plugin/editor/LCVPanel.java index 3f3f461e..c4319755 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/editor/LCVPanel.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/editor/LCVPanel.java @@ -6,20 +6,29 @@ import com.intellij.notification.Notifications; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.colors.EditorColors; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.colors.impl.EditorColorsSchemeImpl; +import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.fileTypes.ex.FileTypeChooser; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.JBColor; import com.intellij.ui.jcef.JCEFHtmlPanel; +import com.intellij.util.Url; +import com.intellij.util.Urls; import com.intellij.util.io.HttpRequests; import com.intellij.util.io.URLUtil; import com.intellij.util.ui.UIUtil; import com.shuzijun.leetcode.plugin.model.PluginConstant; import com.shuzijun.leetcode.plugin.utils.FileUtils; +import com.shuzijun.leetcode.plugin.utils.PropertiesUtils; import io.netty.handler.codec.http.HttpHeaderNames; import org.apache.commons.lang.StringUtils; import org.cef.browser.CefBrowser; @@ -29,13 +38,19 @@ import org.cef.network.CefRequest; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.ide.BuiltInServerManager; +import java.awt.*; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; import java.util.*; +import java.util.List; /** * @author shuzijun @@ -44,19 +59,36 @@ public class LCVPanel extends JCEFHtmlPanel { private static final Logger LOG = Logger.getInstance(LCVPanel.class); - private final CefRequestHandler requestHandler; - private final CefLifeSpanHandler lifeSpanHandler; + private final Url servicePath = BuiltInServerManager.getInstance().addAuthToken(Urls.parseEncoded("http://localhost:" + BuiltInServerManager.getInstance().getPort() + PreviewStaticServer.PREFIX)); + private String templateHtmlFile = "template/default.html"; + + private CefRequestHandler requestHandler; + private CefLifeSpanHandler lifeSpanHandler; private final String url; + private final String text; private final Project project; private final List iframe = new ArrayList<>(); private static final List headers = Arrays.asList(HttpHeaderNames.CONTENT_SECURITY_POLICY.toString(), HttpHeaderNames.CONTENT_ENCODING.toString() , HttpHeaderNames.CONTENT_LENGTH.toString()); - public LCVPanel(@Nullable String url, Project project) { - super("about:blank"); + public LCVPanel(@Nullable String url, Project project, String text, boolean old) { + super(null); this.url = url; this.project = project; + this.text = text; + init(); + } + + public LCVPanel(@Nullable String url, Project project, String text) { + super(null, null); + this.url = url; + this.project = project; + this.text = text; + init(); + } + + private void init() { getJBCefClient().addRequestHandler(requestHandler = new CefRequestHandlerAdapter() { @Override public boolean onBeforeBrowse(CefBrowser browser, CefFrame frame, CefRequest request, boolean user_gesture, boolean is_redirect) { @@ -116,6 +148,11 @@ public boolean onBeforePopup(CefBrowser browser, CefFrame frame, String target_u return true; } }, getCefBrowser()); + loadHTML(createHtml(text), url); + } + + public void reloadText() { + loadHTML(createHtml(text), url); } @Override @@ -151,7 +188,82 @@ private void openUrl(String url) { } } - public void updateStyle(String style) { + private String createHtml(String text) { + InputStream inputStream = null; + + try { + + inputStream = PreviewStaticServer.class.getResourceAsStream("/" + templateHtmlFile); + + String template = new String(FileUtilRt.loadBytes(inputStream)); + return template.replace("{{service}}", servicePath.getScheme() + URLUtil.SCHEME_SEPARATOR + servicePath.getAuthority() + servicePath.getPath()) + .replace("{{serverToken}}", org.apache.commons.lang3.StringUtils.isNotBlank(servicePath.getParameters()) ? servicePath.getParameters().substring(1) : "") + .replace("{{fileValue}}", text) + .replace("{{Lang}}", PropertiesUtils.getInfo("Lang")) + .replace("{{darcula}}", UIUtil.isUnderDarcula() + "") + .replace("{{ideStyle}}", getStyle(true)) + ; + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException ignore) { + } + } + } + } + + private String getStyle(boolean isTag) { + try { + EditorColorsSchemeImpl editorColorsScheme = (EditorColorsSchemeImpl) EditorColorsManager.getInstance().getGlobalScheme(); + Color defaultBackground = editorColorsScheme.getDefaultBackground(); + + Color scrollbarThumbColor = EditorColors.SCROLLBAR_THUMB_COLOR.getDefaultColor(); + if (editorColorsScheme.getColor(EditorColors.SCROLLBAR_THUMB_COLOR) != null) { + scrollbarThumbColor = editorColorsScheme.getColor(EditorColors.SCROLLBAR_THUMB_COLOR); + } + TextAttributes textAttributes = editorColorsScheme.getDirectlyDefinedAttributes().get("TEXT"); + Color text = null; + if (textAttributes != null) { + text = textAttributes.getForegroundColor(); + } + String fontFamily = "font-family:\"" + editorColorsScheme.getEditorFontName() + "\",\"Helvetica Neue\",\"Luxi Sans\",\"DejaVu Sans\"," + + "\"Hiragino Sans GB\",\"Microsoft Yahei\",sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Noto Color Emoji\",\"Segoe UI Symbol\"," + + "\"Android Emoji\",\"EmojiSymbols\";"; + StringBuilder sb = new StringBuilder(isTag ? "" : ""); + return sb.toString(); + } catch (Exception e) { + return ""; + } + + } + + private String toHexColor(Color color) { + DecimalFormat df = new DecimalFormat("0.00"); + DecimalFormatSymbols dfs = new DecimalFormatSymbols(); + dfs.setDecimalSeparator('.'); + df.setDecimalFormatSymbols(dfs); + return String.format("rgba(%s,%s,%s,%s)", color.getRed(), color.getGreen(), color.getBlue(), df.format(color.getAlpha() / (float) 255)); + } + + public void updateStyle() { + String style = getStyle(false); getCefBrowser().executeJavaScript( "updateStyle('" + style + "'," + UIUtil.isUnderDarcula() + ");", getCefBrowser().getURL(), 0); } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/editor/LCVPreview.java b/src/main/java/com/shuzijun/leetcode/plugin/editor/LCVPreview.java index 0b549e99..cc4975e1 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/editor/LCVPreview.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/editor/LCVPreview.java @@ -3,12 +3,7 @@ import com.google.common.net.UrlEscapers; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.colors.EditorColors; -import com.intellij.openapi.editor.colors.EditorColorsListener; import com.intellij.openapi.editor.colors.EditorColorsManager; -import com.intellij.openapi.editor.colors.EditorColorsScheme; -import com.intellij.openapi.editor.colors.impl.EditorColorsSchemeImpl; -import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorLocation; @@ -16,30 +11,19 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.UserDataHolderBase; -import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.ui.JBColor; import com.intellij.ui.components.JBLabel; -import com.intellij.util.Url; -import com.intellij.util.Urls; import com.intellij.util.io.URLUtil; import com.intellij.util.messages.MessageBusConnection; -import com.intellij.util.ui.UIUtil; +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.FileUtils; -import com.shuzijun.leetcode.plugin.utils.PropertiesUtils; -import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.ide.BuiltInServerManager; import javax.swing.*; -import java.awt.*; import java.beans.PropertyChangeListener; -import java.io.IOException; -import java.io.InputStream; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; /** * @author shuzijun @@ -50,47 +34,56 @@ public class LCVPreview extends UserDataHolderBase implements FileEditor { private final VirtualFile myFile; private final Document myDocument; - private final JPanel myHtmlPanelWrapper; - private final LCVPanel myPanel; + private BorderLayoutPanel myHtmlPanelWrapper; + private LCVPanel myPanel; - private final Url servicePath = BuiltInServerManager.getInstance().addAuthToken(Urls.parseEncoded("http://localhost:" + BuiltInServerManager.getInstance().getPort() + PreviewStaticServer.PREFIX)); - private final String templateHtmlFile = "template/default.html"; - private final boolean isPresentableUrl; + private boolean isPresentableUrl; public LCVPreview(@NotNull Project project, @NotNull VirtualFile file) { myProject = project; myFile = file; myDocument = FileDocumentManager.getInstance().getDocument(myFile); - myHtmlPanelWrapper = new JPanel(new BorderLayout()); - isPresentableUrl = project.getPresentableUrl() != null; - String url = UrlEscapers.urlFragmentEscaper().escape(URLUtil.FILE_PROTOCOL + URLUtil.SCHEME_SEPARATOR + FileUtils.separator() + myFile.getPath()); - LCVPanel tempPanel = null; - try { - tempPanel = new LCVPanel(url, project); - tempPanel.loadHTML(createHtml(isPresentableUrl), url); - myHtmlPanelWrapper.add(tempPanel.getComponent(), BorderLayout.CENTER); - } catch (Throwable e) { - myHtmlPanelWrapper.add(new JBLabel("Your environment does not support JCEF.
Check the Registry 'ide.browser.jcef.enabled'.
"+e.getMessage()+""), BorderLayout.CENTER); - } - myPanel = tempPanel; - myHtmlPanelWrapper.repaint(); MessageBusConnection settingsConnection = ApplicationManager.getApplication().getMessageBus().connect(this); - settingsConnection.subscribe(EditorColorsManager.TOPIC, new EditorColorsListener() { - @Override - public void globalSchemeChange(@Nullable EditorColorsScheme scheme) { - myPanel.updateStyle(getStyle(false)); + settingsConnection.subscribe(EditorColorsManager.TOPIC, scheme -> { + if (myPanel != null) { + myPanel.updateStyle(); } }); } @Override public @NotNull JComponent getComponent() { + if (myHtmlPanelWrapper == null) { + myHtmlPanelWrapper = JBUI.Panels.simplePanel(); + isPresentableUrl = myProject.getPresentableUrl() != null; + + JBLabel loadingLabel = new JBLabel("Loading......"); + myHtmlPanelWrapper.addToCenter(loadingLabel); + String url = UrlEscapers.urlFragmentEscaper().escape(URLUtil.FILE_PROTOCOL + URLUtil.SCHEME_SEPARATOR + FileUtils.separator() + myFile.getPath()); + LCVPanel tempPanel = null; + try { + try { + tempPanel = new LCVPanel(url, myProject, myDocument.getText()); + } catch (IllegalArgumentException e) { + tempPanel = new LCVPanel(url, myProject, myDocument.getText(), true); + } + myHtmlPanelWrapper.addToCenter(tempPanel.getComponent()); + + } catch (Throwable e) { + myHtmlPanelWrapper.addToCenter(new JBLabel("Your environment does not support JCEF.
Check the Registry 'ide.browser.jcef.enabled'.
" + e.getMessage() + "")); + } finally { + myPanel = tempPanel; + myHtmlPanelWrapper.remove(loadingLabel); + myHtmlPanelWrapper.repaint(); + } + } + return myHtmlPanelWrapper; } @Override public @Nullable JComponent getPreferredFocusedComponent() { - return myPanel != null ? myPanel.getComponent() : null; + return null; } @Override @@ -100,7 +93,6 @@ public void globalSchemeChange(@Nullable EditorColorsScheme scheme) { @Override public void setState(@NotNull FileEditorState state) { - } @Override @@ -135,83 +127,9 @@ public void dispose() { } } - private String createHtml(boolean isPresentableUrl) { - InputStream inputStream = null; - - try { - - inputStream = PreviewStaticServer.class.getResourceAsStream("/" + templateHtmlFile); - - String template = new String(FileUtilRt.loadBytes(inputStream)); - return template.replace("{{service}}", servicePath.getScheme() + URLUtil.SCHEME_SEPARATOR + servicePath.getAuthority() + servicePath.getPath()) - .replace("{{serverToken}}", StringUtils.isNotBlank(servicePath.getParameters()) ? servicePath.getParameters().substring(1) : "") - .replace("{{fileValue}}", FileDocumentManager.getInstance().getDocument(myFile).getText()) - .replace("{{Lang}}", PropertiesUtils.getInfo("Lang")) - .replace("{{darcula}}", UIUtil.isUnderDarcula() + "") - .replace("{{ideStyle}}", getStyle(true)) - ; - } catch (IOException e) { - throw new RuntimeException(e); - } finally { - if (inputStream != null) { - try { - inputStream.close(); - } catch (IOException ignore) { - } - } - } - } - @Override public @Nullable VirtualFile getFile() { return myFile; } - - private String getStyle(boolean isTag) { - try { - EditorColorsSchemeImpl editorColorsScheme = (EditorColorsSchemeImpl) EditorColorsManager.getInstance().getGlobalScheme(); - Color defaultBackground = editorColorsScheme.getDefaultBackground(); - - Color scrollbarThumbColor = EditorColors.SCROLLBAR_THUMB_COLOR.getDefaultColor(); - if (editorColorsScheme.getColor(EditorColors.SCROLLBAR_THUMB_COLOR) != null) { - scrollbarThumbColor = editorColorsScheme.getColor(EditorColors.SCROLLBAR_THUMB_COLOR); - } - TextAttributes textAttributes = editorColorsScheme.getDirectlyDefinedAttributes().get("TEXT"); - Color text = null; - if (textAttributes != null) { - text = textAttributes.getForegroundColor(); - } - String fontFamily = "font-family:\""+editorColorsScheme.getEditorFontName()+"\",\"Helvetica Neue\",\"Luxi Sans\",\"DejaVu Sans\"," + - "\"Hiragino Sans GB\",\"Microsoft Yahei\",sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Noto Color Emoji\",\"Segoe UI Symbol\"," + - "\"Android Emoji\",\"EmojiSymbols\";"; - StringBuilder sb = new StringBuilder(isTag ? "" : ""); - return sb.toString(); - } catch (Exception e) { - return ""; - } - - } - - private String toHexColor(Color color) { - DecimalFormat df = new DecimalFormat("0.00"); - DecimalFormatSymbols dfs = new DecimalFormatSymbols(); - dfs.setDecimalSeparator('.'); - df.setDecimalFormatSymbols(dfs); - return String.format("rgba(%s,%s,%s,%s)", color.getRed(), color.getGreen(), color.getBlue(), df.format(color.getAlpha() / (float) 255)); - } - } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/editor/QuestionEditorIconProvider.java b/src/main/java/com/shuzijun/leetcode/plugin/editor/QuestionEditorIconProvider.java new file mode 100644 index 00000000..bb39d869 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/editor/QuestionEditorIconProvider.java @@ -0,0 +1,47 @@ +package com.shuzijun.leetcode.plugin.editor; + +import com.intellij.ide.FileIconPatcher; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.shuzijun.leetcode.plugin.model.Config; +import com.shuzijun.leetcode.plugin.model.LeetcodeEditor; +import com.shuzijun.leetcode.plugin.setting.PersistentConfig; +import com.shuzijun.leetcode.plugin.setting.ProjectConfig; +import com.shuzijun.leetcode.plugin.utils.LogUtils; +import icons.LeetCodeEditorIcons; +import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.io.File; + +/** + * @author shuzijun + */ +public class QuestionEditorIconProvider implements FileIconPatcher { + + @Override + public Icon patchIcon(Icon baseIcon, VirtualFile file, int flags, @Nullable Project project) { + if (project == null) { + return baseIcon; + } + try { + Config config = PersistentConfig.getInstance().getInitConfig(); + if (config == null || !config.isQuestionEditor() || !config.isShowQuestionEditorSign()) { + return baseIcon; + } + LeetcodeEditor leetcodeEditor = ProjectConfig.getInstance(project).getEditor(file.getPath(), config.getUrl()); + if (leetcodeEditor == null || StringUtils.isBlank(leetcodeEditor.getContentPath())) { + return baseIcon; + } + File contentFile = new File(leetcodeEditor.getContentPath()); + if (!contentFile.exists()) { + return baseIcon; + } + } catch (Throwable e) { + LogUtils.LOG.error("QuestionEditorIconProvider -> patchIcon", e); + return baseIcon; + } + return LeetCodeEditorIcons.LEETCODE_TOOL_WINDOW; + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/editor/QuestionEditorProvider.java b/src/main/java/com/shuzijun/leetcode/plugin/editor/QuestionEditorProvider.java index fabf9817..8fd0c23a 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/editor/QuestionEditorProvider.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/editor/QuestionEditorProvider.java @@ -1,11 +1,15 @@ package com.shuzijun.leetcode.plugin.editor; import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.fileEditor.FileEditorProvider; import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.fileEditor.impl.text.PsiAwareTextEditorProvider; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.shuzijun.leetcode.plugin.editor.converge.ContentProvider; +import com.shuzijun.leetcode.plugin.editor.converge.NoteProvider; +import com.shuzijun.leetcode.plugin.editor.converge.SolutionProvider; +import com.shuzijun.leetcode.plugin.editor.converge.SubmissionsProvider; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.LeetcodeEditor; import com.shuzijun.leetcode.plugin.setting.PersistentConfig; @@ -22,14 +26,14 @@ public class QuestionEditorProvider extends SplitTextEditorProvider { public QuestionEditorProvider() { - super(new PsiAwareTextEditorProvider(), new ContentProvider()); + super(new PsiAwareTextEditorProvider(), new ConvergeProvider(new FileEditorProvider[]{new ContentProvider(), new SolutionProvider(), new SubmissionsProvider(), new NoteProvider()}, new String[]{"Content", "Solution", "Submissions", "Note"})); } @Override public boolean accept(@NotNull Project project, @NotNull VirtualFile file) { try { Config config = PersistentConfig.getInstance().getInitConfig(); - if (config == null || !config.getQuestionEditor()) { + if (config == null || !config.isQuestionEditor()) { return false; } LeetcodeEditor leetcodeEditor = ProjectConfig.getInstance(project).getEditor(file.getPath()); @@ -49,12 +53,9 @@ public boolean accept(@NotNull Project project, @NotNull VirtualFile file) { @Override public Builder createEditorAsync(@NotNull Project project, @NotNull VirtualFile file) { - LeetcodeEditor leetcodeEditor = ProjectConfig.getInstance(project).getEditor(file.getPath()); final Builder firstBuilder = getBuilderFromEditorProvider(this.myFirstProvider, project, file); - - VirtualFile contentVf = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(leetcodeEditor.getContentPath())); - final Builder secondBuilder = getBuilderFromEditorProvider(this.mySecondProvider, project, contentVf); + final Builder secondBuilder = getBuilderFromEditorProvider(this.mySecondProvider, project, file); return new Builder() { public FileEditor build() { return createSplitEditor(firstBuilder.build(), secondBuilder.build()); @@ -65,8 +66,14 @@ public FileEditor build() { @Override protected FileEditor createSplitEditor(@NotNull FileEditor firstEditor, @NotNull FileEditor secondEditor) { + if (PersistentConfig.getInstance().getInitConfig().isLeftQuestionEditor()) { + return new QuestionEditorWithPreview((TextEditor) secondEditor, firstEditor); + } else { + return new QuestionEditorWithPreview((TextEditor) firstEditor, secondEditor); + } + //if (firstEditor instanceof TextEditor && secondEditor instanceof MarkdownSplitEditor) { - return new QuestionEditorWithPreview((TextEditor) firstEditor, secondEditor); + //} else { // throw new IllegalArgumentException("Main editor should be TextEditor"); //} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/editor/QuestionEditorTabTitleProvider.java b/src/main/java/com/shuzijun/leetcode/plugin/editor/QuestionEditorTabTitleProvider.java new file mode 100644 index 00000000..5fc0d836 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/editor/QuestionEditorTabTitleProvider.java @@ -0,0 +1,45 @@ +package com.shuzijun.leetcode.plugin.editor; + +import com.intellij.openapi.fileEditor.impl.EditorTabTitleProvider; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.NlsContexts; +import com.intellij.openapi.vfs.VirtualFile; +import com.shuzijun.leetcode.plugin.manager.QuestionManager; +import com.shuzijun.leetcode.plugin.model.Config; +import com.shuzijun.leetcode.plugin.model.LeetcodeEditor; +import com.shuzijun.leetcode.plugin.model.Question; +import com.shuzijun.leetcode.plugin.setting.PersistentConfig; +import com.shuzijun.leetcode.plugin.setting.ProjectConfig; +import com.shuzijun.leetcode.plugin.utils.LogUtils; +import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author shuzijun + */ +public class QuestionEditorTabTitleProvider implements EditorTabTitleProvider { + @Override + public @NlsContexts.TabTitle @Nullable String getEditorTabTitle(@NotNull Project project, @NotNull VirtualFile file) { + try { + Config config = PersistentConfig.getInstance().getInitConfig(); + if (config == null || !config.isQuestionEditor() || !config.isShowQuestionEditorSign()) { + return null; + } + LeetcodeEditor leetcodeEditor = ProjectConfig.getInstance(project).getEditor(file.getPath(), config.getUrl()); + if (leetcodeEditor == null || StringUtils.isBlank(leetcodeEditor.getContentPath())) { + return null; + } else { + Question question = QuestionManager.getQuestionByTitleSlug(leetcodeEditor.getTitleSlug(), project); + if (question == null) { + return null; + } else { + return question.getFormTitle(); + } + } + } catch (Throwable e) { + LogUtils.LOG.error("QuestionEditorIconProvider -> patchIcon", e); + return null; + } + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/editor/QuestionEditorWithPreview.java b/src/main/java/com/shuzijun/leetcode/plugin/editor/QuestionEditorWithPreview.java index 359b4f10..64743a3d 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/editor/QuestionEditorWithPreview.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/editor/QuestionEditorWithPreview.java @@ -1,12 +1,17 @@ package com.shuzijun.leetcode.plugin.editor; +import com.intellij.codeHighlighting.BackgroundEditorHighlighter; +import com.intellij.ide.structureView.StructureViewBuilder; import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.fileEditor.FileEditorLocation; import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.fileEditor.TextEditorWithPreview; import com.intellij.openapi.util.Key; import com.shuzijun.leetcode.plugin.model.PluginConstant; +import com.shuzijun.leetcode.plugin.setting.PersistentConfig; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -17,13 +22,83 @@ public class QuestionEditorWithPreview extends TextEditorWithPreview { public static final Key PARENT_SPLIT_EDITOR_KEY = Key.create(PluginConstant.PLUGIN_ID + "Question Split"); public QuestionEditorWithPreview(@NotNull TextEditor editor, @NotNull FileEditor preview) { - super(editor, preview, "Question " + Layout.SHOW_EDITOR_AND_PREVIEW.getName(), Layout.SHOW_EDITOR_AND_PREVIEW); + super(editor, preview, "Question Editor", Layout.SHOW_EDITOR_AND_PREVIEW); editor.putUserData(PARENT_SPLIT_EDITOR_KEY, this); preview.putUserData(PARENT_SPLIT_EDITOR_KEY, this); } @Nullable protected ActionGroup createLeftToolbarActionGroup() { - return (ActionGroup) ActionManager.getInstance().getAction(PluginConstant.LEETCODE_EDITOR_GROUP); + if (!PersistentConfig.getInstance().getInitConfig().isLeftQuestionEditor()) { + return (ActionGroup) ActionManager.getInstance().getAction(PluginConstant.LEETCODE_EDITOR_GROUP); + } else { + return null; + } + + } + + @Nullable + protected ActionGroup createRightToolbarActionGroup() { + if (PersistentConfig.getInstance().getInitConfig().isLeftQuestionEditor()) { + return (ActionGroup) ActionManager.getInstance().getAction(PluginConstant.LEETCODE_EDITOR_GROUP); + } else { + return null; + } + } + + @NotNull + protected ActionGroup createViewActionGroup() { + if (PersistentConfig.getInstance().getInitConfig().isLeftQuestionEditor()) { + return new DefaultActionGroup( + getShowEditorAndPreviewAction(), + getShowPreviewAction() + ); + } else { + return new DefaultActionGroup( + getShowEditorAction(), + getShowEditorAndPreviewAction() + ); + } + + + } + + @Nullable + @Override + public BackgroundEditorHighlighter getBackgroundHighlighter() { + return getTextEditor().getBackgroundHighlighter(); + } + + @Nullable + @Override + public FileEditorLocation getCurrentLocation() { + return getTextEditor().getCurrentLocation(); + } + + @Nullable + @Override + public StructureViewBuilder getStructureViewBuilder() { + return getTextEditor().getStructureViewBuilder(); + } + + + @NotNull + public TextEditor getTextEditor() { + if (PersistentConfig.getInstance().getInitConfig().isLeftQuestionEditor()) { + if (((TextEditor) myPreview).getEditor() == null) { + return myEditor; + } + return (TextEditor) myPreview; + } else { + if ((myEditor).getEditor() == null) { + return (TextEditor) myPreview; + } + return myEditor; + } + + } + + public FileEditor getPreviewEditor() { + return myPreview == getTextEditor() ? myEditor : myPreview; } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/editor/ResourcesController.java b/src/main/java/com/shuzijun/leetcode/plugin/editor/ResourcesController.java index 27bb2e9c..4f32ec23 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/editor/ResourcesController.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/editor/ResourcesController.java @@ -41,7 +41,7 @@ public FullHttpResponse get(@NotNull QueryStringDecoder urlDecoder, @NotNull Ful FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(data)); response.headers().set(HttpHeaderNames.CONTENT_TYPE, FileResponses.INSTANCE.getContentType(resourceName) + "; charset=utf-8"); - response.headers().set(HttpHeaderNames.CACHE_CONTROL, "max-age=3600, private, must-revalidate"); + response.headers().set(HttpHeaderNames.CACHE_CONTROL, "max-age=3600, public"); response.headers().set(HttpHeaderNames.ETAG, Long.toString(LAST_MODIFIED)); return response; } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/ContentProvider.java b/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/ContentProvider.java new file mode 100644 index 00000000..9bc28eb3 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/ContentProvider.java @@ -0,0 +1,31 @@ +package com.shuzijun.leetcode.plugin.editor.converge; + +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.shuzijun.leetcode.plugin.editor.LCVProvider; +import com.shuzijun.leetcode.plugin.model.LeetcodeEditor; +import com.shuzijun.leetcode.plugin.setting.ProjectConfig; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * @author shuzijun + */ +public class ContentProvider extends LCVProvider { + + @Override + public boolean accept(@NotNull Project project, @NotNull VirtualFile file) { + return true; + } + + @Override + public @NotNull FileEditor createEditor(@NotNull Project project, @NotNull VirtualFile file) { + LeetcodeEditor leetcodeEditor = ProjectConfig.getInstance(project).getEditor(file.getPath()); + VirtualFile contentVf = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(leetcodeEditor.getContentPath())); + + return super.createEditor(project, contentVf); + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/NotePreview.java b/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/NotePreview.java new file mode 100644 index 00000000..cac6285e --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/NotePreview.java @@ -0,0 +1,186 @@ +package com.shuzijun.leetcode.plugin.editor.converge; + +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.ActionPlaces; +import com.intellij.openapi.actionSystem.ActionToolbar; +import com.intellij.openapi.actionSystem.DefaultActionGroup; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileEditor.*; +import com.intellij.openapi.fileEditor.ex.FileEditorProviderManager; +import com.intellij.openapi.fileEditor.impl.text.PsiAwareTextEditorProvider; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.UserDataHolderBase; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.newvfs.RefreshQueue; +import com.intellij.ui.components.JBLabel; +import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.components.BorderLayoutPanel; +import com.shuzijun.leetcode.plugin.editor.ConvergePreview; +import com.shuzijun.leetcode.plugin.manager.NoteManager; +import com.shuzijun.leetcode.plugin.model.LeetcodeEditor; +import com.shuzijun.leetcode.plugin.model.PluginConstant; +import com.shuzijun.leetcode.plugin.utils.URLUtils; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.beans.PropertyChangeListener; +import java.io.File; + +/** + * @author shuzijun + */ +public class NotePreview extends UserDataHolderBase implements FileEditor { + + + private final Project project; + private final LeetcodeEditor leetcodeEditor; + + + private BorderLayoutPanel myComponent; + private FileEditor fileEditor; + + private boolean isLoad = false; + + public NotePreview(Project project, LeetcodeEditor leetcodeEditor) { + this.project = project; + this.leetcodeEditor = leetcodeEditor; + } + + @Override + public @NotNull JComponent getComponent() { + if (myComponent == null) { + myComponent = JBUI.Panels.simplePanel(); + if (isLoad) { + initComponent(); + } + } + return myComponent; + } + + + private void initComponent() { + isLoad = true; + NotePreview notePreview = this; + ApplicationManager.getApplication().invokeLater(() -> { + JBLabel loadingLabel = new JBLabel("Loading......"); + myComponent.addToCenter(loadingLabel); + try { + File file = ApplicationManager.getApplication().executeOnPooledThread(() -> NoteManager.show(leetcodeEditor.getTitleSlug(), project, false)).get(); + if (file == null || !file.exists()) { + myComponent.addToCenter(new JBLabel("No note")); + } else { + VirtualFile vf = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); + FileEditorProvider[] editorProviders = FileEditorProviderManager.getInstance().getProviders(project, vf); + + if (editorProviders != null && editorProviders.length > 0) { + fileEditor = editorProviders[0].createEditor(project, vf); + Disposer.register(notePreview, fileEditor); + } else { + fileEditor = new PsiAwareTextEditorProvider().createEditor(project, vf); + Disposer.register(notePreview, fileEditor); + } + myComponent.addToCenter(fileEditor.getComponent()); + myComponent.addToTop(createToolbarWrapper(fileEditor.getComponent())); + + } + } catch (Exception e) { + myComponent.addToCenter(new JBLabel(e.getMessage())); + } finally { + myComponent.remove(loadingLabel); + } + }); + } + + + private SplitEditorToolbar createToolbarWrapper(JComponent targetComponentForActions) { + DefaultActionGroup actionGroup = (DefaultActionGroup) ActionManager.getInstance().getAction(PluginConstant.LEETCODE_EDITOR_NOTE); + ActionToolbar actionToolbar = ActionManager.getInstance().createActionToolbar("Note" + ActionPlaces.TOOLBAR, actionGroup, true); + actionToolbar.setTargetComponent(targetComponentForActions); + SplitEditorToolbar splitEditorToolbar = new SplitEditorToolbar(null, actionToolbar); + if (URLUtils.leetcodecn.equals(leetcodeEditor.getHost())) { + splitEditorToolbar.add(new JBLabel("网站已更换新笔记功能,此功能后续同步官网,请备份此版本下的笔记."), 0); + } + return splitEditorToolbar; + } + + @Override + public @Nullable JComponent getPreferredFocusedComponent() { + return null; + } + + @Override + public @Nls(capitalization = Nls.Capitalization.Title) @NotNull String getName() { + return PluginConstant.LEETCODE_EDITOR_TAB_VIEW + " Note"; + } + + @Override + public void setState(@NotNull FileEditorState state) { + if (state instanceof ConvergePreview.TabFileEditorState) { + if (!isLoad && ((ConvergePreview.TabFileEditorState) state).isLoad()) { + initComponent(); + } else { + if (fileEditor != null) { + RefreshQueue.getInstance().refresh(false, false, null, fileEditor.getFile()); + } + } + } else if (state instanceof ConvergePreview.LoginState) { + ConvergePreview.LoginState loginState = (ConvergePreview.LoginState) state; + if (isLoad && loginState.isLogin()) { + if (loginState.isSelect()) { + ApplicationManager.getApplication().invokeLater(() -> { + myComponent.removeAll(); + myComponent.updateUI(); + initComponent(); + }); + } else { + isLoad = false; + } + } + } + } + + @Override + public boolean isModified() { + return false; + } + + @Override + public boolean isValid() { + return false; + } + + @Override + public void addPropertyChangeListener(@NotNull PropertyChangeListener listener) { + + } + + @Override + public void removePropertyChangeListener(@NotNull PropertyChangeListener listener) { + + } + + @Override + public @Nullable FileEditorLocation getCurrentLocation() { + return null; + } + + @Override + public void dispose() { + if (fileEditor != null) { + Disposer.dispose(fileEditor); + } + } + + @Override + public @Nullable VirtualFile getFile() { + if (fileEditor != null) { + return fileEditor.getFile(); + } else { + return null; + } + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/NoteProvider.java b/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/NoteProvider.java new file mode 100644 index 00000000..b0c4dfc7 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/NoteProvider.java @@ -0,0 +1,57 @@ +package com.shuzijun.leetcode.plugin.editor.converge; + +import com.intellij.openapi.fileEditor.AsyncFileEditorProvider; +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.fileEditor.FileEditorPolicy; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.shuzijun.leetcode.plugin.model.LeetcodeEditor; +import com.shuzijun.leetcode.plugin.model.PluginConstant; +import com.shuzijun.leetcode.plugin.setting.ProjectConfig; +import org.jetbrains.annotations.NotNull; + +/** + * @author shuzijun + */ +public class NoteProvider implements AsyncFileEditorProvider, DumbAware { + + private FileEditor fileEditor; + + @Override + public @NotNull Builder createEditorAsync(@NotNull Project project, @NotNull VirtualFile file) { + LeetcodeEditor leetcodeEditor = ProjectConfig.getInstance(project).getEditor(file.getPath()); + + return new Builder() { + @Override + public FileEditor build() { + return createSplitEditor(leetcodeEditor, project); + } + }; + } + + protected FileEditor createSplitEditor(@NotNull LeetcodeEditor leetcodeEditor, Project project) { + return new NotePreview(project, leetcodeEditor); + } + + @Override + public boolean accept(@NotNull Project project, @NotNull VirtualFile file) { + return true; + } + + @Override + public @NotNull FileEditor createEditor(@NotNull Project project, @NotNull VirtualFile file) { + return createEditorAsync(project, file).build(); + } + + @Override + public @NotNull String getEditorTypeId() { + return PluginConstant.LEETCODE_EDITOR_TAB_VIEW + " Note view"; + } + + @Override + public @NotNull FileEditorPolicy getPolicy() { + return FileEditorPolicy.HIDE_DEFAULT_EDITOR; + } + +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/SolutionPreview.java b/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/SolutionPreview.java new file mode 100644 index 00000000..cfe47a50 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/SolutionPreview.java @@ -0,0 +1,351 @@ +package com.shuzijun.leetcode.plugin.editor.converge; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileEditor.*; +import com.intellij.openapi.fileEditor.ex.FileEditorProviderManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.UserDataHolderBase; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.JBSplitter; +import com.intellij.ui.components.JBLabel; +import com.intellij.ui.components.JBScrollPane; +import com.intellij.ui.table.JBTable; +import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.components.BorderLayoutPanel; +import com.shuzijun.leetcode.plugin.editor.ConvergePreview; +import com.shuzijun.leetcode.plugin.editor.SplitFileEditor; +import com.shuzijun.leetcode.plugin.manager.ArticleManager; +import com.shuzijun.leetcode.plugin.manager.QuestionManager; +import com.shuzijun.leetcode.plugin.model.*; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.table.AbstractTableModel; +import java.awt.*; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.util.List; + +import static com.intellij.openapi.actionSystem.ActionPlaces.TEXT_EDITOR_WITH_PREVIEW; + +/** + * @author shuzijun + */ +public class SolutionPreview extends UserDataHolderBase implements FileEditor { + + private static final String MY_PROPORTION_KEY = PluginConstant.PLUGIN_ID + "SolutionSplitEditor.Proportion"; + + + private final Project project; + private final LeetcodeEditor leetcodeEditor; + + + private BorderLayoutPanel myComponent; + private Question question; + private FileEditor fileEditor; + + private boolean isLoad = false; + + private List solutionList; + private JBTable table; + + private JBSplitter mySplitter; + private SplitFileEditor.SplitEditorLayout myLayout = SplitFileEditor.SplitEditorLayout.FIRST; + + public SolutionPreview(Project project, LeetcodeEditor leetcodeEditor) { + this.project = project; + this.leetcodeEditor = leetcodeEditor; + } + + @Override + public @NotNull JComponent getComponent() { + if (myComponent == null) { + mySplitter = new JBSplitter(false, 0.35f, 0.15f, 0.85f); + mySplitter.setSplitterProportionKey(MY_PROPORTION_KEY); + mySplitter.setDividerWidth(3); + myComponent = JBUI.Panels.simplePanel(); + myComponent.add(mySplitter, BorderLayout.CENTER); + if (isLoad) { + initComponent(null); + } + } + return myComponent; + } + + private void initComponent(String defaultSlug) { + isLoad = true; + ApplicationManager.getApplication().invokeLater(() -> { + JBLabel loadingLabel = new JBLabel("Loading......"); + mySplitter.setFirstComponent(loadingLabel); + try { + question = QuestionManager.getQuestionByTitleSlug(leetcodeEditor.getTitleSlug(), project); + + if (question == null || Constant.ARTICLE_LIVE_NONE.equals(question.getArticleLive())) { + mySplitter.setFirstComponent(new JBLabel("No question or no solution")); + } else if (Constant.ARTICLE_LIVE_ONE.equals(question.getArticleLive())) { + openArticle(); + myLayout = SplitFileEditor.SplitEditorLayout.SECOND; + adjustEditorsVisibility(); + } else if (Constant.ARTICLE_LIVE_LIST.equals(question.getArticleLive())) { + solutionList = ApplicationManager.getApplication().executeOnPooledThread(() -> ArticleManager.getSolutionList(question.getTitleSlug(), project)).get(); + if (CollectionUtils.isEmpty(solutionList)) { + mySplitter.setFirstComponent(new JBLabel("no solution")); + } else { + table = new JBTable(new TableModel(solutionList)); + table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + table.getTableHeader().setReorderingAllowed(false); + table.setRowSelectionAllowed(true); + table.setRowSelectionInterval(0, 0); + table.getColumnModel().getColumn(0).setPreferredWidth(350); + table.getColumnModel().getColumn(1).setPreferredWidth(200); + + table.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) { + int row = table.getSelectedRow(); + openSelectedQuestion(solutionList, row); + } + } + }); + table.addKeyListener(new KeyAdapter() { + @Override + public void keyTyped(KeyEvent e) { + if (e.getKeyChar() == KeyEvent.VK_ENTER) { + int row = table.getSelectedRow(); + openSelectedQuestion(solutionList, row); + } + + } + }); + JBScrollPane jbScrollPane = new JBScrollPane(table, JBScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JBScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + mySplitter.setFirstComponent(jbScrollPane); + if (StringUtils.isNotBlank(defaultSlug)) { + for (int i = 0; i < solutionList.size(); i++) { + if (solutionList.get(i).getSlug().equals(defaultSlug)) { + openSelectedQuestion(solutionList, i); + table.setRowSelectionInterval(i, i); + table.scrollRectToVisible(table.getCellRect(i, 0, true)); + } + } + } + } + } else { + mySplitter.setFirstComponent(new JBLabel("no solution")); + } + } catch (Exception e) { + myLayout = SplitFileEditor.SplitEditorLayout.FIRST; + adjustEditorsVisibility(); + mySplitter.setFirstComponent(new JBLabel(e.getMessage())); + } finally { + mySplitter.remove(loadingLabel); + } + }); + } + + private void openSelectedQuestion(List solutionList, int row) { + if (row < 0 || solutionList == null || row >= solutionList.size()) { + return; + } + Solution solution = solutionList.get(row); + question.setArticleSlug(solution.getSlug()); + try { + myLayout = SplitFileEditor.SplitEditorLayout.SPLIT; + adjustEditorsVisibility(); + openArticle(); + } catch (Exception e) { + } + } + + private void openArticle() throws InterruptedException, java.util.concurrent.ExecutionException { + File file = ApplicationManager.getApplication().executeOnPooledThread(() -> { + return ArticleManager.openArticle(question.getTitleSlug(), question.getArticleSlug(), project, false); + }).get(); + if (file == null || !file.exists()) { + mySplitter.setSecondComponent(new JBLabel("no solution")); + } else { + VirtualFile vf = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); + FileEditorProvider[] editorProviders = FileEditorProviderManager.getInstance().getProviders(project, vf); + FileEditor newEditor = editorProviders[0].createEditor(project, vf); + if (newEditor == fileEditor) { + return; + } + if (fileEditor != null) { + mySplitter.setSecondComponent(new JBLabel("Loading......")); + FileEditor temp = fileEditor; + Disposer.dispose(temp); + } + fileEditor = newEditor; + Disposer.register(this, fileEditor); + BorderLayoutPanel secondComponent = JBUI.Panels.simplePanel(fileEditor.getComponent()); + if (!Constant.ARTICLE_LIVE_ONE.equals(question.getArticleLive())) { + secondComponent.addToTop(createToolbarWrapper(fileEditor.getComponent())); + } + mySplitter.setSecondComponent(secondComponent); + } + } + + private SplitEditorToolbar createToolbarWrapper(JComponent targetComponentForActions) { + DefaultActionGroup actionGroup = new DefaultActionGroup(new AnAction("Close", "Close", AllIcons.Actions.Close) { + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + myLayout = SplitFileEditor.SplitEditorLayout.FIRST; + adjustEditorsVisibility(); + } + }); + ActionToolbar actionToolbar = ActionManager.getInstance().createActionToolbar("Solution" + TEXT_EDITOR_WITH_PREVIEW, actionGroup, true); + actionToolbar.setTargetComponent(targetComponentForActions); + return new SplitEditorToolbar(null, actionToolbar); + } + + private void adjustEditorsVisibility() { + if (mySplitter.getFirstComponent() != null) { + if (myLayout == SplitFileEditor.SplitEditorLayout.FIRST || myLayout == SplitFileEditor.SplitEditorLayout.SPLIT) { + mySplitter.getFirstComponent().setVisible(true); + } else { + mySplitter.getFirstComponent().setVisible(false); + } + } + + if (mySplitter.getSecondComponent() != null) { + if (myLayout == SplitFileEditor.SplitEditorLayout.SECOND || myLayout == SplitFileEditor.SplitEditorLayout.SPLIT) { + mySplitter.getSecondComponent().setVisible(true); + } else { + mySplitter.getSecondComponent().setVisible(false); + } + } + } + + @Override + public @Nullable JComponent getPreferredFocusedComponent() { + return myComponent; + } + + @Override + public @Nls(capitalization = Nls.Capitalization.Title) @NotNull String getName() { + return PluginConstant.LEETCODE_EDITOR_TAB_VIEW + " Solution"; + } + + @Override + public void setState(@NotNull FileEditorState state) { + if (state instanceof ConvergePreview.TabFileEditorState) { + if (!isLoad && ((ConvergePreview.TabFileEditorState) state).isLoad()) { + initComponent(null); + } else if (myLayout == SplitFileEditor.SplitEditorLayout.SECOND || myLayout == SplitFileEditor.SplitEditorLayout.SPLIT) { + try { + openArticle(); + } catch (Exception ignore) { + } + } + } else if (state instanceof ConvergePreview.TabSelectFileEditorState) { + String slug = ((ConvergePreview.TabSelectFileEditorState) state).getChildrenState(); + if (!isLoad) { + initComponent(slug); + } else if (CollectionUtils.isNotEmpty(solutionList)) { + for (int i = 0; i < solutionList.size(); i++) { + if (solutionList.get(i).getSlug().equals(slug)) { + openSelectedQuestion(solutionList, i); + table.setRowSelectionInterval(i, i); + break; + } + } + } + if (myLayout == SplitFileEditor.SplitEditorLayout.SECOND || myLayout == SplitFileEditor.SplitEditorLayout.SPLIT) { + try { + openArticle(); + } catch (Exception ignore) { + } + } + } + } + + @Override + public boolean isModified() { + return false; + } + + @Override + public boolean isValid() { + return false; + } + + @Override + public void addPropertyChangeListener(@NotNull PropertyChangeListener listener) { + + } + + @Override + public void removePropertyChangeListener(@NotNull PropertyChangeListener listener) { + + } + + @Override + public @Nullable FileEditorLocation getCurrentLocation() { + return null; + } + + @Override + public void dispose() { + if (fileEditor != null) { + Disposer.dispose(fileEditor); + } + } + + @Override + public @Nullable VirtualFile getFile() { + if (fileEditor != null) { + return fileEditor.getFile(); + } else { + return null; + } + } + + + private static class TableModel extends AbstractTableModel { + + String[] columnNames = {"Title", "Tags"}; + + String[][] data; + + public TableModel(List solutionList) { + data = new String[solutionList.size()][columnNames.length]; + for (int i = 0, j = solutionList.size(); i < j; i++) { + Solution s = solutionList.get(i); + data[i][0] = s.getTitle(); + data[i][1] = s.getTags(); + } + } + + @Override + public int getRowCount() { + return data.length; + } + + @Override + public int getColumnCount() { + return columnNames.length; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + return data[rowIndex][columnIndex]; + } + + @Override + public String getColumnName(int column) { + return columnNames[column]; + } + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/SolutionProvider.java b/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/SolutionProvider.java new file mode 100644 index 00000000..948ddfba --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/SolutionProvider.java @@ -0,0 +1,39 @@ +package com.shuzijun.leetcode.plugin.editor.converge; + +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.fileEditor.FileEditorPolicy; +import com.intellij.openapi.fileEditor.WeighedFileEditorProvider; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.shuzijun.leetcode.plugin.model.LeetcodeEditor; +import com.shuzijun.leetcode.plugin.model.PluginConstant; +import com.shuzijun.leetcode.plugin.setting.ProjectConfig; +import org.jetbrains.annotations.NotNull; + +/** + * @author shuzijun + */ +public class SolutionProvider extends WeighedFileEditorProvider { + + + @Override + public boolean accept(@NotNull Project project, @NotNull VirtualFile file) { + return true; + } + + @Override + public @NotNull FileEditor createEditor(@NotNull Project project, @NotNull VirtualFile file) { + LeetcodeEditor leetcodeEditor = ProjectConfig.getInstance(project).getEditor(file.getPath()); + return new SolutionPreview(project, leetcodeEditor); + } + + @Override + public @NotNull String getEditorTypeId() { + return PluginConstant.LEETCODE_EDITOR_TAB_VIEW + " Solution view"; + } + + @Override + public @NotNull FileEditorPolicy getPolicy() { + return FileEditorPolicy.HIDE_DEFAULT_EDITOR; + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/SubmissionsPreview.java b/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/SubmissionsPreview.java new file mode 100644 index 00000000..8e242cf0 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/SubmissionsPreview.java @@ -0,0 +1,319 @@ +package com.shuzijun.leetcode.plugin.editor.converge; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileEditor.*; +import com.intellij.openapi.fileEditor.ex.FileEditorProviderManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.UserDataHolderBase; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.JBSplitter; +import com.intellij.ui.components.JBLabel; +import com.intellij.ui.components.JBScrollPane; +import com.intellij.ui.table.JBTable; +import com.intellij.util.messages.MessageBusConnection; +import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.components.BorderLayoutPanel; +import com.shuzijun.leetcode.plugin.editor.ConvergePreview; +import com.shuzijun.leetcode.plugin.editor.SplitFileEditor; +import com.shuzijun.leetcode.plugin.listener.QuestionSubmitNotifier; +import com.shuzijun.leetcode.plugin.manager.QuestionManager; +import com.shuzijun.leetcode.plugin.manager.SubmissionManager; +import com.shuzijun.leetcode.plugin.model.LeetcodeEditor; +import com.shuzijun.leetcode.plugin.model.PluginConstant; +import com.shuzijun.leetcode.plugin.model.Question; +import com.shuzijun.leetcode.plugin.model.Submission; +import com.shuzijun.leetcode.plugin.window.dialog.SubmissionsPanel; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.util.List; + +import static com.intellij.openapi.actionSystem.ActionPlaces.TEXT_EDITOR_WITH_PREVIEW; + +/** + * @author shuzijun + */ +public class SubmissionsPreview extends UserDataHolderBase implements FileEditor { + + private static final String MY_PROPORTION_KEY = PluginConstant.PLUGIN_ID + "SubmissionsSplitEditor.Proportion"; + + private final Project project; + private final LeetcodeEditor leetcodeEditor; + + + private BorderLayoutPanel myComponent; + private Question question; + private FileEditor fileEditor; + + private boolean isLoad = false; + + private List submissionList; + private JBTable table; + + private JBSplitter mySplitter; + private SplitFileEditor.SplitEditorLayout myLayout = SplitFileEditor.SplitEditorLayout.FIRST; + + public SubmissionsPreview(Project project, LeetcodeEditor leetcodeEditor) { + this.project = project; + this.leetcodeEditor = leetcodeEditor; + MessageBusConnection settingsConnection = ApplicationManager.getApplication().getMessageBus().connect(this); + + settingsConnection.subscribe(QuestionSubmitNotifier.TOPIC, new QuestionSubmitNotifier() { + @Override + public void submit(String host, String slug) { + if (leetcodeEditor.getTitleSlug().equals(slug) && leetcodeEditor.getHost().equals(host)) { + if (isLoad) { + initComponent(null); + } + } + } + }); + } + + @Override + public @NotNull JComponent getComponent() { + if (myComponent == null) { + mySplitter = new JBSplitter(false, 0.35f, 0.15f, 0.85f); + mySplitter.setSplitterProportionKey(MY_PROPORTION_KEY); + mySplitter.setDividerWidth(3); + myComponent = JBUI.Panels.simplePanel(); + myComponent.add(mySplitter, BorderLayout.CENTER); + if (isLoad) { + initComponent(null); + } + } + return myComponent; + } + + private void initComponent(String defaultId) { + isLoad = true; + ApplicationManager.getApplication().invokeLater(() -> { + JBLabel loadingLabel = new JBLabel("Loading......"); + mySplitter.setFirstComponent(loadingLabel); + try { + question = QuestionManager.getQuestionByTitleSlug(leetcodeEditor.getTitleSlug(), project); + + if (question == null) { + mySplitter.setFirstComponent(new JBLabel("No question")); + } else { + submissionList = ApplicationManager.getApplication().executeOnPooledThread(() -> SubmissionManager.getSubmissionService(question.getTitleSlug(), project)).get(); + if (CollectionUtils.isNotEmpty(submissionList)) { + table = new JBTable(new SubmissionsPanel.TableModel(submissionList)); + table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + table.getTableHeader().setReorderingAllowed(false); + table.setRowSelectionAllowed(true); + table.setRowSelectionInterval(0, 0); + table.getColumnModel().getColumn(0).setPreferredWidth(150); + table.getColumnModel().getColumn(1).setPreferredWidth(100); + table.getColumnModel().getColumn(2).setPreferredWidth(50); + table.getColumnModel().getColumn(3).setPreferredWidth(100); + table.getColumnModel().getColumn(4).setPreferredWidth(50); + + table.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) { + int row = table.getSelectedRow(); + openSelectedQuestion(submissionList, row); + } + } + }); + table.addKeyListener(new KeyAdapter() { + @Override + public void keyTyped(KeyEvent e) { + if (e.getKeyChar() == KeyEvent.VK_ENTER) { + int row = table.getSelectedRow(); + openSelectedQuestion(submissionList, row); + } + + } + }); + JBScrollPane jbScrollPane = new JBScrollPane(table, JBScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JBScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + mySplitter.setFirstComponent(jbScrollPane); + + if (StringUtils.isNotBlank(defaultId)) { + for (int i = 0; i < submissionList.size(); i++) { + if (submissionList.get(i).getId().equals(defaultId)) { + openSelectedQuestion(submissionList, i); + table.setRowSelectionInterval(i, i); + table.scrollRectToVisible(table.getCellRect(i, 0, true)); + } + } + } + + } else { + mySplitter.setFirstComponent(new JBLabel("No login or no submissions")); + } + } + } catch (Exception e) { + mySplitter.setFirstComponent(new JBLabel(e.getMessage())); + } finally { + mySplitter.remove(loadingLabel); + } + }); + + } + + private void openSelectedQuestion(List submissionList, int row) { + if (row < 0 || submissionList == null || row >= submissionList.size()) { + return; + } + Submission submission = submissionList.get(row); + try { + openSubmission(submission); + } catch (Exception e) { + } + } + + private void openSubmission(Submission submission) throws InterruptedException, java.util.concurrent.ExecutionException { + File file = ApplicationManager.getApplication().executeOnPooledThread(() -> SubmissionManager.openSubmission(submission, question.getTitleSlug(), project, false)).get(); + if (file == null || !file.exists()) { + mySplitter.setSecondComponent(new JBLabel("no submission")); + } else { + VirtualFile vf = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); + FileEditorProvider[] editorProviders = FileEditorProviderManager.getInstance().getProviders(project, vf); + FileEditor newEditor = editorProviders[0].createEditor(project, vf); + if (newEditor == fileEditor) { + return; + } + if (fileEditor != null) { + mySplitter.setSecondComponent(new JBLabel("Loading......")); + FileEditor temp = fileEditor; + Disposer.dispose(temp); + } + fileEditor = newEditor; + Disposer.register(this, fileEditor); + BorderLayoutPanel secondComponent = JBUI.Panels.simplePanel(fileEditor.getComponent()); + secondComponent.addToTop(createToolbarWrapper(fileEditor.getComponent())); + mySplitter.setSecondComponent(secondComponent); + } + } + + private SplitEditorToolbar createToolbarWrapper(JComponent targetComponentForActions) { + DefaultActionGroup actionGroup = new DefaultActionGroup(new AnAction("Close", "Close", AllIcons.Actions.Close) { + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + myLayout = SplitFileEditor.SplitEditorLayout.FIRST; + adjustEditorsVisibility(); + } + }); + ActionToolbar actionToolbar = ActionManager.getInstance().createActionToolbar("Submissions" + TEXT_EDITOR_WITH_PREVIEW, actionGroup, true); + actionToolbar.setTargetComponent(targetComponentForActions); + return new SplitEditorToolbar(null, actionToolbar); + } + + private void adjustEditorsVisibility() { + if (mySplitter.getFirstComponent() != null) { + if (myLayout == SplitFileEditor.SplitEditorLayout.FIRST || myLayout == SplitFileEditor.SplitEditorLayout.SPLIT) { + mySplitter.getFirstComponent().setVisible(true); + } else { + mySplitter.getFirstComponent().setVisible(false); + } + } + + if (mySplitter.getSecondComponent() != null) { + if (myLayout == SplitFileEditor.SplitEditorLayout.SECOND || myLayout == SplitFileEditor.SplitEditorLayout.SPLIT) { + mySplitter.getSecondComponent().setVisible(true); + } else { + mySplitter.getSecondComponent().setVisible(false); + } + } + } + + @Override + public @Nullable JComponent getPreferredFocusedComponent() { + return myComponent; + } + + @Override + public @Nls(capitalization = Nls.Capitalization.Title) @NotNull String getName() { + return PluginConstant.LEETCODE_EDITOR_TAB_VIEW + " Solution"; + } + + @Override + public void setState(@NotNull FileEditorState state) { + if (state instanceof ConvergePreview.TabFileEditorState) { + if (!isLoad && ((ConvergePreview.TabFileEditorState) state).isLoad()) { + initComponent(null); + } + } else if (state instanceof ConvergePreview.TabSelectFileEditorState) { + String id = ((ConvergePreview.TabSelectFileEditorState) state).getChildrenState(); + if (!isLoad) { + initComponent(id); + } else if (CollectionUtils.isNotEmpty(submissionList)) { + for (int i = 0; i < submissionList.size(); i++) { + if (submissionList.get(i).getId().equals(id)) { + openSelectedQuestion(submissionList, i); + table.setRowSelectionInterval(i, i); + return; + } + } + } + } else if (state instanceof ConvergePreview.LoginState) { + ConvergePreview.LoginState loginState = (ConvergePreview.LoginState) state; + if (isLoad) { + if (loginState.isSelect()) { + initComponent(null); + } else { + isLoad = false; + } + } + } + } + + @Override + public boolean isModified() { + return false; + } + + @Override + public boolean isValid() { + return false; + } + + @Override + public void addPropertyChangeListener(@NotNull PropertyChangeListener listener) { + + } + + @Override + public void removePropertyChangeListener(@NotNull PropertyChangeListener listener) { + + } + + @Override + public @Nullable FileEditorLocation getCurrentLocation() { + return null; + } + + @Override + public void dispose() { + if (fileEditor != null) { + Disposer.dispose(fileEditor); + } + } + + @Override + public @Nullable VirtualFile getFile() { + if (fileEditor != null) { + return fileEditor.getFile(); + } else { + return null; + } + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/SubmissionsProvider.java b/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/SubmissionsProvider.java new file mode 100644 index 00000000..7902ab5b --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/editor/converge/SubmissionsProvider.java @@ -0,0 +1,39 @@ +package com.shuzijun.leetcode.plugin.editor.converge; + +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.fileEditor.FileEditorPolicy; +import com.intellij.openapi.fileEditor.WeighedFileEditorProvider; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.shuzijun.leetcode.plugin.model.LeetcodeEditor; +import com.shuzijun.leetcode.plugin.model.PluginConstant; +import com.shuzijun.leetcode.plugin.setting.ProjectConfig; +import org.jetbrains.annotations.NotNull; + +/** + * @author shuzijun + */ +public class SubmissionsProvider extends WeighedFileEditorProvider { + + + @Override + public boolean accept(@NotNull Project project, @NotNull VirtualFile file) { + return true; + } + + @Override + public @NotNull FileEditor createEditor(@NotNull Project project, @NotNull VirtualFile file) { + LeetcodeEditor leetcodeEditor = ProjectConfig.getInstance(project).getEditor(file.getPath()); + return new SubmissionsPreview(project, leetcodeEditor); + } + + @Override + public @NotNull String getEditorTypeId() { + return PluginConstant.LEETCODE_EDITOR_TAB_VIEW + " Submissions view"; + } + + @Override + public @NotNull FileEditorPolicy getPolicy() { + return FileEditorPolicy.HIDE_DEFAULT_EDITOR; + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/listener/AllQuestionNotifier.java b/src/main/java/com/shuzijun/leetcode/plugin/listener/AllQuestionNotifier.java new file mode 100644 index 00000000..c8505570 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/listener/AllQuestionNotifier.java @@ -0,0 +1,15 @@ +package com.shuzijun.leetcode.plugin.listener; + +import com.intellij.util.messages.Topic; +import com.shuzijun.leetcode.plugin.model.PluginConstant; + +/** + * @author shuzijun + */ +public interface AllQuestionNotifier { + + @Topic.AppLevel + Topic TOPIC = Topic.create(PluginConstant.LEETCODE_ALL_QUESTION_TOPIC, AllQuestionNotifier.class); + + void reset(); +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/listener/ConfigNotifier.java b/src/main/java/com/shuzijun/leetcode/plugin/listener/ConfigNotifier.java new file mode 100644 index 00000000..c762f7a4 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/listener/ConfigNotifier.java @@ -0,0 +1,16 @@ +package com.shuzijun.leetcode.plugin.listener; + +import com.intellij.util.messages.Topic; +import com.shuzijun.leetcode.plugin.model.Config; +import com.shuzijun.leetcode.plugin.model.PluginConstant; + +/** + * @author shuzijun + */ +public interface ConfigNotifier { + + @Topic.AppLevel + Topic TOPIC = Topic.create(PluginConstant.LEETCODE_EDITOR_CONFIG_TOPIC, ConfigNotifier.class); + + void change(Config oldConfig, Config newConfig); +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/listener/HtmlListener.java b/src/main/java/com/shuzijun/leetcode/plugin/listener/HtmlListener.java deleted file mode 100644 index 25dfd8e4..00000000 --- a/src/main/java/com/shuzijun/leetcode/plugin/listener/HtmlListener.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.shuzijun.leetcode.plugin.listener; - -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.fileEditor.OpenFileDescriptor; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.MessageType; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.wm.ToolWindow; -import com.shuzijun.leetcode.plugin.manager.ExploreManager; -import com.shuzijun.leetcode.plugin.model.Constant; -import com.shuzijun.leetcode.plugin.model.Question; -import com.shuzijun.leetcode.plugin.setting.PersistentConfig; -import com.shuzijun.leetcode.plugin.utils.FileUtils; -import com.shuzijun.leetcode.plugin.utils.MessageUtils; -import com.shuzijun.leetcode.plugin.utils.PropertiesUtils; -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.swing.tree.DefaultMutableTreeNode; -import java.io.File; - -/** - * @author shuzijun - */ -public class HtmlListener implements Runnable { - - private final static Logger logger = LoggerFactory.getLogger(HtmlListener.class); - - private DefaultMutableTreeNode node; - - private ToolWindow toolWindow; - - private Project project; - - public HtmlListener(DefaultMutableTreeNode node, ToolWindow toolWindow, Project project) { - this.node = node; - this.toolWindow = toolWindow; - this.project = project; - } - - @Override - public void run() { - - Question question = (Question) node.getUserObject(); - - if (Constant.NODETYPE_ITEM.equals(question.getNodeType())) { - ExploreManager.getItem(question); - if (Constant.NODETYPE_ITEM.equals(question.getNodeType())) { - MessageUtils.showMsg(toolWindow.getContentManager().getComponent(), MessageType.INFO, "info", PropertiesUtils.getInfo("request.failed")); - return; - } else { - question.setNodeType(Constant.NODETYPE_DEF); - node.setUserObject(question); - } - } - - String filePath = PersistentConfig.getInstance().getTempFilePath() + question.getFormTitle() + ".md"; - - File file = new File(filePath); - if (file.exists()) { - VirtualFile vf = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); - OpenFileDescriptor descriptor = new OpenFileDescriptor(project, vf); - FileEditorManager.getInstance(project).openTextEditor(descriptor, false); - } else { - String body = null; - if(Constant.ITEM_TYPE_HTML.equals(question.getLangSlug())){ - body = ExploreManager.GetHtmlArticle(question); - }else if(Constant.ITEM_TYPE_ARTICLE.equals(question.getLangSlug())){ - body = ExploreManager.GetArticle(question); - } - if(StringUtils.isBlank(body)){ - MessageUtils.showMsg(toolWindow.getContentManager().getComponent(), MessageType.INFO, "info", PropertiesUtils.getInfo("request.failed")); - return; - } - - FileUtils.saveFile(file, body); - VirtualFile vf = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); - OpenFileDescriptor descriptor = new OpenFileDescriptor(project, vf); - FileEditorManager.getInstance(project).openTextEditor(descriptor, false); - } - } -} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/listener/JTableKeyAdapter.java b/src/main/java/com/shuzijun/leetcode/plugin/listener/JTableKeyAdapter.java index f83ca4ea..26d541f1 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/listener/JTableKeyAdapter.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/listener/JTableKeyAdapter.java @@ -6,8 +6,8 @@ import com.intellij.openapi.project.Project; import com.shuzijun.leetcode.plugin.manager.CodeManager; import com.shuzijun.leetcode.plugin.model.PluginConstant; -import com.shuzijun.leetcode.plugin.model.Question; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; +import com.shuzijun.leetcode.plugin.model.QuestionView; +import com.shuzijun.leetcode.plugin.window.NavigatorTableData; import org.jetbrains.annotations.NotNull; import java.awt.event.KeyAdapter; @@ -18,23 +18,23 @@ */ public class JTableKeyAdapter extends KeyAdapter { - private NavigatorTable navigatorTable; + private NavigatorTableData navigatorTable; private Project project; - public JTableKeyAdapter(NavigatorTable navigatorTable, Project project) { + public JTableKeyAdapter(NavigatorTableData navigatorTable, Project project) { this.navigatorTable = navigatorTable; this.project = project; } @Override public void keyTyped(KeyEvent e) { - Question question = navigatorTable.getSelectedRowData(); + QuestionView question = navigatorTable.getSelectedRowData(); if (question != null) { if (e.getKeyChar() == KeyEvent.VK_ENTER) { ProgressManager.getInstance().run(new Task.Backgroundable(project, PluginConstant.LEETCODE_EDITOR_OPEN_CODE, false) { @Override public void run(@NotNull ProgressIndicator progressIndicator) { - CodeManager.openCode(question, project); + CodeManager.openCode(question.getTitleSlug(), project); } }); } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/listener/LoginNotifier.java b/src/main/java/com/shuzijun/leetcode/plugin/listener/LoginNotifier.java new file mode 100644 index 00000000..9b42ee76 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/listener/LoginNotifier.java @@ -0,0 +1,18 @@ +package com.shuzijun.leetcode.plugin.listener; + +import com.intellij.openapi.project.Project; +import com.intellij.util.messages.Topic; +import com.shuzijun.leetcode.plugin.model.PluginConstant; + +/** + * @author shuzijun + */ +public interface LoginNotifier { + + @Topic.AppLevel + Topic TOPIC = Topic.create(PluginConstant.LEETCODE_EDITOR_LOGIN_TOPIC, LoginNotifier.class); + + void login(Project project, String host); + + void logout(Project project, String host); +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/listener/QueryKeyListener.java b/src/main/java/com/shuzijun/leetcode/plugin/listener/QueryKeyListener.java index e86ac546..cf2a14cd 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/listener/QueryKeyListener.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/listener/QueryKeyListener.java @@ -4,8 +4,7 @@ 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.window.NavigatorTable; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; @@ -23,12 +22,12 @@ public class QueryKeyListener implements KeyListener { private final static Logger logger = LoggerFactory.getLogger(QueryKeyListener.class); private JTextField jTextField; - private NavigatorTable navigatorTable; + private NavigatorAction navigatorAction; private Project project; - public QueryKeyListener(JTextField jTextField, NavigatorTable navigatorTable, Project project) { + public QueryKeyListener(JTextField jTextField, NavigatorAction navigatorAction, Project project) { this.jTextField = jTextField; - this.navigatorTable = navigatorTable; + this.navigatorAction = navigatorAction; this.project = project; } @@ -44,9 +43,9 @@ public void keyPressed(KeyEvent e) { @Override public void run(@NotNull ProgressIndicator progressIndicator) { String selectText = jTextField.getText(); - navigatorTable.getPageInfo().disposeFilters("searchKeywords", selectText, StringUtils.isNotBlank(selectText)); - navigatorTable.getPageInfo().setPageIndex(1); - ViewManager.loadServiceData(navigatorTable, project); + navigatorAction.getPageInfo().disposeFilters("searchKeywords", selectText, StringUtils.isNotBlank(selectText)); + navigatorAction.getPageInfo().setPageIndex(1); + navigatorAction.loadServiceData(); } }); } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/listener/QuestionStatusListener.java b/src/main/java/com/shuzijun/leetcode/plugin/listener/QuestionStatusListener.java deleted file mode 100644 index 34380ded..00000000 --- a/src/main/java/com/shuzijun/leetcode/plugin/listener/QuestionStatusListener.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.shuzijun.leetcode.plugin.listener; - -import com.intellij.util.messages.Topic; -import com.shuzijun.leetcode.plugin.model.Question; - -/** - * @author shuzijun - */ -public interface QuestionStatusListener { - - @Topic.ProjectLevel - Topic QUESTION_STATUS_TOPIC = Topic.create("Question Status", QuestionStatusListener.class); - - public void updateTable(Question question); - - -} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/listener/QuestionStatusNotifier.java b/src/main/java/com/shuzijun/leetcode/plugin/listener/QuestionStatusNotifier.java new file mode 100644 index 00000000..c43a4609 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/listener/QuestionStatusNotifier.java @@ -0,0 +1,18 @@ +package com.shuzijun.leetcode.plugin.listener; + +import com.intellij.util.messages.Topic; +import com.shuzijun.leetcode.plugin.model.PluginConstant; +import com.shuzijun.leetcode.plugin.model.Question; + +/** + * @author shuzijun + */ +public interface QuestionStatusNotifier { + + @Topic.AppLevel + Topic QUESTION_STATUS_TOPIC = Topic.create(PluginConstant.LEETCODE_EDITOR_QUESTION_STATUS_TOPIC, QuestionStatusNotifier.class); + + public void updateTable(Question question); + + +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/listener/QuestionSubmitNotifier.java b/src/main/java/com/shuzijun/leetcode/plugin/listener/QuestionSubmitNotifier.java new file mode 100644 index 00000000..bad576cb --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/listener/QuestionSubmitNotifier.java @@ -0,0 +1,15 @@ +package com.shuzijun.leetcode.plugin.listener; + +import com.intellij.util.messages.Topic; +import com.shuzijun.leetcode.plugin.model.PluginConstant; + +/** + * @author shuzijun + */ +public interface QuestionSubmitNotifier { + + @Topic.AppLevel + Topic TOPIC = Topic.create(PluginConstant.LEETCODE_EDITOR_QUESTION_SUBMIT_TOPIC, QuestionSubmitNotifier.class); + + void submit(String host, String slug); +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/listener/TreeMouseListener.java b/src/main/java/com/shuzijun/leetcode/plugin/listener/TreeMouseListener.java index 5a044203..4b65d755 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/listener/TreeMouseListener.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/listener/TreeMouseListener.java @@ -8,8 +8,8 @@ import com.intellij.openapi.project.Project; import com.shuzijun.leetcode.plugin.manager.CodeManager; import com.shuzijun.leetcode.plugin.model.PluginConstant; -import com.shuzijun.leetcode.plugin.model.Question; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; +import com.shuzijun.leetcode.plugin.model.QuestionView; +import com.shuzijun.leetcode.plugin.window.NavigatorTableData; import org.jetbrains.annotations.NotNull; import java.awt.event.MouseAdapter; @@ -21,10 +21,10 @@ public class TreeMouseListener extends MouseAdapter { - private NavigatorTable navigatorTable; + private NavigatorTableData navigatorTable; private Project project; - public TreeMouseListener(NavigatorTable navigatorTable, Project project) { + public TreeMouseListener(NavigatorTableData navigatorTable, Project project) { this.navigatorTable = navigatorTable; this.project = project; } @@ -32,27 +32,27 @@ public TreeMouseListener(NavigatorTable navigatorTable, Project project) { @Override public void mouseClicked(MouseEvent e) { - Question question = navigatorTable.getSelectedRowData(); + QuestionView question = navigatorTable.getSelectedRowData(); if (question != null) { if ("lock".equals(question.getStatus())) { return; } - if (question.isLeaf()) { - if (e.getButton() == MouseEvent.BUTTON3) { //鼠标右键 - final ActionManager actionManager = ActionManager.getInstance(); - final ActionGroup actionGroup = (ActionGroup) actionManager.getAction(PluginConstant.LEETCODE_NAVIGATOR_ACTIONS_MENU); - if (actionGroup != null) { - actionManager.createActionPopupMenu("", actionGroup).getComponent().show(e.getComponent(), e.getX(), e.getY()); - } - } else if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) { - ProgressManager.getInstance().run(new Task.Backgroundable(project, PluginConstant.LEETCODE_EDITOR_OPEN_CODE, false) { - @Override - public void run(@NotNull ProgressIndicator progressIndicator) { - CodeManager.openCode(question, project); - } - }); + + if (e.getButton() == MouseEvent.BUTTON3) { //鼠标右键 + final ActionManager actionManager = ActionManager.getInstance(); + final ActionGroup actionGroup = (ActionGroup) actionManager.getAction(PluginConstant.LEETCODE_NAVIGATOR_ACTIONS_MENU); + if (actionGroup != null) { + actionManager.createActionPopupMenu(PluginConstant.ACTION_PREFIX + " TableMenu", actionGroup).getComponent().show(e.getComponent(), e.getX(), e.getY()); } + } else if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) { + ProgressManager.getInstance().run(new Task.Backgroundable(project, PluginConstant.LEETCODE_EDITOR_OPEN_CODE, false) { + @Override + public void run(@NotNull ProgressIndicator progressIndicator) { + CodeManager.openCode(question.getTitleSlug(), project); + } + }); } + } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/listener/TreeWillListener.java b/src/main/java/com/shuzijun/leetcode/plugin/listener/TreeWillListener.java deleted file mode 100644 index 7afee187..00000000 --- a/src/main/java/com/shuzijun/leetcode/plugin/listener/TreeWillListener.java +++ /dev/null @@ -1,139 +0,0 @@ -package com.shuzijun.leetcode.plugin.listener; - - -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.MessageType; -import com.intellij.openapi.wm.ToolWindow; -import com.shuzijun.leetcode.plugin.manager.ExploreManager; -import com.shuzijun.leetcode.plugin.model.Constant; -import com.shuzijun.leetcode.plugin.model.PluginConstant; -import com.shuzijun.leetcode.plugin.model.Question; -import com.shuzijun.leetcode.plugin.utils.MessageUtils; -import com.shuzijun.leetcode.plugin.utils.PropertiesUtils; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import javax.swing.event.TreeExpansionEvent; -import javax.swing.event.TreeWillExpandListener; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.ExpandVetoException; -import javax.swing.tree.TreePath; -import java.util.List; - -/** - * @author shuzijun - */ -public class TreeWillListener implements TreeWillExpandListener { - - - private JTree tree; - private ToolWindow toolWindow; - private Project project; - - public TreeWillListener(JTree tree, ToolWindow toolWindow, Project project) { - this.tree = tree; - this.toolWindow = toolWindow; - this.project = project; - } - - @Override - public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException { - - TreePath selPath = event.getPath(); - DefaultMutableTreeNode node = (DefaultMutableTreeNode) selPath.getLastPathComponent(); - Question question = (Question) node.getUserObject(); - if (!isOneOpen(node)) { - return; - } else if ("lock".equals(question.getStatus())) { - MessageUtils.showMsg(toolWindow.getContentManager().getComponent(), MessageType.INFO, "info", "no permissions"); - throw new ExpandVetoException(event); - } - ProgressManager.getInstance().run(new Task.Backgroundable(project, PluginConstant.LEETCODE_EDITOR_TREE,false) { - @Override - public void run(@NotNull ProgressIndicator progressIndicator) { - //loadData(question,node,selPath,tree,toolWindow); - MessageUtils.showMsg(toolWindow.getContentManager().getComponent(), MessageType.INFO, "info", "Temporarily disabled"); - } - }); - throw new ExpandVetoException(event); - } - - private void loadData( Question question,DefaultMutableTreeNode node,TreePath selPath ,JTree tree,ToolWindow toolWindow){ - - if (Constant.NODETYPE_EXPLORE.equals(question.getNodeType())) { - List category = ExploreManager.getCategory(); - if (category.isEmpty()) { - MessageUtils.showMsg(toolWindow.getContentManager().getComponent(), MessageType.ERROR, "info", PropertiesUtils.getInfo("response.type.failed", "category")); - return; - } - node.removeAllChildren(); - for (Question q : category) { - DefaultMutableTreeNode categoriesNode = new DefaultMutableTreeNode(q); - node.add(addLoad(categoriesNode)); - } - }else if (Constant.NODETYPE_CATEGORY.equals(question.getNodeType())) { - List cartList = ExploreManager.getCards(question); - if (cartList.isEmpty()) { - MessageUtils.showMsg(toolWindow.getContentManager().getComponent(), MessageType.ERROR, "info", PropertiesUtils.getInfo("response.type.failed", "cards")); - return; - } - node.removeAllChildren(); - for (Question cart : cartList) { - node.add(addLoad(new DefaultMutableTreeNode(cart))); - } - } else if (Constant.NODETYPE_CARD.equals(question.getNodeType())) { - List chapters = ExploreManager.getChapters(question); - if (chapters.isEmpty()) { - MessageUtils.showMsg(toolWindow.getContentManager().getComponent(), MessageType.ERROR, "info", PropertiesUtils.getInfo("response.type.failed", "chapter")); - return; - } - node.removeAllChildren(); - - for (Question chapter : chapters) { - node.add(addLoad(new DefaultMutableTreeNode(chapter))); - } - } else if (Constant.NODETYPE_CHAPTER.equals(question.getNodeType())) { - List chapters = ExploreManager.getChapterItem(question); - if (chapters.isEmpty()) { - MessageUtils.showMsg(toolWindow.getContentManager().getComponent(), MessageType.ERROR, "info", PropertiesUtils.getInfo("response.type.failed", "Question")); - return; - } - node.removeAllChildren(); - for (Question chapter : chapters) { - node.add(new DefaultMutableTreeNode(chapter)); - } - }else { - return; - } - - tree.expandPath(selPath); - - } - - @Override - public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException { - - } - - private boolean isOneOpen(DefaultMutableTreeNode node) { - if (node.getChildCount() == 1) { - Question question = (Question) ((DefaultMutableTreeNode) node.getChildAt(0)).getUserObject(); - if (Constant.NODETYPE_LOAD.equals(question.getNodeType())) { - return Boolean.TRUE; - } - } - return Boolean.FALSE; - } - - private DefaultMutableTreeNode addLoad(DefaultMutableTreeNode node) { - Question question = (Question) node.getUserObject(); - if ("lock".equals(question.getStatus())) { - return node; - } - node.add(new DefaultMutableTreeNode(new Question(Constant.NODETYPE_LOAD, Constant.NODETYPE_LOAD))); - return node; - } -} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/manager/ArticleManager.java b/src/main/java/com/shuzijun/leetcode/plugin/manager/ArticleManager.java index 4da44f17..c36dccad 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/manager/ArticleManager.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/manager/ArticleManager.java @@ -4,8 +4,8 @@ import com.alibaba.fastjson.JSONObject; import com.intellij.openapi.project.Project; import com.shuzijun.leetcode.plugin.model.Constant; +import com.shuzijun.leetcode.plugin.model.Graphql; import com.shuzijun.leetcode.plugin.model.PluginConstant; -import com.shuzijun.leetcode.plugin.model.Question; import com.shuzijun.leetcode.plugin.model.Solution; import com.shuzijun.leetcode.plugin.setting.PersistentConfig; import com.shuzijun.leetcode.plugin.utils.*; @@ -21,71 +21,42 @@ */ public class ArticleManager { - public static void openArticle(Question question, Project project) { - - String filePath = PersistentConfig.getInstance().getTempFilePath() + Constant.DOC_SOLUTION + question.getArticleSlug() + "." + PluginConstant.LEETCODE_EDITOR_VIEW; + public static File openArticle(String titleSlug, String articleSlug, Project project, Boolean isOpenEditor) { + String filePath = PersistentConfig.getInstance().getTempFilePath() + Constant.DOC_SOLUTION + articleSlug + "." + PluginConstant.LEETCODE_EDITOR_VIEW; File file = new File(filePath); - String host = ""; + String host; if (!file.exists()) { - String article; + String article = getArticle(titleSlug, articleSlug, project); if (URLUtils.isCn()) { - article = getCnArticle(question, project); - host = URLUtils.getLeetcodeProblems() + question.getTitleSlug() + "/solution/" + question.getArticleSlug() + "/"; + host = URLUtils.getLeetcodeProblems() + titleSlug + "/solution/" + articleSlug + "/"; } else { - article = getEnArticle(question, project); - host = URLUtils.getLeetcodeProblems() + question.getTitleSlug() + "/solution/"; + host = URLUtils.getLeetcodeProblems() + titleSlug + "/solution/"; } if (StringUtils.isBlank(article)) { - return; + return file; } - article = formatMarkdown(article, project, host); + article = formatMarkdown(article, host); FileUtils.saveFile(file, article); } - FileUtils.openFileEditor(file, project); + if (isOpenEditor) { + FileUtils.openFileEditor(file, project); + } + return file; } - private static String getEnArticle(Question question, Project project) { + private static String getArticle(String titleSlug, String articleSlug, Project project) { try { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(), "application/json"); - httpRequest.setBody("{\"operationName\":\"QuestionNote\",\"variables\":{\"titleSlug\":\"" + question.getTitleSlug() + "\"},\"query\":\"query QuestionNote($titleSlug: String!) " + - "{\\n question(titleSlug: $titleSlug) {\\n questionId\\n article\\n solution {\\n id\\n content\\n contentTypeId\\n canSeeDetail\\n " + - " paidOnly\\n hasVideoSolution\\n paidOnlyVideo\\n rating {\\n id\\n count\\n average\\n userRating {\\n score\\n " + - " __typename\\n }\\n __typename\\n }\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}"); - httpRequest.addHeader("Accept", "application/json"); - HttpResponse response = HttpRequestUtils.executePost(httpRequest); + HttpResponse response = Graphql.builder().cn(URLUtils.isCn()).operationName("solutionDetailArticle"). + variables("slug", articleSlug).variables("titleSlug", titleSlug).variables("orderBy", "DEFAULT").request(); if (response.getStatusCode() == 200) { - String content = JSONObject.parseObject(response.getBody()).getJSONObject("data").getJSONObject("question").getJSONObject("solution").getString("content"); - if (StringUtils.isBlank(content)) { - MessageUtils.getInstance(project).showWarnMsg("error", PropertiesUtils.getInfo("request.auth")); - return null; + String content; + if (URLUtils.isCn()) { + content = JSONObject.parseObject(response.getBody()).getJSONObject("data").getJSONObject("solutionArticle").getString("content"); } else { - return content; + content = JSONObject.parseObject(response.getBody()).getJSONObject("data").getJSONObject("solutionArticle").getJSONObject("solution").getString("content"); } - } - } catch (Exception e) { - LogUtils.LOG.error("article acquisition failed", e); - MessageUtils.getInstance(project).showWarnMsg("error", PropertiesUtils.getInfo("response.code")); - } - return null; - } - - - private static String getCnArticle(Question question, Project project) { - try { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(), "application/json"); - httpRequest.setBody("{\"operationName\":\"solutionDetailArticle\",\"variables\":{\"slug\":\"" + question.getArticleSlug() + "\",\"orderBy\":\"DEFAULT\"}," + - "\"query\":\"query solutionDetailArticle($slug: String!, $orderBy: SolutionArticleOrderBy!) {\\n solutionArticle(slug: $slug, orderBy: $orderBy) " + - "{\\n ...solutionArticle\\n content\\n question {\\n questionTitleSlug\\n __typename\\n }\\n position\\n next {\\n slug\\n " + - " title\\n __typename\\n }\\n prev {\\n slug\\n title\\n __typename\\n }\\n __typename\\n }\\n}\\n\\nfragment solutionArticle on SolutionArticleNode " + - "{\\n uuid\\n title\\n slug\\n chargeType\\n status\\n identifier\\n canEdit\\n reactionType\\n reactionsV2 {\\n count\\n reactionType\\n __typename\\n }\\n tags {\\n " + - " name\\n nameTranslated\\n slug\\n __typename\\n }\\n createdAt\\n thumbnail\\n author {\\n username\\n profile {\\n userAvatar\\n userSlug\\n realName\\n " + - " __typename\\n }\\n __typename\\n }\\n summary\\n topic {\\n id\\n commentCount\\n viewCount\\n __typename\\n }\\n byLeetcode\\n isMyFavorite\\n isMostPopular\\n " + - " isEditorsPick\\n hitCount\\n videosInfo {\\n videoId\\n coverUrl\\n duration\\n __typename\\n }\\n __typename\\n}\\n\"}"); - HttpResponse response = HttpRequestUtils.executePost(httpRequest); - if (response.getStatusCode() == 200) { - String content = JSONObject.parseObject(response.getBody()).getJSONObject("data").getJSONObject("solutionArticle").getString("content"); if (StringUtils.isBlank(content)) { MessageUtils.getInstance(project).showWarnMsg("error", PropertiesUtils.getInfo("request.auth")); return null; @@ -103,23 +74,16 @@ private static String getCnArticle(Question question, Project project) { } - public static String formatMarkdown(String content, Project project, String host) { + public static String formatMarkdown(String content, String host) { return CleanMarkdown.cleanMarkdown(content, host); } - public static List getSolutionList(Question question, Project project) { + public static List getSolutionList(String titleSlug, Project project) { List solutionList = new ArrayList<>(); try { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(), "application/json"); - httpRequest.setBody("{\"operationName\":\"questionSolutionArticles\",\"variables\":{\"questionSlug\":\"" + question.getTitleSlug() + "\",\"first\":10,\"skip\":0,\"orderBy\":\"DEFAULT\"},\"query\":\"query " + - "questionSolutionArticles($questionSlug: String!, $skip: Int, $first: Int, $orderBy: SolutionArticleOrderBy, $userInput: String, $tagSlugs: [String!]) {\\n questionSolutionArticles(questionSlug: $questionSlug, " + - "skip: $skip, first: $first, orderBy: $orderBy, userInput: $userInput, tagSlugs: $tagSlugs) {\\n totalNum\\n edges {\\n node {\\n ...solutionArticle\\n __typename\\n }\\n __typename\\n }\\n " + - " __typename\\n }\\n}\\n\\nfragment solutionArticle on SolutionArticleNode {\\n uuid\\n title\\n slug\\n chargeType\\n status\\n identifier\\n canEdit\\n reactionType\\n reactionsV2 {\\n count\\n reactionType\\n " + - "__typename\\n }\\n tags {\\n name\\n nameTranslated\\n slug\\n __typename\\n }\\n createdAt\\n thumbnail\\n author {\\n username\\n profile {\\n userAvatar\\n userSlug\\n realName\\n __typename\\n }\\n " + - " __typename\\n }\\n summary\\n topic {\\n id\\n commentCount\\n viewCount\\n __typename\\n }\\n byLeetcode\\n isMyFavorite\\n isMostPopular\\n isEditorsPick\\n hitCount\\n videosInfo {\\n videoId\\n coverUrl\\n duration\\n __typename\\n }\\n __typename\\n}\\n\"}"); - httpRequest.addHeader("Accept", "application/json"); - HttpResponse response = HttpRequestUtils.executePost(httpRequest); + HttpResponse response = Graphql.builder().cn(URLUtils.isCn()).operationName("questionSolutionArticles"). + variables("questionSlug", titleSlug).variables("first", 200).variables("skip", 0).variables("orderBy", "DEFAULT").request(); if (response.getStatusCode() == 200) { JSONArray edges = JSONObject.parseObject(response.getBody()).getJSONObject("data").getJSONObject("questionSolutionArticles").getJSONArray("edges"); for (int i = 0; i < edges.size(); i++) { diff --git a/src/main/java/com/shuzijun/leetcode/plugin/manager/CodeManager.java b/src/main/java/com/shuzijun/leetcode/plugin/manager/CodeManager.java index 860588f6..6c44aeb4 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/manager/CodeManager.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/manager/CodeManager.java @@ -1,13 +1,14 @@ package com.shuzijun.leetcode.plugin.manager; -import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.google.common.base.Joiner; +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.shuzijun.leetcode.plugin.listener.QuestionStatusListener; +import com.shuzijun.leetcode.plugin.listener.QuestionStatusNotifier; +import com.shuzijun.leetcode.plugin.listener.QuestionSubmitNotifier; import com.shuzijun.leetcode.plugin.model.*; import com.shuzijun.leetcode.plugin.setting.PersistentConfig; import com.shuzijun.leetcode.plugin.utils.*; @@ -23,21 +24,20 @@ */ public class CodeManager { - public static void openCode(Question question, Project project) { + public static void openCode(String titleSlug, Project project) { Config config = PersistentConfig.getInstance().getInitConfig(); - String codeType = config.getCodeType(); - CodeTypeEnum codeTypeEnum = CodeTypeEnum.getCodeTypeEnum(codeType); + CodeTypeEnum codeTypeEnum = config.getCodeTypeEnum(project); if (codeTypeEnum == null) { - MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("config.code")); return; } - if (!QuestionManager.fillQuestion(question, codeTypeEnum, project)) { + Question question = QuestionManager.getQuestionByTitleSlug(titleSlug, project); + if (question == null) { return; } - if (config.getQuestionEditor()) { - openContent(question, project, false); + if (config.isQuestionEditor()) { + openContent(titleSlug, project, false); } String filePath = PersistentConfig.getInstance().getTempFilePath() + VelocityUtils.convert(config.getCustomFileName(), question) + codeTypeEnum.getSuffix(); @@ -47,23 +47,24 @@ public static void openCode(Question question, Project project) { if (file.exists()) { FileUtils.openFileEditorAndSaveState(file, project, question, fillPath, true); } else { - question.setContent(CommentUtils.createComment(question.getContent(), codeTypeEnum, config)); - FileUtils.saveFile(file, VelocityUtils.convert(config.getCustomTemplate(), question)); - FileUtils.openFileEditorAndSaveState(file, project, question, fillPath, true); + String content = question.getContent(); + try{ + question.setLangSlug(codeTypeEnum.getLangSlug()); + question.setContent(CommentUtils.createComment(content, codeTypeEnum, config)); + FileUtils.saveFile(file, VelocityUtils.convert(config.getCustomTemplate(), question)); + FileUtils.openFileEditorAndSaveState(file, project, question, fillPath, true); + }finally { + question.setContent(content); + } + } } - public static void openContent(Question question, Project project, boolean isOpen) { + public static void openContent(String titleSlug, Project project, boolean isOpen) { Config config = PersistentConfig.getInstance().getInitConfig(); - String codeType = config.getCodeType(); - CodeTypeEnum codeTypeEnum = CodeTypeEnum.getCodeTypeEnum(codeType); - if (codeTypeEnum == null) { - MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("config.code")); - return; - } - - if (!QuestionManager.fillQuestion(question, codeTypeEnum, project)) { + Question question = QuestionManager.getQuestionByTitleSlug(titleSlug, project); + if (question == null) { return; } @@ -80,112 +81,102 @@ public static void openContent(Question question, Project project, boolean isOpe } - public static void SubmitCode(Question question, Project project) { + public static void SubmitCode(String titleSlug, Project project) { Config config = PersistentConfig.getInstance().getInitConfig(); - String codeType = config.getCodeType(); - CodeTypeEnum codeTypeEnum = CodeTypeEnum.getCodeTypeEnum(codeType); - String code = getCodeText(question, config, codeTypeEnum, project); - if (StringUtils.isBlank(code)) { + Question question = QuestionManager.getQuestionByTitleSlug(titleSlug, project); + if (question == null) { return; } - - if (!QuestionManager.fillQuestion(question, codeTypeEnum, project)) { + CodeTypeEnum codeTypeEnum = config.getCodeTypeEnum(project); + String code = getCodeText(question, config, codeTypeEnum, project); + if (StringUtils.isBlank(code)) { return; } try { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeProblems() + question.getTitleSlug() + "/submit/", "application/json"); JSONObject arg = new JSONObject(); arg.put("question_id", question.getQuestionId()); - arg.put("lang", question.getLangSlug()); + arg.put("lang", codeTypeEnum.getLangSlug()); arg.put("typed_code", code); - httpRequest.setBody(arg.toJSONString()); - httpRequest.addHeader("Accept", "application/json"); - HttpResponse response = HttpRequestUtils.executePost(httpRequest); - if (response != null && response.getStatusCode() == 200) { + HttpResponse response = HttpRequest.builderPost(URLUtils.getLeetcodeProblems() + question.getTitleSlug() + "/submit/", "application/json") + .addHeader("Accept", "application/json").body(arg.toJSONString()).request(); + if (response.getStatusCode() == 200) { String body = response.getBody(); JSONObject returnObj = JSONObject.parseObject(body); ProgressManager.getInstance().run(new SubmitCheckTask(returnObj, codeTypeEnum, question, project)); - MessageUtils.getInstance(project).showInfoMsg("info", PropertiesUtils.getInfo("request.pending")); - } else if (response != null && response.getStatusCode() == 429) { - MessageUtils.getInstance(project).showInfoMsg("info", PropertiesUtils.getInfo("request.pending")); + MessageUtils.getInstance(project).showInfoMsg("", PropertiesUtils.getInfo("request.pending")); + } else if (response.getStatusCode() == 429) { + MessageUtils.getInstance(project).showInfoMsg("", PropertiesUtils.getInfo("request.pending")); } else { - LogUtils.LOG.error("提交失败:url:" + httpRequest.getUrl() + ";param:" + arg.toJSONString() + ";body:" + response.getBody()); - MessageUtils.getInstance(project).showWarnMsg("error", PropertiesUtils.getInfo("request.failed")); + LogUtils.LOG.error("提交失败:url:" + URLUtils.getLeetcodeProblems() + question.getTitleSlug() + "/submit/" + ";param:" + arg.toJSONString() + ";body:" + response.getBody()); + MessageUtils.getInstance(project).showWarnMsg("", PropertiesUtils.getInfo("request.failed")); } } catch (Exception i) { LogUtils.LOG.error("SubmitCode error", i); - MessageUtils.getInstance(project).showWarnMsg("error", PropertiesUtils.getInfo("response.code")); + MessageUtils.getInstance(project).showWarnMsg("", PropertiesUtils.getInfo("response.code")); } } - public static void RunCodeCode(Question question, Project project) { + public static void RunCodeCode(String titleSlug, Project project) { Config config = PersistentConfig.getInstance().getInitConfig(); - String codeType = config.getCodeType(); - CodeTypeEnum codeTypeEnum = CodeTypeEnum.getCodeTypeEnum(codeType); - - String code = getCodeText(question, config, codeTypeEnum, project); - if (StringUtils.isBlank(code)) { + Question question = QuestionManager.getQuestionByTitleSlug(titleSlug, project); + if (question == null) { return; } - - if (!QuestionManager.fillQuestion(question, codeTypeEnum, project)) { + CodeTypeEnum codeTypeEnum = config.getCodeTypeEnum(project); + String code = getCodeText(question, config, codeTypeEnum, project); + if (StringUtils.isBlank(code)) { return; } - try { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeProblems() + question.getTitleSlug() + "/interpret_solution/", "application/json"); JSONObject arg = new JSONObject(); arg.put("question_id", question.getQuestionId()); arg.put("data_input", question.getTestCase()); - arg.put("lang", question.getLangSlug()); + arg.put("lang", codeTypeEnum.getLangSlug()); arg.put("judge_type", "large"); arg.put("typed_code", code); - httpRequest.setBody(arg.toJSONString()); - httpRequest.addHeader("Accept", "application/json"); - HttpResponse response = HttpRequestUtils.executePost(httpRequest); - if (response != null && response.getStatusCode() == 200) { + HttpResponse response = HttpRequest.builderPost(URLUtils.getLeetcodeProblems() + question.getTitleSlug() + "/interpret_solution/", "application/json") + .addHeader("Accept", "application/json").body(arg.toJSONString()).request(); + if (response.getStatusCode() == 200) { String body = response.getBody(); JSONObject returnObj = JSONObject.parseObject(body); ProgressManager.getInstance().run(new RunCodeCheckTask(returnObj, project, question.getTestCase())); - MessageUtils.getInstance(project).showInfoMsg("info", PropertiesUtils.getInfo("request.pending")); - } else if (response != null && response.getStatusCode() == 429) { - MessageUtils.getInstance(project).showWarnMsg("error", "Please wait for the result."); + MessageUtils.getInstance(project).showInfoMsg("", PropertiesUtils.getInfo("request.pending")); + } else if (response.getStatusCode() == 429) { + MessageUtils.getInstance(project).showWarnMsg("", "Please wait for the result."); } else { LogUtils.LOG.error("RuncodeCode failure " + response == null ? "" : response.getBody()); - MessageUtils.getInstance(project).showWarnMsg("error", PropertiesUtils.getInfo("request.failed")); + MessageUtils.getInstance(project).showWarnMsg("", PropertiesUtils.getInfo("request.failed")); } } catch (Exception i) { - MessageUtils.getInstance(project).showWarnMsg("error", PropertiesUtils.getInfo("response.code")); + MessageUtils.getInstance(project).showWarnMsg("", PropertiesUtils.getInfo("response.code")); } } private static String getCodeText(Question question, Config config, CodeTypeEnum codeTypeEnum, Project project) { if (codeTypeEnum == null) { - MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("config.code")); return null; } - if (!HttpRequestUtils.isLogin()) { - MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("login.not")); + if (!HttpRequestUtils.isLogin(project)) { + MessageUtils.getInstance(project).showWarnMsg("", PropertiesUtils.getInfo("login.not")); return null; } String filePath = PersistentConfig.getInstance().getTempFilePath() + VelocityUtils.convert(config.getCustomFileName(), question) + codeTypeEnum.getSuffix(); File file = new File(filePath); if (!file.exists()) { - MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("request.code")); + MessageUtils.getInstance(project).showWarnMsg("", PropertiesUtils.getInfo("request.code")); return null; } else { - setTestCaeAndLang(question, codeTypeEnum, project); if (StringUtils.isBlank(question.getTestCase())) { return null; } String code = FileUtils.getClearCommentFileBody(file, codeTypeEnum); if (StringUtils.isBlank(code)) { - MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("request.empty")); + MessageUtils.getInstance(project).showWarnMsg("", PropertiesUtils.getInfo("request.empty")); return null; } @@ -194,47 +185,6 @@ private static String getCodeText(Question question, Config config, CodeTypeEnum } } - public static void setTestCaeAndLang(Question question, CodeTypeEnum codeTypeEnum, Project project) { - if (codeTypeEnum == null) { - MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("config.code")); - return; - } - if (!QuestionManager.fillQuestion(question, codeTypeEnum, project)) { - return; - } - - try { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(), "application/json"); - httpRequest.setBody("{\"operationName\":\"questionData\",\"variables\":{\"titleSlug\":\"" + question.getTitleSlug() + "\"},\"query\":\"query questionData($titleSlug: String!) {\\n question(titleSlug: $titleSlug) {\\n questionId\\n questionFrontendId\\n boundTopicId\\n title\\n titleSlug\\n content\\n translatedTitle\\n translatedContent\\n isPaidOnly\\n difficulty\\n likes\\n dislikes\\n isLiked\\n similarQuestions\\n contributors {\\n username\\n profileUrl\\n avatarUrl\\n __typename\\n }\\n langToValidPlayground\\n topicTags {\\n name\\n slug\\n translatedName\\n __typename\\n }\\n companyTagStats\\n codeSnippets {\\n lang\\n langSlug\\n code\\n __typename\\n }\\n stats\\n hints\\n solution {\\n id\\n canSeeDetail\\n __typename\\n }\\n status\\n sampleTestCase\\n metaData\\n judgerAvailable\\n judgeType\\n mysqlSchemas\\n enableRunCode\\n enableTestMode\\n envInfo\\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(); - - JSONObject jsonObject = JSONObject.parseObject(body).getJSONObject("data").getJSONObject("question"); - if (StringUtils.isBlank(question.getTestCase())) { - question.setTestCase(jsonObject.getString("sampleTestCase")); - } - - JSONArray jsonArray = jsonObject.getJSONArray("codeSnippets"); - - for (int i = 0; i < jsonArray.size(); i++) { - JSONObject object = jsonArray.getJSONObject(i); - if (codeTypeEnum.getType().equals(object.getString("lang"))) { - question.setLangSlug(object.getString("langSlug")); - break; - } - } - } - } catch (Exception i) { - LogUtils.LOG.error("get test case error", i); - MessageUtils.getInstance(project).showWarnMsg("error", PropertiesUtils.getInfo("response.code")); - return; - } - - } - - private static class SubmitCheckTask extends Task.Backgroundable { private Question question; @@ -255,13 +205,12 @@ public void run(@NotNull ProgressIndicator progressIndicator) { String key = returnObj.getString("submission_id"); for (int i = 0; i < 100; i++) { if (progressIndicator.isCanceled()) { - MessageUtils.getInstance(project).showWarnMsg("error", PropertiesUtils.getInfo("request.cancel")); + MessageUtils.getInstance(project).showWarnMsg("", PropertiesUtils.getInfo("request.cancel")); return; } try { - HttpRequest httpRequest = HttpRequest.get(URLUtils.getLeetcodeSubmissions() + key + "/check/"); - HttpResponse response = HttpRequestUtils.executeGet(httpRequest); - if (response != null && response.getStatusCode() == 200) { + HttpResponse response = HttpRequest.builderGet(URLUtils.getLeetcodeSubmissions() + key + "/check/").request(); + if (response.getStatusCode() == 200) { String body = response.getBody(); JSONObject jsonObject = JSONObject.parseObject(body); if ("SUCCESS".equals(jsonObject.getString("state"))) { @@ -272,30 +221,39 @@ public void run(@NotNull ProgressIndicator progressIndicator) { String memory = jsonObject.getString("status_memory"); String memoryPercentile = jsonObject.getBigDecimal("memory_percentile").setScale(2, BigDecimal.ROUND_HALF_UP).toString(); - MessageUtils.getInstance(project).showInfoMsg("info", PropertiesUtils.getInfo("submit.success", runtime, runtimePercentile, codeTypeEnum.getType(), memory, memoryPercentile, codeTypeEnum.getType())); + MessageUtils.getInstance(project).showInfoMsg("", PropertiesUtils.getInfo("submit.success", runtime, runtimePercentile, codeTypeEnum.getType(), memory, memoryPercentile, codeTypeEnum.getType())); question.setStatus("ac"); - project.getMessageBus().syncPublisher(QuestionStatusListener.QUESTION_STATUS_TOPIC).updateTable(question); + ApplicationManager.getApplication().getMessageBus().syncPublisher(QuestionStatusNotifier.QUESTION_STATUS_TOPIC).updateTable(question); } else { String input = jsonObject.getString("input"); + if (StringUtils.isNotBlank(input)) { + input = input.replace("\n", "\n\t\t\t"); + } String output = jsonObject.getString("code_output"); String expected = jsonObject.getString("expected_output"); + output = MessageUtils.formatDiff(expected, output); String outputs = jsonObject.getString("std_output"); - MessageUtils.getInstance(project).showInfoMsg("info", PropertiesUtils.getInfo("submit.failed", input, output, expected, outputs)); + MessageUtils.getInstance(project).showInfoMsg("", PropertiesUtils.getInfo("submit.failed", input, output, expected, outputs)); if (!"ac".equals(question.getStatus())) { question.setStatus("notac"); - project.getMessageBus().syncPublisher(QuestionStatusListener.QUESTION_STATUS_TOPIC).updateTable(question); + ApplicationManager.getApplication().getMessageBus().syncPublisher(QuestionStatusNotifier.QUESTION_STATUS_TOPIC).updateTable(question); } } } else { String outputs = jsonObject.getString("std_output"); - MessageUtils.getInstance(project).showInfoMsg("info", PropertiesUtils.getInfo("submit.run.failed", buildErrorMsg(jsonObject), jsonObject.getString("last_testcase"), outputs)); + String testcase = jsonObject.getString("last_testcase"); + if (StringUtils.isNotBlank(testcase)) { + testcase = testcase.replace("\n", "\n\t\t\t"); + } + MessageUtils.getInstance(project).showInfoMsg("", PropertiesUtils.getInfo("submit.run.failed", MessageUtils.format(buildErrorMsg(jsonObject), "E"), testcase, outputs)); if (!"ac".equals(question.getStatus())) { question.setStatus("notac"); - project.getMessageBus().syncPublisher(QuestionStatusListener.QUESTION_STATUS_TOPIC).updateTable(question); + ApplicationManager.getApplication().getMessageBus().syncPublisher(QuestionStatusNotifier.QUESTION_STATUS_TOPIC).updateTable(question); } } + ApplicationManager.getApplication().getMessageBus().syncPublisher(QuestionSubmitNotifier.TOPIC).submit(URLUtils.getLeetcodeHost(), question.getTitleSlug()); return; } @@ -303,13 +261,13 @@ public void run(@NotNull ProgressIndicator progressIndicator) { Thread.sleep(300L); } catch (Exception e) { LogUtils.LOG.error("提交出错", e); - MessageUtils.getInstance(project).showWarnMsg("error", PropertiesUtils.getInfo("request.failed")); + MessageUtils.getInstance(project).showWarnMsg("", PropertiesUtils.getInfo("request.failed")); return; } } - - MessageUtils.getInstance(project).showInfoMsg("info", PropertiesUtils.getInfo("response.timeout")); + ApplicationManager.getApplication().getMessageBus().syncPublisher(QuestionSubmitNotifier.TOPIC).submit(URLUtils.getLeetcodeHost(), question.getTitleSlug()); + MessageUtils.getInstance(project).showInfoMsg("", PropertiesUtils.getInfo("response.timeout")); } } @@ -348,13 +306,12 @@ public void run(@NotNull ProgressIndicator progressIndicator) { } for (int i = 0; i < 100; i++) { if (progressIndicator.isCanceled()) { - MessageUtils.getInstance(project).showWarnMsg("error", PropertiesUtils.getInfo("request.cancel")); + MessageUtils.getInstance(project).showWarnMsg("", PropertiesUtils.getInfo("request.cancel")); return; } String body = null; try { - HttpRequest httpRequest = HttpRequest.get(URLUtils.getLeetcodeSubmissions() + key + "/check/"); - HttpResponse response = HttpRequestUtils.executeGet(httpRequest); + HttpResponse response = HttpRequest.builderGet(URLUtils.getLeetcodeSubmissions() + key + "/check/").request(); if (response != null && response.getStatusCode() == 200) { body = response.getBody(); JSONObject jsonObject = JSONObject.parseObject(body); @@ -365,6 +322,9 @@ public void run(@NotNull ProgressIndicator progressIndicator) { } else { if (jsonObject.getBoolean("run_success")) { String input = returnObj.getString("test_case"); + if (StringUtils.isNotBlank(input)) { + input = input.replace("\n", "\n\t\t\t"); + } String output = ""; if (jsonObject.getJSONArray("code_answer") != null) { output = Joiner.on("\n").join(jsonObject.getJSONArray("code_answer")); @@ -375,11 +335,16 @@ public void run(@NotNull ProgressIndicator progressIndicator) { } else if (jsonObject.getJSONArray("expected_code_answer") != null && !jsonObject.getJSONArray("expected_code_answer").isEmpty()) { expected = Joiner.on("\n").join(jsonObject.getJSONArray("expected_code_answer")); } + output = MessageUtils.formatDiff(expected, output); String outputs = StringUtils.join(jsonObject.getJSONArray("code_output"), "\n\t\t"); - MessageUtils.getInstance(project).showInfoMsg("info", PropertiesUtils.getInfo("test.success", input, output, expected, outputs)); + MessageUtils.getInstance(project).showInfoMsg("", PropertiesUtils.getInfo("test.success", input, output, expected, outputs)); } else { String outputs = StringUtils.join(jsonObject.getJSONArray("code_output"), "\n\t\t"); - MessageUtils.getInstance(project).showInfoMsg("info", PropertiesUtils.getInfo("submit.run.failed", buildErrorMsg(jsonObject), input, outputs)); + String tempInput = input; + if (StringUtils.isNotBlank(tempInput)) { + tempInput = tempInput.replace("\n", "\n\t\t\t"); + } + MessageUtils.getInstance(project).showInfoMsg("", PropertiesUtils.getInfo("submit.run.failed", MessageUtils.format(buildErrorMsg(jsonObject), "E"), tempInput, outputs)); } return; } @@ -389,12 +354,12 @@ public void run(@NotNull ProgressIndicator progressIndicator) { Thread.sleep(300L); } catch (Exception e) { LogUtils.LOG.error("提交出错,body:" + body + ",returnObj:" + returnObj.toJSONString(), e); - MessageUtils.getInstance(project).showWarnMsg("error", PropertiesUtils.getInfo("request.failed")); + MessageUtils.getInstance(project).showWarnMsg("", PropertiesUtils.getInfo("request.failed")); return; } } - MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("response.timeout")); + MessageUtils.getInstance(project).showWarnMsg("", PropertiesUtils.getInfo("response.timeout")); } } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/manager/CodeTopManager.java b/src/main/java/com/shuzijun/leetcode/plugin/manager/CodeTopManager.java new file mode 100644 index 00000000..ec2d9ee5 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/manager/CodeTopManager.java @@ -0,0 +1,159 @@ +package com.shuzijun.leetcode.plugin.manager; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Lists; +import com.intellij.openapi.project.Project; +import com.shuzijun.leetcode.plugin.model.*; +import com.shuzijun.leetcode.plugin.utils.*; +import org.apache.commons.lang.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author shuzijun + */ +public class CodeTopManager { + + public static void loadServiceData(NavigatorAction navigatorAction, Project project) { + loadServiceData(navigatorAction, project, null); + } + + public static void loadServiceData(NavigatorAction navigatorAction, Project project, String selectTitleSlug) { + QuestionManager.getQuestionAllService(project, false); + PageInfo pageInfo = CodeTopManager.getQuestionService(project, navigatorAction.getPageInfo()); + if ((pageInfo.getRows() == null || pageInfo.getRows().isEmpty()) && pageInfo.getRowTotal() != 0) { + MessageUtils.getInstance(project).showErrorMsg("error", PropertiesUtils.getInfo("response.question")); + return; + } + + if (navigatorAction.getFind().getFilter().isEmpty()) { + navigatorAction.getFind().addFilter(Constant.CODETOP_FIND_TYPE_DIFFICULTY, CodeTopManager.getDifficulty()); + navigatorAction.getFind().addFilter(Constant.CODETOP_FIND_TYPE_TAGS, CodeTopManager.getTags()); + navigatorAction.getFind().addFilter(Constant.CODETOP_FIND_TYPE_COMPANY, CodeTopManager.getCompany()); + } + navigatorAction.loadData(selectTitleSlug); + } + + private static List getCompany() { + List tags = new ArrayList<>(); + + HttpResponse response = HttpRequest.builderGet(CodeTopURLUtils.getCompanies()).request(); + if (response != null && response.getStatusCode() == 200) { + try { + String body = response.getBody(); + if (StringUtils.isNotBlank(body)) { + JSONArray jsonArray = JSONObject.parseArray(body); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject object = jsonArray.getJSONObject(i); + Tag tag = new Tag(); + tag.setName(object.getString("name")); + tag.setSlug(object.getString("id")); + tags.add(tag); + } + } + } catch (Exception e1) { + LogUtils.LOG.error("Request companies exception", e1); + } + } else { + LogUtils.LOG.error("Request companies failed, status:" + response.getStatusCode() + "body:" + response.getBody()); + } + return tags; + } + + private static List getTags() { + + List tags = new ArrayList<>(); + + HttpResponse response = HttpRequest.builderGet(CodeTopURLUtils.getTags()).request(); + if (response.getStatusCode() == 200) { + try { + String body = response.getBody(); + if (StringUtils.isNotBlank(body)) { + JSONArray jsonArray = JSONObject.parseArray(body); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject object = jsonArray.getJSONObject(i); + Tag tag = new Tag(); + tag.setName(object.getString("name")); + tag.setSlug(object.getString("id")); + tags.add(tag); + } + } + } catch (Exception e1) { + LogUtils.LOG.error("Request tags exception", e1); + } + } else { + LogUtils.LOG.error("Request tags failed, status:" + response.getStatusCode() + "body:" + response.getBody()); + } + return tags; + } + + private static List getDifficulty() { + List keyList = Lists.newArrayList(Constant.DIFFICULTY_EASY, Constant.DIFFICULTY_MEDIUM, Constant.DIFFICULTY_HARD); + List difficultyList = Lists.newArrayList(); + for (int i = 0; i < keyList.size(); i++) { + Tag tag = new Tag(); + tag.setName(keyList.get(i)); + tag.setSlug("" + (i + 1)); + difficultyList.add(tag); + } + return difficultyList; + } + + private static PageInfo getQuestionService(Project project, PageInfo pageInfo) { + String url = CodeTopURLUtils.getQuestions() + "?page=" + pageInfo.getPageIndex(); + PageInfo.Filters filters = pageInfo.getFilters(); + if (StringUtils.isNotBlank(filters.getOrderBy())) { + url = url + "&ordering=" + ("DESCENDING".equals(filters.getSortOrder()) ? "-" : "") + filters.getOrderBy(); + } + if (StringUtils.isNotBlank(filters.getDifficulty())) { + url = url + "&leetcode__level=" + filters.getDifficulty(); + } + + if (filters.getTags() != null && !filters.getTags().isEmpty()) { + url = url + "&leetcode__tags=" + filters.getTags().get(0); + } + + if (StringUtils.isNotBlank(filters.getListId())) { + url = url + "&company=" + filters.getListId(); + } + + + HttpResponse response = HttpRequest.builderGet(url).request(); + if (response.getStatusCode() == 200) { + List questionList = new ArrayList(); + JSONObject pageObject = JSONObject.parseObject(response.getBody()); + JSONArray questionJsonArray = pageObject.getJSONArray("list"); + for (int i = 0; i < pageObject.getJSONArray("list").size(); i++) { + JSONObject codeTopQuestionJsonObject = questionJsonArray.getJSONObject(i); + JSONObject questionJsonObject = codeTopQuestionJsonObject.getJSONObject("leetcode"); + CodeTopQuestionView question = new CodeTopQuestionView(); + question.setTitle(questionJsonObject.getString("title")); + question.setFrontendQuestionId(questionJsonObject.getString("frontend_question_id")); + question.setLevel(questionJsonObject.getString("level")); + question.setTitleSlug(questionJsonObject.getString("slug_title")); + question.setInspectFrequency(codeTopQuestionJsonObject.getInteger("value")); + String time = codeTopQuestionJsonObject.getString("time"); + if (StringUtils.isNotBlank(time) && time.length() > 10) { + question.setInspectTime(time.substring(0, 10)); + } else { + question.setInspectTime(time); + } + QuestionIndex questionIndex = QuestionManager.getQuestionIndex(question.getTitleSlug()); + if (questionIndex != null) { + question.setStatus(questionIndex.getQuestionView().getStatus()); + } + questionList.add(question); + } + + pageInfo.setRowTotal(pageObject.getInteger("count")); + pageInfo.setRows(questionList); + } else { + LogUtils.LOG.error("Request question list failed, status:" + response == null ? "" : response.getStatusCode()); + throw new RuntimeException("Request question list failed"); + } + + return pageInfo; + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/manager/ExploreManager.java b/src/main/java/com/shuzijun/leetcode/plugin/manager/ExploreManager.java deleted file mode 100644 index 80fece2b..00000000 --- a/src/main/java/com/shuzijun/leetcode/plugin/manager/ExploreManager.java +++ /dev/null @@ -1,236 +0,0 @@ -package com.shuzijun.leetcode.plugin.manager; - - -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; -import com.google.common.collect.Lists; -import com.shuzijun.leetcode.plugin.model.Constant; -import com.shuzijun.leetcode.plugin.model.Question; -import com.shuzijun.leetcode.plugin.utils.HttpRequest; -import com.shuzijun.leetcode.plugin.utils.HttpRequestUtils; -import com.shuzijun.leetcode.plugin.utils.HttpResponse; -import com.shuzijun.leetcode.plugin.utils.URLUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.List; - -/** - * @author shuzijun - */ -public class ExploreManager { - - private final static Logger logger = LoggerFactory.getLogger(ExploreManager.class); - - public static List getCategory() { - - List categories = Lists.newArrayList(); - - try { - - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(),"application/json"); - httpRequest.setBody("{\"operationName\":\"GetCategories\",\"variables\":{\"num\":0},\"query\":\"query GetCategories($categorySlug: String, $num: Int) {\\n categories(slug: $categorySlug) {\\n id\\n title\\n slug\\n cards(num: $num) {\\n ...CardDetailFragment\\n __typename\\n }\\n __typename\\n }\\n mostRecentCard {\\n ...CardDetailFragment\\n progress\\n __typename\\n }\\n allProgress\\n}\\n\\nfragment CardDetailFragment on CardNode {\\n id\\n img\\n title\\n slug\\n categorySlug\\n description\\n createdAt\\n lastModified\\n paidOnly\\n published\\n numChapters\\n numItems\\n __typename\\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").getJSONArray("categories"); - for (int i = 0; i < jsonArray.size(); i++) { - JSONObject object = jsonArray.getJSONObject(i); - Question question = new Question(object.getString("title"), Constant.NODETYPE_CATEGORY); - question.setTitleSlug(object.getString("slug")); - categories.add(question); - } - - } - } catch (Exception i) { - logger.error("获取GetCategories错误", i); - } - - return categories; - } - - - public static List getCards(Question q) { - - List cards = Lists.newArrayList(); - try { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(),"application/json"); - httpRequest.setBody("{\"operationName\":\"GetCategories\",\"variables\":{\"categorySlug\":\"" + q.getTitleSlug() + "\",\"num\":null},\"query\":\"query GetCategories($categorySlug: String, $num: Int) {\\n categories(slug: $categorySlug) {\\n id\\n title\\n slug\\n cards(num: $num) {\\n ...CardDetailFragment\\n __typename\\n }\\n __typename\\n }\\n mostRecentCard {\\n ...CardDetailFragment\\n progress\\n __typename\\n }\\n allProgress\\n}\\n\\nfragment CardDetailFragment on CardNode {\\n id\\n img\\n title\\n slug\\n categorySlug\\n description\\n createdAt\\n lastModified\\n paidOnly\\n published\\n numChapters\\n numItems\\n __typename\\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").getJSONArray("categories").getJSONObject(0).getJSONArray("cards"); - for (int i = 0; i < jsonArray.size(); i++) { - JSONObject jsonObject = jsonArray.getJSONObject(i); - Question card = new Question(jsonObject.getString("title"), Constant.NODETYPE_CARD); - card.setTitleSlug(jsonObject.getString("slug")); - card.setStatus(jsonObject.getBoolean("paidOnly") ? "lock" : null); - cards.add(card); - } - } - } catch (Exception i) { - logger.error("获取GetCategories错误", i); - } - - return cards; - } - - - public static List getChapters(Question q) { - List chapters = Lists.newArrayList(); - - try { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(),"application/json"); - httpRequest.setBody("{\"operationName\":\"GetChapters\",\"variables\":{\"cardSlug\":\"" + q.getTitleSlug() + "\"},\"query\":\"query GetChapters($cardSlug: String!) {\\n chapters(cardSlug: $cardSlug) {\\n descriptionText\\n id\\n title\\n slug\\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").getJSONArray("chapters"); - for (int i = 0; i < jsonArray.size(); i++) { - JSONObject object = jsonArray.getJSONObject(i); - Question question = new Question(object.getString("title"), Constant.NODETYPE_CHAPTER); - question.setTitleSlug(q.getTitleSlug()); - - question.setQuestionId(object.getString("id")); - - chapters.add(question); - } - - } - } catch (Exception i) { - logger.error("获取GetChapters错误", i); - } - return chapters; - - } - - public static List getChapterItem(Question q) { - List chapterItem = Lists.newArrayList(); - - try { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(),"application/json"); - httpRequest.setBody("{\"operationName\":\"GetChapter\",\"variables\":{\"chapterId\":\"" + q.getQuestionId() + "\",\"cardSlug\":\"" + q.getTitleSlug() + "\"},\"query\":\"query GetChapter($chapterId: String, $cardSlug: String) {\\n chapter(chapterId: $chapterId, cardSlug: $cardSlug) {\\n ...ExtendedChapterDetail\\n description\\n __typename\\n }\\n}\\n\\nfragment ExtendedChapterDetail on ChapterNode {\\n id\\n title\\n slug\\n items {\\n id\\n title\\n type\\n info\\n paidOnly\\n chapterId\\n prerequisites {\\n id\\n chapterId\\n __typename\\n }\\n __typename\\n }\\n __typename\\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("chapter").getJSONArray("items"); - for (int i = 0; i < jsonArray.size(); i++) { - JSONObject object = jsonArray.getJSONObject(i); - Question question = new Question(object.getString("title"), Constant.NODETYPE_ITEM); - question.setQuestionId(object.getString("id")); - question.setStatus(object.getBoolean("paidOnly") ? "lock" : null); - if ("1".equals(object.getString("type"))) { - question.setLeaf(!object.getBoolean("paidOnly")); - question.setLangSlug(Constant.ITEM_TYPE_QUESTION); - chapterItem.add(question); - }/*else if("3".equals(object.getString("type"))){ - question.setLangSlug(Constant.ITEM_TYPE_HTML); - chapterItem.add(question); - }else if("0".equals(object.getString("type"))){ - question.setLangSlug(Constant.ITEM_TYPE_ARTICLE); - chapterItem.add(question); - }*/ - } - if (chapterItem.isEmpty()) { - chapterItem.add(new Question("no question")); - } - } - } catch (Exception i) { - logger.error("获取GetChapters错误", i); - } - return chapterItem; - - } - - public static Question getItem(Question q) { - - - try { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(),"application/json"); - httpRequest.setBody("{\"operationName\":\"GetItem\",\"variables\":{\"itemId\":\"" + q.getQuestionId() + "\"},\"query\":\"query GetItem($itemId: String!) {\\n item(id: $itemId) {\\n id\\n title\\n type\\n paidOnly\\n lang\\n question {\\n questionId\\n title\\n titleSlug\\n __typename\\n }\\n article {\\n id\\n title\\n __typename\\n }\\n video {\\n id\\n __typename\\n }\\n htmlArticle {\\n id\\n __typename\\n }\\n webPage {\\n id\\n __typename\\n }\\n __typename\\n }\\n isCurrentUserAuthenticated\\n}\\n\"}"); - httpRequest.addHeader("Accept", "application/json"); - HttpResponse response = HttpRequestUtils.executePost(httpRequest); - if (response != null && response.getStatusCode() == 200) { - - String body = response.getBody(); - - JSONObject object = JSONObject.parseObject(body).getJSONObject("data").getJSONObject("item"); - if (object!=null){ - q.setStatus(object.getBoolean("paidOnly") ? "lock" : null); - JSONObject question = object.getJSONObject(q.getLangSlug()); - if(Constant.ITEM_TYPE_QUESTION.equals(q.getLangSlug())){ - q.setQuestionId(question.getString("questionId")); - q.setFrontendQuestionId(question.getString("questionId")); - q.setTitleSlug(question.getString("titleSlug")); - }else { - q.setNodeType(Constant.NODETYPE_DEF); - q.setQuestionId(question.getString("id")); - } - - } - } - } catch (Exception i) { - logger.error("获取GetChapters错误", i); - } - return q; - } - - public static String GetHtmlArticle(Question q) { - - try { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(),"application/json"); - httpRequest.setBody("{\"operationName\":\"GetHtmlArticle\",\"variables\":{\"htmlArticleId\":\""+q.getQuestionId()+"\"},\"query\":\"query GetHtmlArticle($htmlArticleId: String!) {\\n htmlArticle(id: $htmlArticleId) {\\n id\\n html\\n originalLink\\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(); - - JSONObject object = JSONObject.parseObject(body).getJSONObject("data").getJSONObject("htmlArticle"); - if (object!=null){ - return object.getString("html"); - } - } - } catch (Exception i) { - logger.error("获取GetChapters错误", i); - } - return null; - } - - - public static String GetArticle(Question q) { - - try { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(),"application/json"); - httpRequest.setBody("{\"operationName\":\"GetArticle\",\"variables\":{\"articleId\":\""+q.getQuestionId()+"\"},\"query\":\"query GetArticle($articleId: String!) {\\n article(id: $articleId) {\\n id\\n title\\n body\\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(); - - JSONObject object = JSONObject.parseObject(body).getJSONObject("data").getJSONObject("article"); - if (object!=null){ - return object.getString("body"); - } - } - } catch (Exception i) { - logger.error("获取GetChapters错误", i); - } - return null; - } - - -} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/manager/FavoriteManager.java b/src/main/java/com/shuzijun/leetcode/plugin/manager/FavoriteManager.java index fb2d91c9..d280ca25 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/manager/FavoriteManager.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/manager/FavoriteManager.java @@ -2,10 +2,9 @@ import com.alibaba.fastjson.JSONObject; import com.intellij.openapi.project.Project; -import com.shuzijun.leetcode.plugin.model.CodeTypeEnum; +import com.shuzijun.leetcode.plugin.model.Graphql; import com.shuzijun.leetcode.plugin.model.Question; import com.shuzijun.leetcode.plugin.model.Tag; -import com.shuzijun.leetcode.plugin.setting.PersistentConfig; import com.shuzijun.leetcode.plugin.utils.*; /** @@ -13,28 +12,20 @@ */ public class FavoriteManager { - public static void addQuestionToFavorite(Tag tag, Question question, Project project) { - if (!HttpRequestUtils.isLogin()) { + public static void addQuestionToFavorite(Tag tag, String titleSlug, Project project) { + if (!HttpRequestUtils.isLogin(project)) { MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("login.not")); - return ; - } - CodeTypeEnum codeTypeEnum = CodeTypeEnum.getCodeTypeEnum(PersistentConfig.getInstance().getInitConfig().getCodeType()); - if (codeTypeEnum == null) { - MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("config.code")); return; } - - if(!QuestionManager.fillQuestion(question,codeTypeEnum,project)){ + Question question = QuestionManager.getQuestionByTitleSlug(titleSlug, project); + if (question == null) { return; } try { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(),"application/json"); - httpRequest.setBody("{\"operationName\":\"addQuestionToFavorite\",\"variables\":{\"favoriteIdHash\":\""+tag.getSlug()+"\",\"questionId\":\""+question.getQuestionId()+"\"},\"query\":\"mutation addQuestionToFavorite($favoriteIdHash: String!, $questionId: String!) {\\n addQuestionToFavorite(favoriteIdHash: $favoriteIdHash, questionId: $questionId) {\\n ok\\n error\\n favoriteIdHash\\n questionId\\n __typename\\n }\\n}\\n\"}"); - httpRequest.addHeader("Accept", "application/json"); - HttpResponse response = HttpRequestUtils.executePost(httpRequest); - - if (response != null && response.getStatusCode() == 200) { + HttpResponse response = Graphql.builder().operationName("addQuestionToFavorite") + .variables("favoriteIdHash", tag.getSlug()).variables("questionId", question.getQuestionId()).request(); + if (response.getStatusCode() == 200) { String body = response.getBody(); JSONObject object = JSONObject.parseObject(body).getJSONObject("data").getJSONObject("addQuestionToFavorite"); if (object.getBoolean("ok")) { @@ -50,28 +41,20 @@ public static void addQuestionToFavorite(Tag tag, Question question, Project pro } } - public static void removeQuestionFromFavorite(Tag tag, Question question,Project project) { - if (!HttpRequestUtils.isLogin()) { + public static void removeQuestionFromFavorite(Tag tag, String titleSlug, Project project) { + if (!HttpRequestUtils.isLogin(project)) { MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("login.not")); - return ; - } - CodeTypeEnum codeTypeEnum = CodeTypeEnum.getCodeTypeEnum(PersistentConfig.getInstance().getInitConfig().getCodeType()); - if (codeTypeEnum == null) { - MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("config.code")); return; } - - if(!QuestionManager.fillQuestion(question,codeTypeEnum,project)){ + Question question = QuestionManager.getQuestionByTitleSlug(titleSlug, project); + if (question == null) { return; } try { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(),"application/json"); - httpRequest.setBody("{\"operationName\":\"removeQuestionFromFavorite\",\"variables\":{\"favoriteIdHash\":\"" + tag.getSlug() + "\",\"questionId\":\"" + question.getQuestionId() + "\"},\"query\":\"mutation removeQuestionFromFavorite($favoriteIdHash: String!, $questionId: String!) {\\n removeQuestionFromFavorite(favoriteIdHash: $favoriteIdHash, questionId: $questionId) {\\n ok\\n error\\n favoriteIdHash\\n questionId\\n __typename\\n }\\n}\\n\"}"); - httpRequest.addHeader("Accept", "application/json"); - HttpResponse response = HttpRequestUtils.executePost(httpRequest); - - if (response != null && response.getStatusCode() == 200) { + HttpResponse response = Graphql.builder().operationName("removeQuestionFromFavorite") + .variables("favoriteIdHash", tag.getSlug()).variables("questionId", question.getQuestionId()).request(); + if (response.getStatusCode() == 200) { String body = response.getBody(); JSONObject object = JSONObject.parseObject(body).getJSONObject("data").getJSONObject("removeQuestionFromFavorite"); if (object.getBoolean("ok")) { diff --git a/src/main/java/com/shuzijun/leetcode/plugin/manager/FindManager.java b/src/main/java/com/shuzijun/leetcode/plugin/manager/FindManager.java new file mode 100644 index 00000000..6a183d05 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/manager/FindManager.java @@ -0,0 +1,176 @@ +package com.shuzijun.leetcode.plugin.manager; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Lists; +import com.intellij.openapi.project.Project; +import com.shuzijun.leetcode.plugin.model.Constant; +import com.shuzijun.leetcode.plugin.model.HttpRequest; +import com.shuzijun.leetcode.plugin.model.Tag; +import com.shuzijun.leetcode.plugin.utils.*; +import com.shuzijun.leetcode.plugin.window.WindowFactory; +import org.apache.commons.lang.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author shuzijun + */ +public class FindManager { + + public static List getDifficulty() { + + List keyList = Lists.newArrayList(Constant.DIFFICULTY_EASY, Constant.DIFFICULTY_MEDIUM, Constant.DIFFICULTY_HARD); + List difficultyList = Lists.newArrayList(); + for (String key : keyList) { + Tag tag = new Tag(); + tag.setName(key); + tag.setSlug(key.toUpperCase()); + difficultyList.add(tag); + } + return difficultyList; + } + + public static List getStatus() { + List keyList = Lists.newArrayList(Constant.STATUS_TODO, Constant.STATUS_SOLVED, Constant.STATUS_ATTEMPTED); + + List statusList = Lists.newArrayList(); + for (String key : keyList) { + Tag tag = new Tag(); + tag.setName(key); + if (Constant.STATUS_TODO.equals(key)) { + tag.setSlug("NOT_STARTED"); + } else if (Constant.STATUS_SOLVED.equals(key)) { + tag.setSlug("AC"); + } else if (Constant.STATUS_ATTEMPTED.equals(key)) { + tag.setSlug("TRIED"); + } + statusList.add(tag); + } + return statusList; + } + + public static List getTags() { + List tags = new ArrayList<>(); + + HttpResponse response = HttpRequest.builderGet(URLUtils.getLeetcodeTags()).cache(true).request(); + if (response.getStatusCode() == 200) { + try { + String body = response.getBody(); + tags = parseTag(body); + } catch (Exception e1) { + LogUtils.LOG.error("Request tags exception", e1); + } + } else { + LogUtils.LOG.error("Request tags failed, status:" + response.getStatusCode() + "body:" + response.getBody()); + } + + return tags; + } + + public static List getLists(Project project) { + List tags = new ArrayList<>(); + + HttpResponse response = HttpRequest.builderGet(URLUtils.getLeetcodeFavorites()) + .cacheParam(WindowFactory.getDataContext(project).getData(DataKeys.LEETCODE_PROJECTS_TABS).getUser().getUsername()).request(); + if (response.getStatusCode() == 200) { + try { + String body = response.getBody(); + tags = parseList(body); + } catch (Exception e1) { + LogUtils.LOG.error("Request Lists exception", e1); + } + } else { + LogUtils.LOG.error("Request Lists failed, status:" + response.getStatusCode() + "body:" + response.getBody()); + } + return tags; + } + + public static List getCategory() { + List tags = new ArrayList<>(); + + HttpResponse response = HttpRequest.builderGet(URLUtils.getLeetcodeCardInfo()).cache(true).request(); + if (response.getStatusCode() == 200) { + try { + String body = response.getBody(); + tags = parseCategory(body); + } catch (Exception e1) { + LogUtils.LOG.error("Request CardInfo exception", e1); + } + } else { + LogUtils.LOG.error("Request CardInfo failed, status:" + response.getStatusCode() + "body:" + response.getBody()); + } + return tags; + } + + private static List parseTag(String str) { + List tags = new ArrayList(); + + if (StringUtils.isNotBlank(str)) { + + JSONArray jsonArray = JSONObject.parseObject(str).getJSONArray("topics"); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject object = jsonArray.getJSONObject(i); + Tag tag = new Tag(); + tag.setSlug(object.getString("slug")); + String name = object.getString(URLUtils.getTagName()); + if (StringUtils.isBlank(name)) { + name = object.getString("name"); + } + tag.setName(name); + JSONArray questionArray = object.getJSONArray("questions"); + for (int j = 0; j < questionArray.size(); j++) { + tag.addQuestion(questionArray.getInteger(j).toString()); + } + + tags.add(tag); + } + } + return tags; + } + + private static List parseCategory(String str) { + List tags = new ArrayList(); + + if (StringUtils.isNotBlank(str)) { + + JSONArray jsonArray = JSONArray.parseObject(str).getJSONObject("categories").getJSONArray("0"); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject object = jsonArray.getJSONObject(i); + Tag tag = new Tag(); + tag.setSlug(object.getString("slug")); + tag.setType(URLUtils.getLeetcodeUrl() + "/api" + object.getString("url").replace("problemset", "problems")); + tag.setName(object.getString("title")); + tags.add(tag); + } + } + return tags; + } + + private static List parseList(String str) { + List tags = new ArrayList(); + + if (StringUtils.isNotBlank(str)) { + + JSONArray jsonArray = JSONArray.parseArray(str); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject object = jsonArray.getJSONObject(i); + Tag tag = new Tag(); + tag.setSlug(object.getString("id")); + tag.setType(object.getString("type")); + String name = object.getString("name"); + if (StringUtils.isBlank(name)) { + name = object.getString("name"); + } + tag.setName(name); + JSONArray questionArray = object.getJSONArray("questions"); + for (int j = 0; j < questionArray.size(); j++) { + tag.addQuestion(questionArray.getInteger(j).toString()); + } + tags.add(tag); + } + } + return tags; + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/manager/NavigatorAction.java b/src/main/java/com/shuzijun/leetcode/plugin/manager/NavigatorAction.java new file mode 100644 index 00000000..7c66faff --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/manager/NavigatorAction.java @@ -0,0 +1,114 @@ +package com.shuzijun.leetcode.plugin.manager; + +import com.shuzijun.leetcode.plugin.model.*; +import com.shuzijun.leetcode.plugin.window.NavigatorTableData; + +import javax.swing.*; + +/** + * @author shuzijun + */ +public interface NavigatorAction { + + void updateUI(); + + JPanel queryPanel(); + + boolean selectedRow(String slug); + + void findClear(); + + void findChange(String filterKey, boolean b, Tag tag); + + Find getFind(); + + void sort(Sort sort); + + T getSelectedRowData(); + + NavigatorTableData.PagePanel getPagePanel(); + + PageInfo getPageInfo(); + + void loadData(String slug); + + void loadServiceData(); + + void resetServiceData(); + + boolean position(String slug); + + public static class Adapter implements NavigatorAction { + + + @Override + public JPanel queryPanel() { + return null; + } + + @Override + public boolean selectedRow(String slug) { + return false; + } + + @Override + public void findClear() { + + } + + @Override + public void updateUI() { + + } + + @Override + public void findChange(String filterKey, boolean b, Tag tag) { + + } + + @Override + public Find getFind() { + return null; + } + + @Override + public void sort(Sort sort) { + + } + + @Override + public T getSelectedRowData() { + return null; + } + + @Override + public NavigatorTableData.PagePanel getPagePanel() { + return null; + } + + @Override + public PageInfo getPageInfo() { + return null; + } + + @Override + public void loadData(String slug) { + + } + + @Override + public void loadServiceData() { + + } + + @Override + public void resetServiceData() { + + } + + @Override + public boolean position(String slug) { + return false; + } + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/manager/NoteManager.java b/src/main/java/com/shuzijun/leetcode/plugin/manager/NoteManager.java index f961de9f..06872d89 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/manager/NoteManager.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/manager/NoteManager.java @@ -9,6 +9,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Constant; +import com.shuzijun.leetcode.plugin.model.Graphql; import com.shuzijun.leetcode.plugin.model.Question; import com.shuzijun.leetcode.plugin.setting.PersistentConfig; import com.shuzijun.leetcode.plugin.utils.*; @@ -21,38 +22,42 @@ public class NoteManager { - public static void show(Question question, Project project) { - Config config = PersistentConfig.getInstance().getInitConfig(); - String filePath = PersistentConfig.getInstance().getTempFilePath() + Constant.DOC_NOTE + VelocityUtils.convert(config.getCustomFileName(), question) + ".md"; + public static File show(String titleSlug, Project project, Boolean isOpenEditor) { + Config config = PersistentConfig.getInstance().getConfig(); + Question question = QuestionManager.getQuestionByTitleSlug(titleSlug, project); + String filePath = PersistentConfig.getInstance().getTempFilePath() + Constant.DOC_NOTE + VelocityUtils.convert(config.getCustomFileName(), question) + ".md"; File file = new File(filePath); if (file.exists()) { - FileUtils.openFileEditor(file,project); - }else { - if(pull( question, project)){ - FileUtils.openFileEditor(file,project); + if (isOpenEditor) { + FileUtils.openFileEditor(file, project); + } + } else { + if (pull(titleSlug, project)) { + if (isOpenEditor) { + FileUtils.openFileEditor(file, project); + } } } + return file; } - public static boolean pull(Question question, Project project) { + + public static boolean pull(String titleSlug, Project project) { try { - if (!HttpRequestUtils.isLogin()) { + if (!HttpRequestUtils.isLogin(project)) { MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("login.not")); return false; } + Question question = QuestionManager.getQuestionByTitleSlug(titleSlug, project); + Config config = PersistentConfig.getInstance().getConfig(); + String filePath = PersistentConfig.getInstance().getTempFilePath() + Constant.DOC_NOTE + VelocityUtils.convert(config.getCustomFileName(), question) + ".md"; - Config config = PersistentConfig.getInstance().getInitConfig(); - String filePath = PersistentConfig.getInstance().getTempFilePath() + Constant.DOC_NOTE + VelocityUtils.convert(config.getCustomFileName(), question) + ".md"; - - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(),"application/json"); - httpRequest.setBody("{\"operationName\":\"QuestionNote\",\"variables\":{\"titleSlug\":\""+question.getTitleSlug()+"\"},\"query\":\"query QuestionNote($titleSlug: String!) {\\n question(titleSlug: $titleSlug) {\\n questionId\\n note\\n __typename\\n }\\n}\\n\"}"); - httpRequest.addHeader("Accept", "application/json"); - HttpResponse response = HttpRequestUtils.executePost(httpRequest); - if (response != null && response.getStatusCode() == 200) { + HttpResponse response = Graphql.builder().operationName("getNote").variables("titleSlug",question.getTitleSlug()).request(); + if (response.getStatusCode() == 200) { String body = response.getBody(); JSONObject jsonObject = JSONObject.parseObject(body).getJSONObject("data").getJSONObject("question"); - FileUtils.saveFile(filePath,jsonObject.getString("note")); + FileUtils.saveFile(filePath, jsonObject.getString("note")); return Boolean.TRUE; } else { MessageUtils.getInstance(project).showWarnMsg("error", PropertiesUtils.getInfo("request.failed")); @@ -65,15 +70,16 @@ public static boolean pull(Question question, Project project) { return Boolean.FALSE; } - public static void push(Question question, Project project) { + public static void push(String titleSlug, Project project) { try { - if (!HttpRequestUtils.isLogin()) { + if (!HttpRequestUtils.isLogin(project)) { MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("login.not")); return; } - Config config = PersistentConfig.getInstance().getInitConfig(); - String filePath = PersistentConfig.getInstance().getTempFilePath() + Constant.DOC_NOTE + VelocityUtils.convert(config.getCustomFileName(), question) + ".md"; + Config config = PersistentConfig.getInstance().getConfig(); + Question question = QuestionManager.getQuestionByTitleSlug(titleSlug, project); + String filePath = PersistentConfig.getInstance().getTempFilePath() + Constant.DOC_NOTE + VelocityUtils.convert(config.getCustomFileName(), question) + ".md"; File file = new File(filePath); if (!file.exists()) { MessageUtils.getInstance(project).showWarnMsg("error", PropertiesUtils.getInfo("request.code")); @@ -82,19 +88,13 @@ public static void push(Question question, Project project) { VirtualFile vf = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); FileUtils.saveEditDocument(vf); String note = ApplicationManager.getApplication().runReadAction((Computable) () -> FileDocumentManager.getInstance().getDocument(vf).getText()); - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(),"application/json"); - JSONObject variables = new JSONObject(); - variables.put("titleSlug",question.getTitleSlug()); - variables.put("content",note); - httpRequest.setBody("{\"operationName\":\"updateNote\",\"variables\":"+variables.toJSONString()+",\"query\":\"mutation updateNote($titleSlug: String!, $content: String!) {\\n updateNote(titleSlug: $titleSlug, content: $content) {\\n ok\\n error\\n question {\\n questionId\\n note\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}"); - httpRequest.addHeader("Accept", "application/json"); - HttpResponse response = HttpRequestUtils.executePost(httpRequest); - if (response != null && response.getStatusCode() == 200) { + HttpResponse response = Graphql.builder().operationName("updateNote").variables("titleSlug",question.getTitleSlug()).variables("content",note).request(); + if (response.getStatusCode() == 200) { String body = response.getBody(); JSONObject jsonObject = JSONObject.parseObject(body).getJSONObject("data").getJSONObject("updateNote"); - if(!jsonObject.getBoolean("ok")){ + if (!jsonObject.getBoolean("ok")) { MessageUtils.getInstance(project).showWarnMsg("error", jsonObject.getString("error")); - }else { + } else { MessageUtils.getInstance(project).showInfoMsg("info", "success"); } } else { diff --git a/src/main/java/com/shuzijun/leetcode/plugin/manager/QuestionManager.java b/src/main/java/com/shuzijun/leetcode/plugin/manager/QuestionManager.java index a4cf7213..71f6ca20 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/manager/QuestionManager.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/manager/QuestionManager.java @@ -2,66 +2,48 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import com.google.common.collect.Lists; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import com.google.common.collect.Maps; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.shuzijun.leetcode.plugin.model.*; import com.shuzijun.leetcode.plugin.setting.PersistentConfig; import com.shuzijun.leetcode.plugin.utils.*; +import com.shuzijun.leetcode.plugin.utils.doc.CleanMarkdown; import com.shuzijun.leetcode.plugin.window.WindowFactory; import org.apache.commons.lang.StringUtils; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.concurrent.TimeUnit; /** * @author shuzijun */ public class QuestionManager { - private static Map dayMap = Maps.newLinkedHashMap(); + private static final Cache dayMap = CacheBuilder.newBuilder().maximumSize(5).expireAfterWrite(2, TimeUnit.DAYS).build(); + private static final Cache questionCache = CacheBuilder.newBuilder().maximumSize(30).build(); + private static final Cache> questionAllCache = CacheBuilder.newBuilder().expireAfterWrite(2, TimeUnit.DAYS).build(); + private static final Map> questionIndexCache = Maps.newLinkedHashMap(); - public static PageInfo getQuestionService(Project project, PageInfo pageInfo) { - Boolean isPremium = false; - if (HttpRequestUtils.isLogin()) { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(), "application/json"); - if (URLUtils.isCn()) { - httpRequest.setBody("{\"query\":\"\\n query globalData {\\n userStatus {\\n isSignedIn\\n isPremium\\n username\\n realName\\n avatar\\n userSlug\\n isAdmin\\n useTranslation\\n premiumExpiredAt\\n isTranslator\\n isSuperuser\\n isPhoneVerified\\n isVerified\\n }\\n jobsMyCompany {\\n nameSlug\\n }\\n commonNojPermissionTypes\\n}\\n \",\"variables\":{},\"operationName\":\"globalData\"}"); - } else { - httpRequest.setBody("{\"query\":\"\\n query globalData {\\n userStatus {\\n userId\\n isSignedIn\\n isMockUser\\n isPremium\\n username\\n avatar\\n isAdmin\\n isSuperuser\\n permissions\\n isTranslator\\n notificationStatus {\\n lastModified\\n numUnread\\n }\\n }\\n}\\n \",\"variables\":{},\"operationName\":\"globalData\"}"); - } - httpRequest.addHeader("Accept", "application/json"); - HttpResponse response = HttpRequestUtils.executePost(httpRequest); - if (response != null && response.getStatusCode() == 200) { - JSONObject user = JSONObject.parseObject(response.getBody()).getJSONObject("data").getJSONObject("userStatus"); - isPremium = user.getBoolean("isPremium"); - ApplicationManager.getApplication().invokeAndWait(() -> { - WindowFactory.updateTitle(project, user.getString("username")); - }); - } else { - LogUtils.LOG.error("Request userStatus failed, status:" + response == null ? "" : response.getStatusCode()); - } - } - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(), "application/json"); - if (URLUtils.isCn()) { - httpRequest.setBody("{\"query\":\"\\n query problemsetQuestionList($categorySlug: String, $limit: Int, $skip: Int, $filters: QuestionListFilterInput) {\\n problemsetQuestionList(\\n categorySlug: $categorySlug\\n limit: $limit\\n skip: $skip\\n filters: $filters\\n ) {\\n hasMore\\n total\\n questions {\\n acRate\\n difficulty\\n freqBar\\n frontendQuestionId\\n isFavor\\n paidOnly\\n solutionNum\\n status\\n title\\n titleCn\\n titleSlug\\n topicTags {\\n name\\n nameTranslated\\n id\\n slug\\n }\\n extra {\\n hasVideoSolution\\n topCompanyTags {\\n imgUrl\\n slug\\n numSubscribed\\n }\\n }\\n }\\n }\\n}\\n \",\"variables\":{\"categorySlug\":\"" + pageInfo.getCategorySlug() + "\",\"skip\":" + pageInfo.getSkip() + ",\"limit\":" + pageInfo.getPageSize() + ",\"filters\":" + pageInfo.getFilters().toString() + "},\"operationName\":\"problemsetQuestionList\"}"); - } else { - httpRequest.setBody("{\"query\":\"\\n query problemsetQuestionList($categorySlug: String, $limit: Int, $skip: Int, $filters: QuestionListFilterInput) {\\n problemsetQuestionList: questionList(\\n categorySlug: $categorySlug\\n limit: $limit\\n skip: $skip\\n filters: $filters\\n ) {\\n total: totalNum\\n questions: data {\\n acRate\\n difficulty\\n freqBar\\n frontendQuestionId: questionFrontendId\\n isFavor\\n paidOnly: isPaidOnly\\n status\\n title\\n titleSlug\\n topicTags {\\n name\\n id\\n slug\\n }\\n hasSolution\\n hasVideoSolution\\n }\\n }\\n}\\n \",\"variables\":{\"categorySlug\":\"" + pageInfo.getCategorySlug() + "\",\"skip\":" + pageInfo.getSkip() + ",\"limit\":" + pageInfo.getPageSize() + ",\"filters\":" + pageInfo.getFilters().toString() + "},\"operationName\":\"problemsetQuestionList\"}"); + public static PageInfo getQuestionViewList(Project project, PageInfo pageInfo) { + boolean isPremium = false; + User user = WindowFactory.getDataContext(project).getData(DataKeys.LEETCODE_PROJECTS_TABS).getUser(); + if (user != null) { + isPremium = user.isPremium(); } - httpRequest.addHeader("Accept", "application/json"); - HttpResponse response = HttpRequestUtils.executePost(httpRequest); - if (response != null && response.getStatusCode() == 200) { - List questionList = parseQuestion(response.getBody(), isPremium); - - Question dayQuestion = dayMap.get(URLUtils.getLeetcodeHost() + new SimpleDateFormat("yyyy-MM-dd").format(new Date())); - if (dayQuestion == null) { - dayQuestion = questionOfToday(); - } + + HttpResponse response = Graphql.builder().cn(URLUtils.isCn()).operationName("problemsetQuestionList") + .variables("categorySlug", pageInfo.getCategorySlug()).variables("skip", pageInfo.getSkip()) + .variables("limit", pageInfo.getPageSize()).variables("filters", pageInfo.getFilters()) + .cacheParam(WindowFactory.getDataContext(project).getData(DataKeys.LEETCODE_PROJECTS_TABS).getUser().getUsername()).request(); + if (response.getStatusCode() == 200) { + List questionList = parseQuestion(response.getBody(), isPremium); + + QuestionView dayQuestion = questionOfToday(); if (dayQuestion != null) { questionList.add(0, dayQuestion); } @@ -70,7 +52,7 @@ public static PageInfo getQuestionService(Project project, PageInfo pa pageInfo.setRowTotal(total); pageInfo.setRows(questionList); } else { - LogUtils.LOG.error("Request question list failed, status:" + response == null ? "" : response.getStatusCode()); + LogUtils.LOG.error("Request question list failed, status:" + response.getStatusCode()); throw new RuntimeException("Request question list failed"); } @@ -78,118 +60,92 @@ public static PageInfo getQuestionService(Project project, PageInfo pa } - public static List getDifficulty() { - - List keyList = Lists.newArrayList(Constant.DIFFICULTY_EASY, Constant.DIFFICULTY_MEDIUM, Constant.DIFFICULTY_HARD); - List difficultyList = Lists.newArrayList(); - for (String key : keyList) { - Tag tag = new Tag(); - tag.setName(key); - tag.setSlug(key.toUpperCase()); - difficultyList.add(tag); - } - return difficultyList; - } - - public static List getStatus() { - List keyList = Lists.newArrayList(Constant.STATUS_TODO, Constant.STATUS_SOLVED, Constant.STATUS_ATTEMPTED); - - List statusList = Lists.newArrayList(); - for (String key : keyList) { - Tag tag = new Tag(); - tag.setName(key); - if (Constant.STATUS_TODO.equals(key)) { - tag.setSlug("NOT_STARTED"); - } else if (Constant.STATUS_SOLVED.equals(key)) { - tag.setSlug("AC"); - } else if (Constant.STATUS_ATTEMPTED.equals(key)) { - tag.setSlug("TRIED"); - } - statusList.add(tag); + public static List getQuestionAllService(Project project, boolean reset) { + Boolean isPremium = false; + User user = WindowFactory.getDataContext(project).getData(DataKeys.LEETCODE_PROJECTS_TABS).getUser(); + if (user != null) { + isPremium = user.isPremium(); } - return statusList; - } - - public static List getTags() { - List tags = new ArrayList<>(); + if (questionAllCache.getIfPresent(URLUtils.getLeetcodeHost()) == null || reset) { + String key = URLUtils.getLeetcodeHost() + "getQuestionAll"; + synchronized (key.intern()) { + if (questionAllCache.getIfPresent(URLUtils.getLeetcodeHost()) == null || reset) { + HttpResponse response = Graphql.builder().cn(URLUtils.isCn()).operationName("allQuestions") + .cacheParam(WindowFactory.getDataContext(project).getData(DataKeys.LEETCODE_PROJECTS_TABS).getUser().getUsername()).request(); + if (response.getStatusCode() == 200) { + List questionViews = new ArrayList<>(); + + JSONArray allQuestions = JSONObject.parseObject(response.getBody()).getJSONObject("data").getJSONArray("allQuestions"); + for (int i = 0; i < allQuestions.size(); i++) { + JSONObject jsonObject = allQuestions.getJSONObject(i); + QuestionView questionView = jsonObject.toJavaObject(QuestionView.class); + if (jsonObject.getBoolean("isPaidOnly") && !isPremium) { + questionView.setStatus("lock"); + } + if (URLUtils.isCn() && !PersistentConfig.getInstance().getConfig().getEnglishContent()) { + if (StringUtils.isNotBlank(jsonObject.getString("translatedTitle"))) { + questionView.setTitle(jsonObject.getString("translatedTitle")); + } + } + questionViews.add(questionView); - HttpRequest httpRequest = HttpRequest.get(URLUtils.getLeetcodeTags()); - HttpResponse response = HttpRequestUtils.executeGet(httpRequest); - if (response != null && response.getStatusCode() == 200) { - try { - String body = response.getBody(); - tags = parseTag(body); - } catch (Exception e1) { - LogUtils.LOG.error("Request tags exception", e1); - } - } else { - LogUtils.LOG.error("Request tags failed, status:" + response.getStatusCode() + "body:" + response.getBody()); - } + } - return tags; - } + Collections.sort(questionViews, (o1, o2) -> o1.frontendQuestionIdCompareTo(o2)); - public static List getLists() { - List tags = new ArrayList<>(); + Map questionIndex = Maps.newHashMap(); + for (int i = 0; i < questionViews.size(); i++) { + questionIndex.put(questionViews.get(i).getTitleSlug(), i); + } - HttpRequest httpRequest = HttpRequest.get(URLUtils.getLeetcodeFavorites()); - HttpResponse response = HttpRequestUtils.executeGet(httpRequest); - if (response != null && response.getStatusCode() == 200) { - try { - String body = response.getBody(); - tags = parseList(body); - } catch (Exception e1) { - LogUtils.LOG.error("Request Lists exception", e1); + questionAllCache.put(URLUtils.getLeetcodeHost(), questionViews); + questionIndexCache.put(URLUtils.getLeetcodeHost(), questionIndex); + } else { + questionAllCache.invalidate(URLUtils.getLeetcodeHost()); + questionIndexCache.remove(URLUtils.getLeetcodeHost()); + } + } } - } else { - LogUtils.LOG.error("Request Lists failed, status:" + response.getStatusCode() + "body:" + response.getBody()); } - return tags; + return questionAllCache.getIfPresent(URLUtils.getLeetcodeHost()); } - public static List getCategory() { - List tags = new ArrayList<>(); - - HttpRequest httpRequest = HttpRequest.get(URLUtils.getLeetcodeCardInfo()); - HttpResponse response = HttpRequestUtils.executeGet(httpRequest); - if (response != null && response.getStatusCode() == 200) { - try { - String body = response.getBody(); - tags = parseCategory(body); - } catch (Exception e1) { - LogUtils.LOG.error("Request CardInfo exception", e1); - } + public static QuestionIndex getQuestionIndex(String titleSlug) { + if (questionAllCache.getIfPresent(URLUtils.getLeetcodeHost()) == null) { + return null; + } else if (!questionIndexCache.get(URLUtils.getLeetcodeHost()).containsKey(titleSlug)) { + return null; } else { - LogUtils.LOG.error("Request CardInfo failed, status:" + response.getStatusCode() + "body:" + response.getBody()); + QuestionIndex questionIndex = new QuestionIndex(); + questionIndex.setIndex(questionIndexCache.get(URLUtils.getLeetcodeHost()).get(titleSlug)); + questionIndex.setQuestionView(questionAllCache.getIfPresent(URLUtils.getLeetcodeHost()).get(questionIndex.getIndex())); + return questionIndex; } - return tags; } + private static List parseQuestion(String str, Boolean isPremium) { - private static List parseQuestion(String str, Boolean isPremium) { - - List questionList = new ArrayList(); + List questionList = new ArrayList<>(); if (StringUtils.isNotBlank(str)) { JSONObject jsonObject = JSONObject.parseObject(str).getJSONObject("data").getJSONObject("problemsetQuestionList"); JSONArray jsonArray = jsonObject.getJSONArray("questions"); for (int i = 0; i < jsonArray.size(); i++) { JSONObject object = jsonArray.getJSONObject(i); - Question question = parseOneQuestion(object, isPremium); + QuestionView question = parseQuestionView(object, isPremium); questionList.add(question); } } return questionList; } - private static Question parseOneQuestion(JSONObject object, Boolean isPremium) { - Question question = new Question(object.getString("title")); + private static QuestionView parseQuestionView(JSONObject object, Boolean isPremium) { + QuestionView question = new QuestionView(object.getString("title")); if (URLUtils.isCn() && !PersistentConfig.getInstance().getConfig().getEnglishContent()) { if (StringUtils.isNotBlank(object.getString("titleCn"))) { question.setTitle(object.getString("titleCn")); } } - question.setLeaf(Boolean.TRUE); question.setFrontendQuestionId(object.getString("frontendQuestionId")); question.setAcceptance(object.getDouble("acRate")); try { @@ -206,163 +162,41 @@ private static Question parseOneQuestion(JSONObject object, Boolean isPremium) { } question.setTitleSlug(object.getString("titleSlug")); question.setLevel(object.getString("difficulty")); - try { - if (object.containsKey("hasSolution")) { - if (object.getBoolean("hasSolution")) { - question.setArticleLive(Constant.ARTICLE_LIVE_ONE); - question.setArticleSlug(object.getString("titleSlug")); - question.setColumnArticles(1); - } else { - question.setArticleLive(Constant.ARTICLE_LIVE_NONE); - } - } else if (object.containsKey("solutionNum")) { - question.setArticleLive(Constant.ARTICLE_LIVE_LIST); - question.setColumnArticles(object.getInteger("solutionNum")); - } else { - question.setArticleLive(Constant.ARTICLE_LIVE_NONE); - } - } catch (Exception e) { - LogUtils.LOG.error("Identify abnormal article", e); - question.setArticleLive(Constant.ARTICLE_LIVE_NONE); - } return question; } - private static Question questionOfToday() { - try { - if (URLUtils.isCn()) { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(), "application/json"); - httpRequest.setBody("{\"query\":\"\\n query questionOfToday {\\n todayRecord {\\n date\\n userStatus\\n question {\\n" + - " questionId\\n frontendQuestionId: questionFrontendId\\n difficulty\\n title\\n titleCn: translatedTitle\\n" + - " titleSlug\\n paidOnly: isPaidOnly\\n freqBar\\n isFavor\\n acRate\\n status\\n solutionNum\\n " + - " hasVideoSolution\\n topicTags {\\n name\\n nameTranslated: translatedName\\n id\\n }\\n extra {\\n " + - " topCompanyTags {\\n imgUrl\\n slug\\n numSubscribed\\n }\\n }\\n }\\n lastSubmission {\\n" + - " id\\n }\\n }\\n}\\n \",\"variables\":{},\"operationName\":\"questionOfToday\"}"); - httpRequest.addHeader("Accept", "application/json"); - HttpResponse response = HttpRequestUtils.executePost(httpRequest); - if (response == null || response.getStatusCode() != 200) { - return null; - } else { - JSONObject jsonObject = JSONObject.parseObject(response.getBody()).getJSONObject("data").getJSONArray("todayRecord").getJSONObject(0); - Question question = parseOneQuestion(jsonObject.getJSONObject("question"), true); - question.setStatus("day"); - dayMap.put(URLUtils.getLeetcodeHost() + jsonObject.getString("date"), question); - return question; - } - } else { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(), "application/json"); - httpRequest.setBody("{\"query\":\"\\n query questionOfToday {\\n activeDailyCodingChallengeQuestion {\\n date\\n" + - " userStatus\\n link\\n question {\\n acRate\\n difficulty\\n freqBar\\n " + - "frontendQuestionId: questionFrontendId\\n isFavor\\n paidOnly: isPaidOnly\\n status\\n" + - " title\\n titleSlug\\n hasVideoSolution\\n hasSolution\\n topicTags {\\n " + - " name\\n id\\n slug\\n }\\n }\\n }\\n}\\n \",\"variables\":{},\"operationName\":\"questionOfToday\"}"); - httpRequest.addHeader("Accept", "application/json"); - HttpResponse response = HttpRequestUtils.executePost(httpRequest); - if (response == null || response.getStatusCode() != 200) { + public static QuestionView questionOfToday() { + QuestionView dayQuestion = dayMap.getIfPresent(URLUtils.getLeetcodeHost() + new SimpleDateFormat("yyyy-MM-dd").format(new Date())); + if (dayQuestion == null) { + try { + HttpResponse response = Graphql.builder().cn(URLUtils.isCn()).operationName("questionOfToday").request(); + if (response.getStatusCode() != 200) { return null; } else { - JSONObject jsonObject = JSONObject.parseObject(response.getBody()).getJSONObject("data").getJSONObject("activeDailyCodingChallengeQuestion"); - Question question = parseOneQuestion(jsonObject.getJSONObject("question"), true); - question.setStatus("day"); - dayMap.put(URLUtils.getLeetcodeHost() + jsonObject.getString("date"), question); - return question; - } - } - } catch (Exception e) { - return null; - } - } - - - private static List parseTag(String str) { - List tags = new ArrayList(); - - if (StringUtils.isNotBlank(str)) { - - JSONArray jsonArray = JSONObject.parseObject(str).getJSONArray("topics"); - for (int i = 0; i < jsonArray.size(); i++) { - JSONObject object = jsonArray.getJSONObject(i); - Tag tag = new Tag(); - tag.setSlug(object.getString("slug")); - String name = object.getString(URLUtils.getTagName()); - if (StringUtils.isBlank(name)) { - name = object.getString("name"); + JSONObject dateObject = JSONObject.parseObject(response.getBody()).getJSONObject("data"); + JSONObject todayRecordObject; + if (URLUtils.isCn()) { + todayRecordObject = dateObject.getJSONArray("activeDailyCodingChallengeQuestion").getJSONObject(0); + } else { + todayRecordObject = dateObject.getJSONObject("activeDailyCodingChallengeQuestion"); + } + dayQuestion = parseQuestionView(todayRecordObject.getJSONObject("question"), true); + dayQuestion.setStatus("day"); + dayMap.put(URLUtils.getLeetcodeHost() + todayRecordObject.getString("date"), dayQuestion); } - tag.setName(name); - tags.add(tag); - } - } - return tags; - } + } catch (Exception ignore) { - private static List parseCategory(String str) { - List tags = new ArrayList(); - - if (StringUtils.isNotBlank(str)) { - - JSONArray jsonArray = JSONArray.parseObject(str).getJSONObject("categories").getJSONArray("0"); - for (int i = 0; i < jsonArray.size(); i++) { - JSONObject object = jsonArray.getJSONObject(i); - Tag tag = new Tag(); - tag.setSlug(object.getString("slug")); - tag.setType(URLUtils.getLeetcodeUrl() + "/api" + object.getString("url").replace("problemset", "problems")); - tag.setName(object.getString("title")); - tags.add(tag); } } - return tags; - } - private static List parseList(String str) { - List tags = new ArrayList(); - - if (StringUtils.isNotBlank(str)) { - - JSONArray jsonArray = JSONArray.parseArray(str); - for (int i = 0; i < jsonArray.size(); i++) { - JSONObject object = jsonArray.getJSONObject(i); - Tag tag = new Tag(); - tag.setSlug(object.getString("id")); - tag.setType(object.getString("type")); - String name = object.getString("name"); - if (StringUtils.isBlank(name)) { - name = object.getString("name"); - } - tag.setName(name); - JSONArray questionArray = object.getJSONArray("questions"); - for (int j = 0; j < questionArray.size(); j++) { - tag.addQuestion(questionArray.getInteger(j).toString()); - } - tags.add(tag); - } - } - return tags; + return dayQuestion; } - public static boolean fillQuestion(Question question, CodeTypeEnum codeTypeEnum, Project project) { - if (Constant.NODETYPE_ITEM.equals(question.getNodeType())) { - ExploreManager.getItem(question); - if (StringUtils.isBlank(question.getTitleSlug())) { - MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("response.restrict")); - return false; - } else { - question.setNodeType(Constant.NODETYPE_DEF); - } - } - if (StringUtils.isBlank(question.getQuestionId())) { - return getQuestion(question, codeTypeEnum, project); - } - return true; - } - - private static boolean getQuestion(Question question, CodeTypeEnum codeTypeEnum, Project project) { + private static boolean getQuestion(Question question, Project project) { try { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(), "application/json"); - httpRequest.setBody("{\"operationName\":\"questionData\",\"variables\":{\"titleSlug\":\"" + question.getTitleSlug() + "\"},\"query\":\"query questionData($titleSlug: String!) {\\n question(titleSlug: $titleSlug) {\\n questionId\\n questionFrontendId\\n boundTopicId\\n title\\n titleSlug\\n content\\n translatedTitle\\n translatedContent\\n isPaidOnly\\n difficulty\\n likes\\n dislikes\\n isLiked\\n similarQuestions\\n contributors {\\n username\\n profileUrl\\n avatarUrl\\n __typename\\n }\\n langToValidPlayground\\n topicTags {\\n name\\n slug\\n translatedName\\n __typename\\n }\\n companyTagStats\\n codeSnippets {\\n lang\\n langSlug\\n code\\n __typename\\n }\\n stats\\n hints\\n solution {\\n id\\n canSeeDetail\\n __typename\\n }\\n status\\n sampleTestCase\\n metaData\\n judgerAvailable\\n judgeType\\n mysqlSchemas\\n enableRunCode\\n enableTestMode\\n envInfo\\n __typename\\n }\\n}\\n\"}"); - httpRequest.addHeader("Accept", "application/json"); - HttpResponse response = HttpRequestUtils.executePost(httpRequest); - if (response != null && response.getStatusCode() == 200) { + HttpResponse response = Graphql.builder().operationName("questionData").variables("titleSlug", question.getTitleSlug()).request(); + if (response.getStatusCode() == 200) { String body = response.getBody(); @@ -371,14 +205,14 @@ private static boolean getQuestion(Question question, CodeTypeEnum codeTypeEnum, question.setQuestionId(jsonObject.getString("questionId")); question.setContent(getContent(jsonObject)); question.setTestCase(jsonObject.getString("sampleTestCase")); - + question.setExampleTestcases(jsonObject.getString("exampleTestcases")); + question.setStatus(jsonObject.get("status") == null ? "" : jsonObject.getString("status")); question.setTitle(jsonObject.getString("title")); if (URLUtils.isCn() && !PersistentConfig.getInstance().getConfig().getEnglishContent()) { if (StringUtils.isNotBlank(jsonObject.getString("translatedTitle"))) { question.setTitle(jsonObject.getString("translatedTitle")); } } - question.setLeaf(Boolean.TRUE); question.setFrontendQuestionId(jsonObject.getString("questionFrontendId")); question.setLevel(jsonObject.getString("difficulty")); if (URLUtils.isCn()) { @@ -391,24 +225,17 @@ private static boolean getQuestion(Question question, CodeTypeEnum codeTypeEnum, } JSONArray jsonArray = jsonObject.getJSONArray("codeSnippets"); - if (jsonArray == null) { - question.setCode("Subscribe to unlock."); - } else if (codeTypeEnum != null) { + if (jsonArray != null) { + List codeSnippets = new ArrayList<>(); for (int i = 0; i < jsonArray.size(); i++) { JSONObject object = jsonArray.getJSONObject(i); - if (codeTypeEnum.getType().equals(object.getString("lang"))) { - question.setLangSlug(object.getString("langSlug")); - StringBuffer sb = new StringBuffer(); - sb.append(codeTypeEnum.getComment()).append(Constant.SUBMIT_REGION_BEGIN).append("\n"); - sb.append(object.getString("code").replaceAll("\\n", "\n")).append("\n"); - sb.append(codeTypeEnum.getComment()).append(Constant.SUBMIT_REGION_END).append("\n"); - question.setCode(sb.toString()); - break; - } - if (i == jsonArray.size() - 1) { - question.setCode(codeTypeEnum.getComment() + "There is no code of " + codeTypeEnum.getType() + " type for this problem"); - } + CodeSnippet codeSnippet = new CodeSnippet(); + codeSnippet.setCode(object.getString("code").replaceAll("\\n", "\n")); + codeSnippet.setLang(object.getString("lang")); + codeSnippet.setLangSlug(object.getString("langSlug")); + codeSnippets.add(codeSnippet); } + question.setCodeSnippets(codeSnippets); } return Boolean.TRUE; } else { @@ -423,8 +250,8 @@ private static boolean getQuestion(Question question, CodeTypeEnum codeTypeEnum, } private static String getContent(JSONObject jsonObject) { - StringBuffer sb = new StringBuffer(); - sb.append(jsonObject.getString(URLUtils.getDescContent())); + StringBuilder sb = new StringBuilder(); + sb.append(CleanMarkdown.cleanMarkdown(jsonObject.getString(URLUtils.getDescContent()), "")); Config config = PersistentConfig.getInstance().getConfig(); if (config.getShowTopics()) { JSONArray topicTagsArray = jsonObject.getJSONArray("topicTags"); @@ -444,30 +271,70 @@ private static String getContent(JSONObject jsonObject) { sb.append("
"); } } - sb.append("
  • \uD83D\uDC4D " + jsonObject.getInteger("likes") + "
  • \uD83D\uDC4E " + jsonObject.getInteger("dislikes") + "
  • "); + sb.append("
  • \uD83D\uDC4D ").append(jsonObject.getInteger("likes")).append("
  • \uD83D\uDC4E ").append(jsonObject.getInteger("dislikes")).append("
  • "); return sb.toString(); } - public static String pick() { + public static Question pick(Project project, PageInfo pageInfo) { String titleSlug = null; - if (URLUtils.isCn()) { - HttpRequest httpRequest = HttpRequest.get(URLUtils.getLeetcodeRandomOneQuestion()); - HttpResponse response = HttpRequestUtils.executeGet(httpRequest); - if (response != null && response.getStatusCode() == 200) { - String redirectsUrl = response.getUrl(); - String[] urls = redirectsUrl.split("/"); - titleSlug = urls[urls.length - 1]; + HttpResponse response = Graphql.builder().cn(URLUtils.isCn()).operationName("randomQuestion").variables("categorySlug", pageInfo.getCategorySlug()).variables("filters", pageInfo.getFilters()).request(); + if (response.getStatusCode() == 200) { + String body = response.getBody(); + if (URLUtils.isCn()) { + titleSlug = JSONObject.parseObject(body).getJSONObject("data").getString("randomQuestion"); + } else { + titleSlug = JSONObject.parseObject(body).getJSONObject("data").getJSONObject("randomQuestion").getString("titleSlug"); } + } + if (StringUtils.isNotBlank(titleSlug)) { + return getQuestionByTitleSlug(titleSlug, project); } else { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(), "application/json"); - httpRequest.setBody("{\"query\":\"\\n query randomQuestion($categorySlug: String, $filters: QuestionListFilterInput) {\\n randomQuestion(categorySlug: $categorySlug, filters: $filters) {\\n titleSlug\\n }\\n}\\n \",\"variables\":{\"categorySlug\":\"\",\"filters\":{}},\"operationName\":\"randomQuestion\"}"); - httpRequest.addHeader("Accept", "application/json"); - HttpResponse response = HttpRequestUtils.executePost(httpRequest); - if (response != null && response.getStatusCode() == 200) { - String body = response.getBody(); - titleSlug = JSONObject.parseObject(body).getJSONObject("data").getJSONObject("randomQuestion").getString("titleSlug"); + return null; + } + + } + + public static User getUser() { + HttpResponse response = Graphql.builder().cn(URLUtils.isCn()).operationName("userStatus").request(); + if (response.getStatusCode() == 200) { + JSONObject userObject = JSONObject.parseObject(response.getBody()).getJSONObject("data").getJSONObject("userStatus"); + User user = new User(); + user.setPremium(userObject.getBoolean("isPremium")); + user.setUsername(userObject.getString("username")); + user.setSignedIn(userObject.getBoolean("isSignedIn")); + user.setVerified(userObject.getBoolean("isVerified")); + user.setPhoneVerified(userObject.getBoolean("isPhoneVerified")); + return user; + } else { + LogUtils.LOG.error("Request userStatus failed, status:" + response.getStatusCode()); + return new User(); + } + } + + public static Question getQuestionByTitleSlug(String titleSlug, Project project) { + if (StringUtils.isBlank(titleSlug)) { + return null; + } + String key = URLUtils.getLeetcodeHost() + titleSlug; + if (questionCache.getIfPresent(key) == null) { + synchronized (key.intern()) { + if (questionCache.getIfPresent(key) == null) { + try { + Question question = new Question(); + question.setTitleSlug(titleSlug); + if (ApplicationManager.getApplication().executeOnPooledThread(() -> { + return getQuestion(question, project); + }).get()) { + questionCache.put(key, question); + } else { + return null; + } + } catch (Exception e) { + return null; + } + } } } - return titleSlug; + return questionCache.getIfPresent(key); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/manager/SessionManager.java b/src/main/java/com/shuzijun/leetcode/plugin/manager/SessionManager.java index aae1a152..9e9bda5b 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/manager/SessionManager.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/manager/SessionManager.java @@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.intellij.openapi.project.Project; +import com.shuzijun.leetcode.plugin.model.HttpRequest; import com.shuzijun.leetcode.plugin.model.Session; import com.shuzijun.leetcode.plugin.utils.*; @@ -16,9 +17,12 @@ public class SessionManager { public static List getSession(Project project) { + return getSession(project, false); + } + + public static List getSession(Project project, boolean cache) { List sessionList = new ArrayList<>(); - HttpRequest httpRequest = HttpRequest.get(URLUtils.getLeetcodeProgress()); - HttpResponse httpResponse = HttpRequestUtils.executeGet(httpRequest); + HttpResponse httpResponse = HttpRequest.builderGet(URLUtils.getLeetcodeProgress()).cache(cache).request(); if (httpResponse.getStatusCode() == 200) { Session defSession = new Session(); @@ -51,13 +55,10 @@ public static List getSession(Project project) { public static boolean switchSession(Project project, Integer id) { - HttpRequest httpRequest = HttpRequest.put(URLUtils.getLeetcodeSession(), "application/json"); - httpRequest.addHeader("Accept", "application/json, text/javascript, */*; q=0.01"); - httpRequest.addHeader("x-requested-with", "XMLHttpRequest"); - - httpRequest.setBody("{\"func\":\"activate\",\"target\":" + id + "}"); - - HttpResponse httpResponse = HttpRequestUtils.executePut(httpRequest); + HttpResponse httpResponse = HttpRequest.builderPut(URLUtils.getLeetcodeSession(), "application/json") + .addHeader("Accept", "application/json, text/javascript, */*; q=0.01") + .addHeader("x-requested-with", "XMLHttpRequest") + .body("{\"func\":\"activate\",\"target\":" + id + "}").request(); if (httpResponse.getStatusCode() == 200) { return true; } else { diff --git a/src/main/java/com/shuzijun/leetcode/plugin/manager/SubmissionManager.java b/src/main/java/com/shuzijun/leetcode/plugin/manager/SubmissionManager.java index 23ce7463..1a7e6674 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/manager/SubmissionManager.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/manager/SubmissionManager.java @@ -17,9 +17,9 @@ */ public class SubmissionManager { - public static List getSubmissionService(Question question, Project project) { + public static List getSubmissionService(String titleSlug, Project project) { - if (!HttpRequestUtils.isLogin()) { + if (!HttpRequestUtils.isLogin(project)) { MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("login.not")); return null; } @@ -27,10 +27,7 @@ public static List getSubmissionService(Question question, Project p List submissionList = new ArrayList(); try { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(), "application/json"); - httpRequest.setBody("{\"operationName\":\"Submissions\",\"variables\":{\"offset\":0,\"limit\":20,\"lastKey\":null,\"questionSlug\":\"" + question.getTitleSlug() + "\"},\"query\":\"query Submissions($offset: Int!, $limit: Int!, $lastKey: String, $questionSlug: String!) {\\n submissionList(offset: $offset, limit: $limit, lastKey: $lastKey, questionSlug: $questionSlug) {\\n lastKey\\n hasNext\\n submissions {\\n id\\n statusDisplay\\n lang\\n runtime\\n timestamp\\n url\\n isPending\\n memory\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}"); - httpRequest.addHeader("Accept", "application/json"); - HttpResponse response = HttpRequestUtils.executePost(httpRequest); + HttpResponse response = Graphql.builder().operationName("submissions").variables("offset", 0).variables("limit", 100).variables("questionSlug", titleSlug).request(); if (response != null && response.getStatusCode() == 200) { String body = response.getBody(); if (StringUtils.isNotBlank(body)) { @@ -47,9 +44,9 @@ public static List getSubmissionService(Question question, Project p submission.setMemory(object.getString("memory")); submissionList.add(submission); } - if (submissionList.size() == 0) { + /* if (submissionList.size() == 0) { MessageUtils.getInstance(project).showInfoMsg("info", PropertiesUtils.getInfo("submission.empty")); - } + }*/ } } else { MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("request.failed")); @@ -61,30 +58,34 @@ public static List getSubmissionService(Question question, Project p return submissionList; } - public static void openSubmission(Submission submission, Question question, Project project) { + public static File openSubmission(Submission submission, String titleSlug, Project project, Boolean isOpenEditor) { - if (!HttpRequestUtils.isLogin()) { + if (!HttpRequestUtils.isLogin(project)) { MessageUtils.getInstance(project).showWarnMsg("info", PropertiesUtils.getInfo("login.not")); - return; + return null; } Config config = PersistentConfig.getInstance().getInitConfig(); + Question question = QuestionManager.getQuestionByTitleSlug(titleSlug, project); CodeTypeEnum codeTypeEnum = CodeTypeEnum.getCodeTypeEnumByLangSlug(submission.getLang()); String filePath = PersistentConfig.getInstance().getTempFilePath() + Constant.DOC_SUBMISSION + VelocityUtils.convert(config.getCustomFileName(), question) + submission.getId() + ".txt"; File file = new File(filePath); if (file.exists()) { - FileUtils.openFileEditor(file, project); + if (isOpenEditor) { + FileUtils.openFileEditor(file, project); + } + return file; } else { try { JSONObject jsonObject; if (URLUtils.isCn()) { - jsonObject = loadSubmissionCn(submission,project); + jsonObject = loadSubmissionCn(submission, project); } else { - jsonObject = loadSubmissionEn(submission,project); + jsonObject = loadSubmissionEn(submission, project); } if (jsonObject == null) { - return; + return file; } StringBuffer sb = new StringBuffer(); @@ -121,23 +122,23 @@ public static void openSubmission(Submission submission, Question question, Proj } } FileUtils.saveFile(file, sb.toString()); - FileUtils.openFileEditor(file, project); - - + if (isOpenEditor) { + FileUtils.openFileEditor(file, project); + } + return file; } catch (Exception e) { LogUtils.LOG.error("获取提交详情失败", e); MessageUtils.getInstance(project).showWarnMsg("error", PropertiesUtils.getInfo("request.failed")); - return; + return file; } } } - private static JSONObject loadSubmissionEn(Submission submission,Project project) { - HttpRequest httpRequest = HttpRequest.get(URLUtils.getLeetcodeSubmissions() + submission.getId() + "/"); - HttpResponse response = HttpRequestUtils.executeGet(httpRequest); - if (response != null && response.getStatusCode() == 200) { + private static JSONObject loadSubmissionEn(Submission submission, Project project) { + HttpResponse response = HttpRequest.builderGet(URLUtils.getLeetcodeSubmissions() + submission.getId() + "/").request(); + if (response.getStatusCode() == 200) { String html = response.getBody(); String body = CommentUtils.createSubmissions(html); if (StringUtils.isBlank(body)) { @@ -158,11 +159,8 @@ private static JSONObject loadSubmissionEn(Submission submission,Project project return null; } - private static JSONObject loadSubmissionCn(Submission submission,Project project) { - HttpRequest httpRequest = HttpRequest.post(URLUtils.getLeetcodeGraphql(), "application/json"); - httpRequest.setBody("{\"operationName\":\"mySubmissionDetail\",\"variables\":{\"id\":\"" + submission.getId() + "\"},\"query\":\"query mySubmissionDetail($id: ID!) {\\n submissionDetail(submissionId: $id) {\\n id\\n code\\n runtime\\n memory\\n statusDisplay\\n timestamp\\n lang\\n passedTestCaseCnt\\n totalTestCaseCnt\\n sourceUrl\\n question {\\n titleSlug\\n title\\n translatedTitle\\n questionId\\n __typename\\n }\\n ... on GeneralSubmissionNode {\\n outputDetail {\\n codeOutput\\n expectedOutput\\n input\\n compileError\\n runtimeError\\n lastTestcase\\n __typename\\n }\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}"); - httpRequest.addHeader("Accept", "application/json"); - HttpResponse response = HttpRequestUtils.executePost(httpRequest); + private static JSONObject loadSubmissionCn(Submission submission, Project project) { + HttpResponse response = Graphql.builder().cn(URLUtils.isCn()).operationName("submissionDetail").variables("id", submission.getId()).request(); if (response != null && response.getStatusCode() == 200) { String body = response.getBody(); if (StringUtils.isNotBlank(body)) { diff --git a/src/main/java/com/shuzijun/leetcode/plugin/manager/ViewManager.java b/src/main/java/com/shuzijun/leetcode/plugin/manager/ViewManager.java index 3a595612..f7cf01ea 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/manager/ViewManager.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/manager/ViewManager.java @@ -1,123 +1,158 @@ package com.shuzijun.leetcode.plugin.manager; -import com.google.common.collect.Maps; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.shuzijun.leetcode.plugin.model.*; import com.shuzijun.leetcode.plugin.utils.MessageUtils; import com.shuzijun.leetcode.plugin.utils.PropertiesUtils; -import com.shuzijun.leetcode.plugin.utils.URLUtils; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.stream.Collectors; /** * @author shuzijun */ public class ViewManager { - private static Map questions = Maps.newLinkedHashMap(); - - private static Map> filter = Maps.newLinkedHashMap(); - - private static Map sortMap = Maps.newLinkedHashMap(); - - static { - sortMap.put(Constant.SORT_TYPE_TITLE, new Sort(Constant.SORT_TYPE_TITLE, "FRONTEND_ID")); - sortMap.put(Constant.SORT_TYPE_SOLUTION, new Sort(Constant.SORT_TYPE_SOLUTION, "SOLUTION_NUM")); - sortMap.put(Constant.SORT_TYPE_ACCEPTANCE, new Sort(Constant.SORT_TYPE_ACCEPTANCE, "AC_RATE")); - sortMap.put(Constant.SORT_TYPE_DIFFICULTY, new Sort(Constant.SORT_TYPE_DIFFICULTY, "DIFFICULTY")); - sortMap.put(Constant.SORT_TYPE_FREQUENCY, new Sort(Constant.SORT_TYPE_FREQUENCY, "FREQUENCY")); + public static void loadServiceData(NavigatorAction navigatorAction, Project project) { + loadServiceData(navigatorAction, project, null); } - - public static void loadServiceData(NavigatorTable navigatorTable, Project project) { - PageInfo pageInfo = QuestionManager.getQuestionService(project, navigatorTable.getPageInfo()); + public static void loadServiceData(NavigatorAction navigatorAction, Project project, String selectTitleSlug) { + QuestionManager.getQuestionAllService(project, false); + PageInfo pageInfo = QuestionManager.getQuestionViewList(project, navigatorAction.getPageInfo()); if ((pageInfo.getRows() == null || pageInfo.getRows().isEmpty()) && pageInfo.getRowTotal() != 0) { MessageUtils.getInstance(project).showErrorMsg("error", PropertiesUtils.getInfo("response.question")); return; } - if (filter.isEmpty()) { - filter.put(Constant.FIND_TYPE_CATEGORY, QuestionManager.getCategory()); - filter.put(Constant.FIND_TYPE_DIFFICULTY, QuestionManager.getDifficulty()); - filter.put(Constant.FIND_TYPE_STATUS, QuestionManager.getStatus()); - filter.put(Constant.FIND_TYPE_TAGS, QuestionManager.getTags()); - } - if (CollectionUtils.isNotEmpty(filter.get(Constant.FIND_TYPE_LISTS))) { - Map oldListsMap = Maps.uniqueIndex(filter.get(Constant.FIND_TYPE_LISTS), tag -> tag.getSlug()); - List newLists = QuestionManager.getLists(); - Map newListsMap = Maps.uniqueIndex(newLists, tag -> tag.getSlug()); - newListsMap.forEach((s, tag) -> { - if (oldListsMap.containsKey(s)) { - tag.setSelect(oldListsMap.get(s).isSelect()); - } + if (navigatorAction.getFind().getFilter().isEmpty()) { + ApplicationManager.getApplication().executeOnPooledThread(() -> { + navigatorAction.getFind().addFilter(Constant.FIND_TYPE_CATEGORY, FindManager.getCategory()); + navigatorAction.getFind().addFilter(Constant.FIND_TYPE_DIFFICULTY, FindManager.getDifficulty()); + navigatorAction.getFind().addFilter(Constant.FIND_TYPE_STATUS, FindManager.getStatus()); + navigatorAction.getFind().addFilter(Constant.FIND_TYPE_TAGS, FindManager.getTags()); + navigatorAction.getFind().addFilter(Constant.FIND_TYPE_LISTS, FindManager.getLists(project)); }); - filter.put(Constant.FIND_TYPE_LISTS, newLists); - } else { - filter.put(Constant.FIND_TYPE_LISTS, QuestionManager.getLists()); } + navigatorAction.loadData(selectTitleSlug); + } - navigatorTable.loadData(pageInfo); + public static void pick(Project project, PageInfo pageInfo) { + Question question = QuestionManager.pick(project, pageInfo); + if (question != null) { + CodeManager.openCode(question.getTitleSlug(), project); + } } - public static List getFilter(String key) { - return filter.get(key); + public static void loadAllServiceData(NavigatorAction navigatorAction, Project project) { + loadAllServiceData(navigatorAction, project, null, false); } - public static void clearFilter() { - for (String key : filter.keySet()) { - List tagList = filter.get(key); - for (Tag tag : tagList) { - tag.setSelect(Boolean.FALSE); - } + public static void loadAllServiceData(NavigatorAction navigatorAction, Project project, String selectTitleSlug, boolean reset) { + List questionViews = QuestionManager.getQuestionAllService(project, reset); + if (CollectionUtils.isEmpty(questionViews)) { + MessageUtils.getInstance(project).showErrorMsg("error", PropertiesUtils.getInfo("response.question")); + return; } - } - public static Question getQuestionByTitleSlug(String titleSlug, CodeTypeEnum codeTypeEnum, Project project) { - if (StringUtils.isBlank(titleSlug)) { - return null; + if (navigatorAction.getFind().getFilter().isEmpty()) { + navigatorAction.getFind().addFilter(Constant.FIND_TYPE_CATEGORY, FindManager.getCategory()); + navigatorAction.getFind().addFilter(Constant.FIND_TYPE_DIFFICULTY, FindManager.getDifficulty()); + navigatorAction.getFind().addFilter(Constant.FIND_TYPE_STATUS, FindManager.getStatus()); + navigatorAction.getFind().addFilter(Constant.FIND_TYPE_TAGS, FindManager.getTags()); + navigatorAction.getFind().addFilter(Constant.FIND_TYPE_LISTS, FindManager.getLists(project)); } - String key = URLUtils.getLeetcodeHost() + titleSlug; - if (!questions.containsKey(key)) { - Question question = new Question(); - question.setTitleSlug(titleSlug); - if (QuestionManager.fillQuestion(question, codeTypeEnum, project)) { - questions.put(key, question); - } else { - return null; + + Set conformSet = questionViews.stream().map(QuestionView::getQuestionId).collect(Collectors.toSet()); + PageInfo pageInfo = navigatorAction.getPageInfo(); + PageInfo.Filters filters = pageInfo.getFilters(); + if (StringUtils.isNotBlank(filters.getListId())) { + List tagList = navigatorAction.getFind().getFilter(Constant.FIND_TYPE_LISTS); + Tag tag = tagList.stream().filter(t -> t.getSlug().equalsIgnoreCase(filters.getListId())).findAny().get(); + conformSet.retainAll(tag.getQuestions()); + } + if (CollectionUtils.isNotEmpty(filters.getTags())) { + List tagList = navigatorAction.getFind().getFilter(Constant.FIND_TYPE_TAGS); + Set tagQuestions = new HashSet<>(); + Set tagSlugs = filters.getTags().stream().collect(Collectors.toSet()); + for (Tag tag : tagList) { + if (tagSlugs.contains(tag.getSlug())) { + tagQuestions.addAll(tag.getQuestions()); + } } + conformSet.retainAll(tagQuestions); } - return questions.get(key); - } - public static Question getCaCheQuestionByTitleSlug(String titleSlug, CodeTypeEnum codeTypeEnum, Project project) { - String key = URLUtils.getLeetcodeHost() + titleSlug; - return questions.get(key); - } + boolean category = StringUtils.isNotBlank(pageInfo.getCategorySlug()); + boolean searchKeywords = StringUtils.isNotBlank(filters.getSearchKeywords()); + boolean difficulty = StringUtils.isNotBlank(filters.getDifficulty()); + boolean status = StringUtils.isNotBlank(filters.getStatus()); - public static void pick(CodeTypeEnum codeTypeEnum, Project project) { - String titleSlug = QuestionManager.pick(); - Question question = getQuestionByTitleSlug(titleSlug, codeTypeEnum, project); - if (question != null) { - CodeManager.openCode(question, project); + List conformList = new ArrayList<>(); + QuestionView dayQuestion = QuestionManager.questionOfToday(); + if (dayQuestion != null) { + conformList.add(dayQuestion); + } + for (QuestionView questionView : questionViews) { + if (!conformSet.contains(questionView.getQuestionId())) { + continue; + } + if (category && !questionView.getCategory().equalsIgnoreCase(pageInfo.getCategorySlug())) { + continue; + } + if (searchKeywords && !(questionView.getFrontendQuestionId().startsWith(filters.getSearchKeywords()) + || questionView.getTitle().contains(filters.getSearchKeywords()) || questionView.getTitleSlug().contains(filters.getSearchKeywords()))) { + continue; + } + if (difficulty) { + List difficultyList = FindManager.getDifficulty().stream().map(t -> t.getSlug()).collect(Collectors.toList()); + Integer level = difficultyList.indexOf(filters.getDifficulty()) + 1; + if (!questionView.getLevel().equals(level)) { + continue; + } + } + if (status) { + if ("TRIED".equalsIgnoreCase(filters.getStatus()) && !questionView.getStatusSign().equalsIgnoreCase("❓")) { + continue; + } else if ("AC".equalsIgnoreCase(filters.getStatus()) && !questionView.getStatusSign().equalsIgnoreCase("✔")) { + continue; + } else if ("NOT_STARTED".equalsIgnoreCase(filters.getStatus()) && !(questionView.getStatusSign().equalsIgnoreCase("$") || StringUtils.isBlank(questionView.getStatusSign()))) { + continue; + } + } + conformList.add(questionView); } - } - public static Sort getSort(String key) { - return sortMap.get(key); - } + if (StringUtils.isNotBlank(filters.getOrderBy())) { + int order = "DESCENDING".equalsIgnoreCase(filters.getSortOrder()) ? -1 : 1; + Collections.sort(conformList, new Comparator() { + @Override + public int compare(QuestionView o1, QuestionView o2) { + if ("day".equalsIgnoreCase(o1.getStatus())) { + return 1; + } else if ("day".equalsIgnoreCase(o2.getStatus())) { + return -1; + } + if ("TITLE".equalsIgnoreCase(filters.getOrderBy())) { + return order * o1.getTitle().compareTo(o2.getTitle()); + } + if ("DIFFICULTY".equalsIgnoreCase(filters.getOrderBy())) { + return order * o1.getLevel().compareTo(o2.getLevel()); + } + if ("STATES".equalsIgnoreCase(filters.getOrderBy())) { + return order * o1.getStatusSign().compareTo(o2.getStatusSign()); + } + return order * o1.getFrontendQuestionId().compareTo(o2.getFrontendQuestionId()); + } + }); + } - public static void operationType(String key) { - sortMap.forEach((s, sort) -> { - if (!s.equals(key)) { - sort.resetType(); - } else { - sort.operationType(); - } - }); + navigatorAction.getPageInfo().setRows(conformList); + navigatorAction.getPageInfo().setRowTotal(conformList.size()); + navigatorAction.loadData(selectTitleSlug); } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/model/CodeSnippet.java b/src/main/java/com/shuzijun/leetcode/plugin/model/CodeSnippet.java new file mode 100644 index 00000000..3d3d6781 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/model/CodeSnippet.java @@ -0,0 +1,37 @@ +package com.shuzijun.leetcode.plugin.model; + +/** + * @author shuzijun + */ +public class CodeSnippet { + + private String code; + + private String lang; + + private String langSlug; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getLang() { + return lang; + } + + public void setLang(String lang) { + this.lang = lang; + } + + public String getLangSlug() { + return langSlug; + } + + public void setLangSlug(String langSlug) { + this.langSlug = langSlug; + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/model/CodeTopQuestionView.java b/src/main/java/com/shuzijun/leetcode/plugin/model/CodeTopQuestionView.java new file mode 100644 index 00000000..4d11f55e --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/model/CodeTopQuestionView.java @@ -0,0 +1,27 @@ +package com.shuzijun.leetcode.plugin.model; + +/** + * @author shuzijun + */ +public class CodeTopQuestionView extends QuestionView { + + private String inspectTime; + + private Integer inspectFrequency; + + public String getInspectTime() { + return inspectTime; + } + + public void setInspectTime(String inspectTime) { + this.inspectTime = inspectTime; + } + + public Integer getInspectFrequency() { + return inspectFrequency; + } + + public void setInspectFrequency(Integer inspectFrequency) { + this.inspectFrequency = inspectFrequency; + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/model/CodeTypeEnum.java b/src/main/java/com/shuzijun/leetcode/plugin/model/CodeTypeEnum.java index 1a4d68cd..0f0a258d 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/model/CodeTypeEnum.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/model/CodeTypeEnum.java @@ -57,6 +57,10 @@ public String getType() { return type; } + public String getLangSlug() { + return langSlug; + } + public String getSuffix() { return suffix; } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/model/Config.java b/src/main/java/com/shuzijun/leetcode/plugin/model/Config.java index 0ce8a6e4..3d182542 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/model/Config.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/model/Config.java @@ -1,15 +1,19 @@ package com.shuzijun.leetcode.plugin.model; +import com.intellij.openapi.project.Project; import com.intellij.util.xmlb.annotations.Transient; +import com.shuzijun.leetcode.plugin.utils.MessageUtils; +import com.shuzijun.leetcode.plugin.utils.PropertiesUtils; +import org.apache.commons.lang3.builder.EqualsBuilder; import java.awt.*; -import java.util.*; -import java.util.List; +import java.util.HashMap; +import java.util.Map; /** * @author shuzijun */ -public class Config { +public class Config implements Cloneable { private Integer version; @@ -84,14 +88,14 @@ public class Config { private String levelColour = Constant.LEVEL_COLOUR; /** - * 使用jcef渲染 + * 使用cookie登录 */ - private Boolean jcef = false; + private boolean cookie = false; /** * question Split Editor */ - private Boolean questionEditor = true; + private String questionEditor = "Left"; /** * Content Multiline Comment @@ -113,7 +117,20 @@ public class Config { */ private Boolean showToolIcon = true; - private List favoriteList; + /** + * convergeEditor + */ + private Boolean convergeEditor = true; + + /** + * 使用的导航 + */ + private String navigatorName; + + /** + * 显示编辑器标志 + */ + private boolean showQuestionEditorSign = true; public String getId() { return id; @@ -151,6 +168,14 @@ public String getCodeType() { return codeType; } + public CodeTypeEnum getCodeTypeEnum(Project project) { + CodeTypeEnum codeTypeEnum = CodeTypeEnum.getCodeTypeEnum(codeType); + if (codeTypeEnum == null) { + MessageUtils.getInstance(project).showWarnMsg("", PropertiesUtils.getInfo("config.code")); + } + return codeTypeEnum; + } + public void setCodeType(String codeType) { this.codeType = codeType; } @@ -227,18 +252,6 @@ public void setUserCookie(Map userCookie) { this.userCookie = userCookie; } - public List getFavoriteList() { - if (favoriteList == null || favoriteList.isEmpty()) { - favoriteList = new ArrayList<>(); - favoriteList.add("Favorite"); - } - return favoriteList; - } - - public void setFavoriteList(List favoriteList) { - this.favoriteList = favoriteList; - } - public String getAlias() { if ("leetcode.com".equals(getUrl())) { return "en"; @@ -261,6 +274,7 @@ public String getCookie(String user) { public String getLevelColour() { return levelColour; } + @Transient public Color[] getFormatLevelColour() { Color[] formatColors = new Color[3]; @@ -290,16 +304,16 @@ public Color[] getFormatLevelColour() { } public void setLevelColour(String levelColour) { - if(levelColour ==null || levelColour.isEmpty()){ + if (levelColour == null || levelColour.isEmpty()) { this.levelColour = Constant.LEVEL_COLOUR; - }else { + } else { this.levelColour = levelColour; } } @Transient public void setFormatLevelColour(Color... colors) { - String levelColour = ""; + StringBuilder levelColour = new StringBuilder(); if (colors != null && colors.length > 0) { for (Color color : colors) { String R = Integer.toHexString(color.getRed()); @@ -309,10 +323,10 @@ public void setFormatLevelColour(Color... colors) { String B = Integer.toHexString(color.getBlue()); B = B.length() < 2 ? ('0' + B) : B; - levelColour = levelColour + '#' + R + G + B + ";"; + levelColour.append('#').append(R).append(G).append(B).append(";"); } } - this.levelColour = levelColour; + this.levelColour = levelColour.toString(); } public Boolean getEnglishContent() { @@ -323,19 +337,29 @@ public void setEnglishContent(Boolean englishContent) { this.englishContent = englishContent; } - public Boolean getJcef() { - return jcef; + public boolean isCookie() { + return cookie; + } + + public void setCookie(boolean cookie) { + this.cookie = cookie; + } + + @Transient + public Boolean isQuestionEditor() { + return !"Disable".equals(questionEditor) && !"false".equals(questionEditor); } - public void setJcef(Boolean jcef) { - this.jcef = jcef; + @Transient + public Boolean isLeftQuestionEditor() { + return "Left".equals(questionEditor) || "true".equals(questionEditor) || !isQuestionEditor(); } - public Boolean getQuestionEditor() { + public String getQuestionEditor() { return questionEditor; } - public void setQuestionEditor(Boolean questionEditor) { + public void setQuestionEditor(String questionEditor) { this.questionEditor = questionEditor; } @@ -371,37 +395,67 @@ public void setShowToolIcon(Boolean showToolIcon) { this.showToolIcon = showToolIcon; } - public boolean isModified(Config config){ - if(config ==null){ - return false; - } - if (!Objects.equals(loginName, config.loginName)) return false; - if (!Objects.equals(filePath, config.filePath)) return false; - if (!Objects.equals(codeType, config.codeType)) return false; - if (!Objects.equals(url, config.url)) return false; - if (!Objects.equals(update, config.update)) return false; - if (!Objects.equals(proxy, config.proxy)) return false; - if (!Objects.equals(customCode, config.customCode)) return false; - if (!Objects.equals(englishContent, config.englishContent)) - return false; - if (!Objects.equals(customFileName, config.customFileName)) - return false; - if (!Objects.equals(customTemplate, config.customTemplate)) - return false; - if (!Objects.equals(jcef, config.jcef)) - return false; - if (!Objects.equals(questionEditor, config.questionEditor)) - return false; - if (!Objects.equals(multilineComment, config.multilineComment)) - return false; - if (!Objects.equals(htmlContent, config.htmlContent)) - return false; - if (!Objects.equals(showTopics, config.showTopics)) - return false; - if (!Objects.equals(showToolIcon, config.showToolIcon)) - return false; - return Objects.equals(levelColour, config.levelColour); + public Boolean getConvergeEditor() { + return convergeEditor; } + public void setConvergeEditor(Boolean convergeEditor) { + this.convergeEditor = convergeEditor; + } + + public String getNavigatorName() { + return navigatorName; + } + public void setNavigatorName(String navigatorName) { + this.navigatorName = navigatorName; + } + + public boolean isShowQuestionEditorSign() { + return showQuestionEditorSign; + } + + public void setShowQuestionEditorSign(boolean showQuestionEditorSign) { + this.showQuestionEditorSign = showQuestionEditorSign; + } + + public boolean isModified(Config config) { + + if (config == null) { + return false; + } + + return new EqualsBuilder() + .append(showQuestionEditorSign, config.showQuestionEditorSign) + .append(loginName, config.loginName) + .append(filePath, config.filePath) + .append(codeType, config.codeType) + .append(url, config.url) + .append(update, config.update) + .append(proxy, config.proxy) + .append(customCode, config.customCode) + .append(englishContent, config.englishContent) + .append(customFileName, config.customFileName) + .append(customTemplate, config.customTemplate) + .append(levelColour, config.levelColour) + .append(cookie, config.cookie) + .append(questionEditor, config.questionEditor) + .append(multilineComment, config.multilineComment) + .append(htmlContent, config.htmlContent) + .append(showTopics, config.showTopics) + .append(showToolIcon, config.showToolIcon) + .append(convergeEditor, config.convergeEditor) + .isEquals(); + } + + + @Override + public Config clone() { + Config config = null; + try { + config = (Config) super.clone(); + } catch (CloneNotSupportedException ignore) { + } + return config; + } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/model/Constant.java b/src/main/java/com/shuzijun/leetcode/plugin/model/Constant.java index 99b8584a..94421572 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/model/Constant.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/model/Constant.java @@ -103,6 +103,8 @@ public class Constant { public static final String SORT_TYPE_DIFFICULTY = "SortByDifficulty"; public static final String SORT_TYPE_FREQUENCY = "SortByFrequency"; + public static final String SORT_TYPE_STATES = "SortByStates"; + /** * path */ @@ -113,4 +115,18 @@ public class Constant { public static final String DOC_NOTE = "doc"+ File.separator + "note" + File.separator; + /** + * CodeTop类别类型 + */ + public static final String CODETOP_FIND_TYPE_DIFFICULTY = "Difficulty"; + public static final String CODETOP_FIND_TYPE_TAGS = "Tags"; + public static final String CODETOP_FIND_TYPE_COMPANY = "Company"; + /** + * CodeTop排序类别 + */ + public static final String CODETOP_SORT_TYPE_TITLE = "CodeTopSortByTitle"; + public static final String CODETOP_SORT_TYPE_TIME = "CodeTopSortByTime"; + public static final String CODETOP_SORT_TYPE_FREQUENCY = "CodeTopSortByFrequency"; + + } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/model/Find.java b/src/main/java/com/shuzijun/leetcode/plugin/model/Find.java new file mode 100644 index 00000000..b3188929 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/model/Find.java @@ -0,0 +1,85 @@ +package com.shuzijun.leetcode.plugin.model; + +import com.google.common.collect.Maps; +import org.apache.commons.collections.CollectionUtils; + +import java.util.List; +import java.util.Map; + +/** + * @author shuzijun + */ +public class Find { + + private Map> filter = Maps.newConcurrentMap(); + + private Map sortMap = Maps.newConcurrentMap(); + + + public Map> getFilter() { + + return filter; + } + + public Map getSortMap() { + + return sortMap; + } + + public void addFilter(String key, List tags) { + filter.put(key.toLowerCase(), tags); + } + + public void addSort(String key, Sort sort) { + sortMap.put(key.toLowerCase(), sort); + } + + public List getFilter(String key) { + if (key == null) { + return null; + } + return filter.get(key.toLowerCase()); + } + + public void clearFilter() { + for (String key : filter.keySet()) { + List tagList = filter.get(key); + for (Tag tag : tagList) { + tag.setSelect(Boolean.FALSE); + } + } + + } + + public Sort getSort(String key) { + if (key == null) { + return null; + } + return sortMap.get(key.toLowerCase()); + } + + public void operationType(String key) { + sortMap.forEach((s, sort) -> { + if (!s.equalsIgnoreCase(key)) { + sort.resetType(); + } else { + sort.operationType(); + } + }); + + } + + public void resetFilterData(String key, List tags) { + if (CollectionUtils.isNotEmpty(getFilter(key))) { + Map oldListsMap = Maps.uniqueIndex(getFilter(key), tag -> tag.getSlug()); + Map newListsMap = Maps.uniqueIndex(tags, tag -> tag.getSlug()); + newListsMap.forEach((s, tag) -> { + if (oldListsMap.containsKey(s)) { + tag.setSelect(oldListsMap.get(s).isSelect()); + } + }); + addFilter(key, tags); + } + } + +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/model/Graphql.java b/src/main/java/com/shuzijun/leetcode/plugin/model/Graphql.java new file mode 100644 index 00000000..b0a15508 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/model/Graphql.java @@ -0,0 +1,140 @@ +package com.shuzijun.leetcode.plugin.model; + +import com.alibaba.fastjson.JSONObject; +import com.intellij.openapi.util.io.FileUtilRt; +import com.shuzijun.leetcode.plugin.utils.*; +import org.apache.commons.collections.map.HashedMap; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +/** + * @author shuzijun + */ +public class Graphql { + + private String operationName; + + private Map variables; + + private String query; + + private Graphql(String operationName, Map variables, String query) { + this.operationName = operationName; + this.variables = variables; + this.query = query; + } + + public String getOperationName() { + return operationName; + } + + public Map getVariables() { + return variables; + } + + public String getQuery() { + return query; + } + + public String generate() { + return JSONObject.toJSONString(this); + } + + public static GraphqlBuilder builder() { + return new GraphqlBuilder(); + } + + public static class GraphqlBuilder { + + private static final String PATH = "/graphql/"; + + private static final String CNSUFFIX = "_cn.graphql"; + + private String url = URLUtils.getLeetcodeGraphql(); + + private String operationName; + + private Map variables = new HashedMap(); + + private String query; + + private String suffix = ".graphql"; + + private boolean cache = false; + + private String cacheParam; + + private GraphqlBuilder() { + + } + + public GraphqlBuilder url(String url) { + this.url = url; + return this; + } + + public GraphqlBuilder cn(boolean isCn) { + if (isCn) { + this.suffix = CNSUFFIX; + } + return this; + } + + public GraphqlBuilder operationName(String operationName) { + this.operationName = operationName; + this.query(operationName); + return this; + } + + public GraphqlBuilder operationName(String operationName, String operationNameAlias) { + this.operationName = operationNameAlias; + this.query(operationName); + return this; + } + + private GraphqlBuilder query(String operationName) { + try (InputStream inputStream = GraphqlBuilder.class.getResourceAsStream(PATH + operationName + suffix)) { + if (inputStream == null) { + LogUtils.LOG.error(PATH + operationName + suffix + " Path is empty"); + } else { + this.query = new String(FileUtilRt.loadBytes(inputStream)); + } + } catch (IOException e) { + LogUtils.LOG.error(PATH + operationName + suffix + " Loading exception", e); + } + return this; + } + + public GraphqlBuilder variables(String key, Object value) { + variables.put(key, value); + return this; + } + + public GraphqlBuilder cache(boolean cache) { + this.cache = cache; + return this; + } + + public GraphqlBuilder cacheParam(String cacheParam) { + this.cacheParam = cacheParam; + this.cache = true; + return this; + } + + public Graphql build() { + return new Graphql(operationName, variables, query); + } + + @NotNull + public HttpResponse request() { + return HttpRequest.builderPost(url, "application/json") + .body(build().generate()) + .addHeader("Accept", "application/json") + .cache(cache).cacheParam(cacheParam).request(); + } + } + +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/model/HttpRequest.java b/src/main/java/com/shuzijun/leetcode/plugin/model/HttpRequest.java new file mode 100644 index 00000000..12f872aa --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/model/HttpRequest.java @@ -0,0 +1,179 @@ +package com.shuzijun.leetcode.plugin.model; + +import com.shuzijun.leetcode.plugin.utils.HttpRequestUtils; +import com.shuzijun.leetcode.plugin.utils.HttpResponse; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author shuzijun + */ +public class HttpRequest { + + private String url; + + private String body; + /** + * POST + */ + private String contentType; + + private Map header; + + private boolean cache; + + private String cacheParam; + + private HttpRequest(String url, String body, String contentType, Map header, boolean cache, String cacheParam) { + this.url = url; + this.body = body; + this.contentType = contentType; + this.header = header; + this.cache = cache; + this.cacheParam = cacheParam; + } + + public String getUrl() { + return url; + } + + public String getBody() { + return body; + } + + public String getContentType() { + return contentType; + } + + public Map getHeader() { + return header; + } + + public boolean isCache() { + return cache; + } + + public String getCacheParam() { + return cacheParam; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + + if (o == null || getClass() != o.getClass()) return false; + + HttpRequest that = (HttpRequest) o; + + return new EqualsBuilder().append(url, that.url).append(body, that.body).append(contentType, that.contentType).append(header, that.header).append(cacheParam, that.cacheParam).isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37).append(url).append(body).append(contentType).append(header).append(cacheParam).toHashCode(); + } + + public static HttpRequest.HttpRequestBuilder builderGet(String url) { + return new HttpRequest.HttpRequestBuilder().get(url); + } + + public static HttpRequest.HttpRequestBuilder builderPost(String url, String contentType) { + return new HttpRequest.HttpRequestBuilder().post(url, contentType); + } + + public static HttpRequest.HttpRequestBuilder builderPut(String url, String contentType) { + return new HttpRequest.HttpRequestBuilder().put(url, contentType); + } + + public static class HttpRequestBuilder { + private String url; + + private String body; + /** + * POST + */ + private String contentType; + + private Type type; + + private Map header = new HashMap<>(); + + private boolean cache = false; + + private String cacheParam; + + private HttpRequestBuilder() { + + } + + private HttpRequestBuilder get(String url) { + this.url = url; + this.type = Type.GET; + return this; + } + + private HttpRequestBuilder post(String url, String contentType) { + this.url = url; + this.contentType = contentType; + this.type = Type.POST; + return this; + } + + private HttpRequestBuilder put(String url, String contentType) { + this.url = url; + this.contentType = contentType; + this.type = Type.PUT; + return this; + } + + public HttpRequestBuilder body(String body) { + this.body = body; + return this; + } + + public HttpRequestBuilder addHeader(String name, String value) { + this.header.put(name, value); + return this; + } + + public HttpRequestBuilder cache(boolean cache) { + this.cache = cache; + return this; + } + + public HttpRequestBuilder cacheParam(String cacheParam) { + this.cacheParam = cacheParam; + this.cache = true; + return this; + } + + public HttpRequest build() { + return new HttpRequest(url, body, contentType, header, cache, cacheParam); + } + + @NotNull + public HttpResponse request() { + HttpRequest httpRequest = build(); + switch (type) { + case GET: + return HttpRequestUtils.executeGet(httpRequest); + case POST: + return HttpRequestUtils.executePost(httpRequest); + case PUT: + return HttpRequestUtils.executePut(httpRequest); + default: + throw new RuntimeException("Type not supported"); + } + + } + + } + + private enum Type { + GET, POST, PUT; + } +} \ No newline at end of file diff --git a/src/main/java/com/shuzijun/leetcode/plugin/model/PageInfo.java b/src/main/java/com/shuzijun/leetcode/plugin/model/PageInfo.java index 70f957dc..c5902cb5 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/model/PageInfo.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/model/PageInfo.java @@ -1,7 +1,8 @@ package com.shuzijun.leetcode.plugin.model; import com.alibaba.fastjson.JSON; -import com.shuzijun.leetcode.plugin.manager.ViewManager; +import com.alibaba.fastjson.annotation.JSONField; +import org.apache.commons.lang.StringUtils; import java.lang.reflect.Field; import java.util.ArrayList; @@ -13,7 +14,7 @@ public class PageInfo { private int pageIndex; - public int pageSize; + private int pageSize; private int rowTotal; private String categorySlug = ""; @@ -90,7 +91,7 @@ public Filters getFilters() { public void disposeFilters(String key, String value, boolean select) { Field[] fields = filters.getClass().getDeclaredFields(); for (Field field : fields) { - if (field.getName().equals(key)) { + if (field.getName().equalsIgnoreCase(key)) { field.setAccessible(true); try { if (List.class.isAssignableFrom(field.getType())) { @@ -121,15 +122,16 @@ public void clear() { this.pageIndex = 1; this.categorySlug = ""; this.filters.clear(); - ViewManager.clearFilter(); - ViewManager.operationType(""); } public void clearFilter() { this.pageIndex = 1; this.categorySlug = ""; this.filters.clearFilter(); - ViewManager.clearFilter(); + } + + public boolean isNoFilter() { + return StringUtils.isBlank(categorySlug) && filters.isNoFilter(); } public static class Filters { @@ -212,6 +214,28 @@ public void clearFilter() { this.listId = null; this.tags = null; } + @JSONField(serialize = false) + public boolean isNoFilter() { + Field[] fields = this.getClass().getDeclaredFields(); + for (Field field : fields) { + field.setAccessible(true); + try { + if (List.class.isAssignableFrom(field.getType())) { + List list = (List) field.get(this); + if (list != null && !list.isEmpty()) { + return false; + } + } else { + String str = (String) field.get(this); + if (StringUtils.isNotBlank(str)) { + return false; + } + } + } catch (IllegalAccessException e) { + } + } + return true; + } @Override public String toString() { diff --git a/src/main/java/com/shuzijun/leetcode/plugin/model/PluginConstant.java b/src/main/java/com/shuzijun/leetcode/plugin/model/PluginConstant.java index 8cdb45de..8ebc0d37 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/model/PluginConstant.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/model/PluginConstant.java @@ -14,7 +14,8 @@ public class PluginConstant { * 通知分组 */ public static final String NOTIFICATION_GROUP = "leetcode editor"; - public static final String TOOL_WINDOW_ID = "leetcode"; + public static final String TOOL_WINDOW_ID = "Leetcode"; + public static final String CONSOLE_WINDOW_ID = "Leetcode Console"; /** * 配置id @@ -30,33 +31,61 @@ public class PluginConstant { public static final String ACTION_PREFIX = "leetcode"; public static final String ACTION_SUFFIX = ""; - public static final String LEETCODE_FIND_CATEGORY = ACTION_PREFIX + ".find.Category"; - public static final String LEETCODE_FIND_DIFFICULTY = ACTION_PREFIX + ".find.Difficulty"; - public static final String LEETCODE_FIND_STATUS = ACTION_PREFIX + ".find.Status"; - public static final String LEETCODE_FIND_LISTS = ACTION_PREFIX + ".find.Lists"; + public static final String LEETCODE_FIND_PREFIX = ACTION_PREFIX + ".find."; public static final String LEETCODE_FIND_TAGS = ACTION_PREFIX + ".find.Tags"; public static final String LEETCODE_SORT_PREFIX = ACTION_PREFIX + ".sort."; public static final String LEETCODE_EDITOR_FAVORITE = ACTION_PREFIX + ".editor.favorite"; - public static final String LEETCODE_NAVIGATOR_ACTIONS_MENU =ACTION_PREFIX + ".NavigatorActionsMenu"; + public static final String LEETCODE_NAVIGATOR_ACTIONS_MENU = ACTION_PREFIX + ".NavigatorActionsMenu"; - public static final String LEETCODE_EDITOR_OPEN_CODE = ACTION_PREFIX + ".editor.openCode"; + public static final String LEETCODE_EDITOR_OPEN_CODE = ACTION_PREFIX + ".editor.openCode"; - public static final String LEETCODE_EDITOR_TREE = ACTION_PREFIX + ".editor.tree"; + public static final String LEETCODE_EDITOR_TREE = ACTION_PREFIX + ".editor.tree"; public static final String LEETCODE_TIMER_BAR_WIDGET = ACTION_PREFIX + ".TimerBarWidget"; - public static final String LEETCODE_NAVIGATOR_ACTIONS_TOOLBAR =ACTION_PREFIX + ".NavigatorActionsToolbar"; + public static final String LEETCODE_NAVIGATOR_ACTIONS_TOOLBAR = ACTION_PREFIX + ".NavigatorActionsToolbar"; public static final String LEETCODE_FIND_TOOLBAR = ACTION_PREFIX + ".find.Toolbar"; public static final String LEETCODE_FIND_SORT_TOOLBAR = ACTION_PREFIX + ".find.SortToolbar"; public static final String LEETCODE_EDITOR_GROUP = ACTION_PREFIX + ".editor.group"; - public static final String LEETCODE_EDITOR_TIMER_STATUS_BAR_ID = PLUGIN_ID + "-TimerStatusBar"; + public static final String LEETCODE_EDITOR_NOTE = ACTION_PREFIX + ".editor.note"; + + public static final String LEETCODE_EDITOR_TIMER_STATUS_BAR_ID = PLUGIN_ID + "-TimerStatusBar"; + + public static final String LEETCODE_EDITOR_VIEW = "lcv"; + + public static final String LEETCODE_EDITOR_TAB_VIEW = PLUGIN_ID + ".editor.tab"; + + public static final String LEETCODE_EDITOR_LOGIN_TOPIC = PLUGIN_ID + ".login.topic"; + + public static final String LEETCODE_EDITOR_QUESTION_STATUS_TOPIC = PLUGIN_ID + ".question.status"; + + public static final String LEETCODE_EDITOR_QUESTION_SUBMIT_TOPIC = PLUGIN_ID + ".question.submit"; + + public static final String LEETCODE_EDITOR_LOGIN_CLOSE_TOPIC = PLUGIN_ID + ".login.close"; + + public static final String LEETCODE_CODETOP_NAVIGATOR_ACTIONS_TOOLBAR = ACTION_PREFIX + ".codetop.NavigatorActionsToolbar"; + public static final String LEETCODE_CODETOP_FIND_TOOLBAR = ACTION_PREFIX + ".codetop.find.Toolbar"; + public static final String LEETCODE_CODETOP_FIND_SORT_TOOLBAR = ACTION_PREFIX + ".codetop.find.SortToolbar"; + + public static final String LEETCODE_CODETOP_FIND_PREFIX = ACTION_PREFIX + ".codetop.find."; + public static final String LEETCODE_CODETOP_SORT_PREFIX = ACTION_PREFIX + ".codetop.sort."; + + public static final String LEETCODE_EDITOR_CONFIG_TOPIC = PLUGIN_ID + ".config.topic"; + + public static final String LEETCODE_ALL_FIND_TOOLBAR = ACTION_PREFIX + ".all.find.Toolbar"; + public static final String LEETCODE_ALL_FIND_SORT_TOOLBAR = ACTION_PREFIX + ".all.find.SortToolbar"; + + public static final String LEETCODE_ALL_FIND_PREFIX = ACTION_PREFIX + ".all.find."; + public static final String LEETCODE_ALL_FIND_TAGS = ACTION_PREFIX + ".all.find.Tags"; + public static final String LEETCODE_ALL_SORT_PREFIX = ACTION_PREFIX + ".all.sort."; + + public static final String LEETCODE_ALL_QUESTION_TOPIC = PLUGIN_ID + ".all.question.topic"; - public static final String LEETCODE_EDITOR_VIEW = "lcv"; } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/model/Question.java b/src/main/java/com/shuzijun/leetcode/plugin/model/Question.java index 12044ac9..f0221e12 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/model/Question.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/model/Question.java @@ -1,36 +1,29 @@ package com.shuzijun.leetcode.plugin.model; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.collections.CollectionUtils; + +import java.util.List; /** * @author shuzijun */ -public class Question { - - private String title; - private String questionId; - private String questionTypename; - private String typeName; - private Integer level; - private String status; - private String titleSlug; - private boolean leaf = Boolean.FALSE; +public class Question extends QuestionView { + private String testCase; + private String exampleTestcases; private String langSlug; private String nodeType = Constant.NODETYPE_DEF; - /** - * 页面的题目编号 - */ - private String frontendQuestionId; + /** * 题目描述 */ private String content; + /** - * 题目代码 + * 所有的代码片段 */ - private String code; + private List codeSnippets; /** * 文章类型 @@ -46,125 +39,18 @@ public class Question { * 专栏文章 */ private Integer columnArticles = 0; - /** - * 解题成功 - */ - @Deprecated - private Integer acs = 0; - /** - * 提交数 - */ - @Deprecated - private Integer submitted = 0; - - /** - * 通过率 % - */ - private Double acceptance = 0D; - /** - * 频率 - */ - private Double frequency = 0d; public Question() { + super(); } public Question(String title) { - this.title = title; - } - - public Question(String title, String nodeType) { - this.title = title; - this.nodeType = nodeType; - } - - public String getTitle() { - return title; - } + super(title); - public String getFormTitle() { - StringBuffer sb = new StringBuffer(); - if (StringUtils.isNotBlank(frontendQuestionId)) { - sb.append("[").append(frontendQuestionId).append("]"); - } - return sb.append(title).toString(); } - public void setTitle(String title) { - this.title = title; - } - - public String getQuestionId() { - return questionId; - } - - public void setQuestionId(String questionId) { - this.questionId = questionId; - } - - public String getQuestionTypename() { - return questionTypename; - } - - public void setQuestionTypename(String questionTypename) { - this.questionTypename = questionTypename; - } - - public String getTypeName() { - return typeName; - } - - public void setTypeName(String typeName) { - this.typeName = typeName; - } - - public Integer getLevel() { - return level; - } - - public void setLevel(Integer level) { - this.level = level; - } - - public void setLevel(String difficulty) { - if(difficulty == null){ - this.level = 0; - }else if("easy".equalsIgnoreCase(difficulty)){ - this.level = 1; - }else if("medium".equalsIgnoreCase(difficulty)){ - this.level = 2; - }else if("hard".equalsIgnoreCase(difficulty)){ - this.level = 3; - }else { - this.level = 0; - } - } - - public String getStatus() { - return status; - } - - public void setStatus(String status) { - this.status = status; - } - - public boolean isLeaf() { - return leaf; - } - - public void setLeaf(boolean leaf) { - this.leaf = leaf; - } - - public String getTitleSlug() { - return titleSlug; - } - - public void setTitleSlug(String titleSlug) { - this.titleSlug = titleSlug; - } public String getTestCase() { return testCase; @@ -174,12 +60,12 @@ public void setTestCase(String testCase) { this.testCase = testCase; } - public String getLangSlug() { - return langSlug; + public String getExampleTestcases() { + return exampleTestcases; } - public void setLangSlug(String langSlug) { - this.langSlug = langSlug; + public void setExampleTestcases(String exampleTestcases) { + this.exampleTestcases = exampleTestcases; } public String getNodeType() { @@ -190,13 +76,6 @@ public void setNodeType(String nodeType) { this.nodeType = nodeType; } - public String getFrontendQuestionId() { - return frontendQuestionId; - } - - public void setFrontendQuestionId(String frontendQuestionId) { - this.frontendQuestionId = frontendQuestionId; - } public String getContent() { return content; @@ -206,12 +85,33 @@ public void setContent(String content) { this.content = content; } + public void setLangSlug(String langSlug) { + this.langSlug = langSlug; + } + public String getCode() { - return code; + if (CollectionUtils.isEmpty(codeSnippets)) { + return "Subscribe to unlock."; + } + CodeTypeEnum codeType = CodeTypeEnum.getCodeTypeEnumByLangSlug(langSlug); + for (CodeSnippet codeSnippet : codeSnippets) { + if (codeType.getLangSlug().equals(codeSnippet.getLangSlug())) { + StringBuffer sb = new StringBuffer(); + sb.append(codeType.getComment()).append(Constant.SUBMIT_REGION_BEGIN).append("\n"); + sb.append(codeSnippet.getCode()).append("\n"); + sb.append(codeType.getComment()).append(Constant.SUBMIT_REGION_END).append("\n"); + return sb.toString(); + } + } + return codeType.getComment() + "There is no code of " + codeType.getType() + " type for this problem"; } - public void setCode(String code) { - this.code = code; + public List getCodeSnippets() { + return codeSnippets; + } + + public void setCodeSnippets(List codeSnippets) { + this.codeSnippets = codeSnippets; } public Integer getArticleLive() { @@ -238,75 +138,4 @@ public void setColumnArticles(Integer columnArticles) { this.columnArticles = columnArticles; } - @Deprecated - public Integer getAcs() { - return acs; - } - - @Deprecated - public void setAcs(Integer acs) { - this.acs = acs; - } - - @Deprecated - public Integer getSubmitted() { - return submitted; - } - - @Deprecated - public void setSubmitted(Integer submitted) { - this.submitted = submitted; - } - - public Double getAcceptance() { - return acceptance; - } - - public void setAcceptance() { - if (this.submitted == 0) { - this.acceptance = 0D; - } else { - this.acceptance = Double.parseDouble(this.acs + "") / Double.parseDouble(this.submitted + ""); - } - } - - public void setAcceptance(Double acceptance) { - this.acceptance = acceptance; - } - - public Double getFrequency() { - return frequency; - } - - public void setFrequency(Double frequency) { - this.frequency = frequency; - } - - public String getStatusSign(){ - - if ("notac".equalsIgnoreCase(status) || "TRIED".equalsIgnoreCase(status)) { - return "❓"; - } else if ("ac".equalsIgnoreCase(status)) { - return "✔"; - } else if ("lock".equalsIgnoreCase(status)) { - return "$"; - } else if ("day".equalsIgnoreCase(status)) { - return "day"; - } else if (leaf && level != null) { - return " "; - } - return " "; - } - - @Override - public String toString() { - StringBuffer sb = new StringBuffer(); - - sb.append(getStatusSign()); - if (StringUtils.isNotBlank(frontendQuestionId) && leaf) { - sb.append("[").append(frontendQuestionId).append("]"); - } - return sb.append(title).toString(); - - } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/model/QuestionIndex.java b/src/main/java/com/shuzijun/leetcode/plugin/model/QuestionIndex.java new file mode 100644 index 00000000..9c55a619 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/model/QuestionIndex.java @@ -0,0 +1,26 @@ +package com.shuzijun.leetcode.plugin.model; + +/** + * @author shuzijun + */ +public class QuestionIndex { + private int index; + + private QuestionView questionView; + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + public QuestionView getQuestionView() { + return questionView; + } + + public void setQuestionView(QuestionView questionView) { + this.questionView = questionView; + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/model/QuestionView.java b/src/main/java/com/shuzijun/leetcode/plugin/model/QuestionView.java new file mode 100644 index 00000000..560a38aa --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/model/QuestionView.java @@ -0,0 +1,193 @@ +package com.shuzijun.leetcode.plugin.model; + +import org.apache.commons.lang.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author shuzijun + */ +public class QuestionView { + private String title; + private String questionId; + private Integer level; + private String status; + private String titleSlug; + /** + * 页面的题目编号 + */ + private String frontendQuestionId; + + /** + * 通过率 % + */ + private Double acceptance = 0D; + + /** + * 频率 + */ + private Double frequency = 0d; + + private String category; + + public QuestionView() { + } + + public QuestionView(String title) { + this.title = title; + } + + + public String getTitle() { + return title; + } + + public String getFormTitle() { + StringBuffer sb = new StringBuffer(); + if (StringUtils.isNotBlank(frontendQuestionId)) { + sb.append("[").append(frontendQuestionId).append("]"); + } + return sb.append(title).toString(); + } + + public void setTitle(String title) { + this.title = title; + } + + public String getQuestionId() { + return questionId; + } + + public void setQuestionId(String questionId) { + this.questionId = questionId; + } + + public Integer getLevel() { + return level; + } + + public void setLevel(String difficulty) { + if (difficulty == null) { + this.level = 0; + } else if ("easy".equalsIgnoreCase(difficulty)) { + this.level = 1; + } else if ("medium".equalsIgnoreCase(difficulty)) { + this.level = 2; + } else if ("hard".equalsIgnoreCase(difficulty)) { + this.level = 3; + } else if ("1".equals(difficulty) || "2".equals(difficulty) || "3".equals(difficulty)) { + this.level = Integer.valueOf(difficulty); + } else { + this.level = 0; + } + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + + public String getTitleSlug() { + return titleSlug; + } + + public void setTitleSlug(String titleSlug) { + this.titleSlug = titleSlug; + } + + public String getFrontendQuestionId() { + return frontendQuestionId; + } + + public void setFrontendQuestionId(String frontendQuestionId) { + this.frontendQuestionId = frontendQuestionId; + } + + public void setAcceptance(Double acceptance) { + this.acceptance = acceptance; + } + + public Double getAcceptance() { + return acceptance; + } + + public Double getFrequency() { + return frequency; + } + + public void setFrequency(Double frequency) { + this.frequency = frequency; + } + + public String getStatusSign() { + + if ("notac".equalsIgnoreCase(status) || "TRIED".equalsIgnoreCase(status)) { + return "❓"; + } else if ("ac".equalsIgnoreCase(status)) { + return "✔"; + } else if ("lock".equalsIgnoreCase(status)) { + return "$"; + } else if ("day".equalsIgnoreCase(status)) { + return "D"; + } else if (level != null) { + return " "; + } + return " "; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + + sb.append(getStatusSign()); + if (StringUtils.isNotBlank(frontendQuestionId)) { + sb.append("[").append(frontendQuestionId).append("]"); + } + return sb.append(title).toString(); + + } + + private static Map SORT = new HashMap<>(); + + static { + String sortStr = "剑面"; + for (int i = 0; i < sortStr.length(); i++) { + SORT.put(sortStr.charAt(i), i); + } + } + + public int frontendQuestionIdCompareTo(QuestionView questionView) { + Integer i1 = SORT.get(frontendQuestionId.charAt(0)); + Integer i2 = SORT.get(questionView.frontendQuestionId.charAt(0)); + if (i1 != null && i2 != null) { + if (i1 != i2) { + return i1.compareTo(i2); + }else { + return frontendQuestionId.compareTo(questionView.frontendQuestionId); + } + } else if (i1 != null) { + return 1; + } else if (i2 != null) { + return -1; + } + if (frontendQuestionId.length() != questionView.frontendQuestionId.length()) { + return frontendQuestionId.length() - questionView.frontendQuestionId.length(); + } + + return frontendQuestionId.compareTo(questionView.frontendQuestionId); + + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/model/Statistics.java b/src/main/java/com/shuzijun/leetcode/plugin/model/Statistics.java new file mode 100644 index 00000000..7d383ef7 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/model/Statistics.java @@ -0,0 +1,72 @@ +package com.shuzijun.leetcode.plugin.model; + +/** + * @author shuzijun + */ +public class Statistics { + + /** + * 解决 + */ + private Integer solvedTotal; + + /** + * 总数 + */ + private Integer questionTotal; + + /** + * 难度 + */ + private Integer easy; + + /** + * 难度 + */ + private Integer medium; + + /** + * 难度 + */ + private Integer hard; + + public Integer getSolvedTotal() { + return solvedTotal; + } + + public void setSolvedTotal(Integer solvedTotal) { + this.solvedTotal = solvedTotal; + } + + public Integer getQuestionTotal() { + return questionTotal; + } + + public void setQuestionTotal(Integer questionTotal) { + this.questionTotal = questionTotal; + } + + public Integer getEasy() { + return easy; + } + + public void setEasy(Integer easy) { + this.easy = easy; + } + + public Integer getMedium() { + return medium; + } + + public void setMedium(Integer medium) { + this.medium = medium; + } + + public Integer getHard() { + return hard; + } + + public void setHard(Integer hard) { + this.hard = hard; + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/model/User.java b/src/main/java/com/shuzijun/leetcode/plugin/model/User.java new file mode 100644 index 00000000..70e0cd2c --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/model/User.java @@ -0,0 +1,59 @@ +package com.shuzijun.leetcode.plugin.model; + +import java.util.Objects; + +/** + * @author shuzijun + */ +public class User { + + private String username; + + private boolean isPremium; + + private boolean isSignedIn = Boolean.FALSE; + + private boolean isVerified; + + private boolean isPhoneVerified; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public boolean isPremium() { + return isPremium; + } + + public void setPremium(Boolean premium) { + isPremium = Objects.requireNonNullElse(premium, false);; + } + + public boolean isVerified() { + return isVerified; + } + + public void setVerified(Boolean verified) { + isVerified = Objects.requireNonNullElse(verified, false); + } + + public boolean isPhoneVerified() { + return isPhoneVerified; + } + + public void setPhoneVerified(Boolean phoneVerified) { + isPhoneVerified = Objects.requireNonNullElse(phoneVerified, false); + } + + public boolean isSignedIn() { + return isSignedIn; + } + + public void setSignedIn(Boolean signedIn) { + isSignedIn = Objects.requireNonNullElse(signedIn, false); + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/renderer/CustomTreeCellRenderer.java b/src/main/java/com/shuzijun/leetcode/plugin/renderer/CustomTreeCellRenderer.java deleted file mode 100644 index cfa6c039..00000000 --- a/src/main/java/com/shuzijun/leetcode/plugin/renderer/CustomTreeCellRenderer.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.shuzijun.leetcode.plugin.renderer; - - -import com.intellij.ide.util.treeView.NodeRenderer; -import com.shuzijun.leetcode.plugin.model.Config; -import com.shuzijun.leetcode.plugin.model.Question; -import com.shuzijun.leetcode.plugin.setting.PersistentConfig; - -import javax.imageio.ImageIO; -import javax.swing.*; -import javax.swing.tree.DefaultMutableTreeNode; -import java.awt.*; -import java.awt.image.BufferedImage; -import java.io.IOException; - -/** - * @author shuzijun - */ -public class CustomTreeCellRenderer extends NodeRenderer { - - 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); - - public CustomTreeCellRenderer() { - loaColor(); - } - - 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]; - } - } - - public static BufferedImage getResourceBufferedImage(String filePath) { - if (CustomTreeCellRenderer.class.getClassLoader().getResourceAsStream(filePath) != null) { - try { - return ImageIO.read(CustomTreeCellRenderer.class.getClassLoader().getResourceAsStream(filePath)); - } catch (IOException e) { - e.printStackTrace(); - } - } - return com.intellij.util.ui.UIUtil.createImage(10, 10, 1); - } - - @SuppressWarnings("unchecked") - @Override - public void customizeCellRenderer(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { - - super.customizeCellRenderer(tree, value, selected, expanded, leaf, row, hasFocus); - - DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; - Question question = (Question) node.getUserObject(); - - if (question.getLevel() == null) { - - } else if (question.getLevel() == 1) { - setForeground(Level1); - } else if (question.getLevel() == 2) { - setForeground(Level2); - } else if (question.getLevel() == 3) { - setForeground(Level3); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/shuzijun/leetcode/plugin/setting/PersistentConfig.java b/src/main/java/com/shuzijun/leetcode/plugin/setting/PersistentConfig.java index c2084938..97a4e7ae 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/setting/PersistentConfig.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/setting/PersistentConfig.java @@ -33,7 +33,6 @@ public class PersistentConfig implements PersistentStateComponent initConfig = new HashMap<>(); - @Nullable public static PersistentConfig getInstance() { return ServiceManager.getService(PersistentConfig.class); } @@ -49,6 +48,8 @@ public void loadState(@NotNull PersistentConfig persistentConfig) { XmlSerializerUtil.copyBean(persistentConfig, this); } + + @Nullable public Config getInitConfig() { Config config = initConfig.get(INITNAME); if (config != null && config.getVersion() != null && config.getVersion() < Constant.PLUGIN_CONFIG_VERSION_3) { @@ -69,6 +70,7 @@ public Config getInitConfig() { return config; } + @NotNull public Config getConfig() { Config config = getInitConfig(); if (config == null) { diff --git a/src/main/java/com/shuzijun/leetcode/plugin/setting/ProjectConfig.java b/src/main/java/com/shuzijun/leetcode/plugin/setting/ProjectConfig.java index b78b7b8e..af10f0a9 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/setting/ProjectConfig.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/setting/ProjectConfig.java @@ -77,6 +77,15 @@ public LeetcodeEditor getEditor(String path) { return innerState.projectConfig.get(path); } + public LeetcodeEditor getEditor(String path, String host) { + LeetcodeEditor leetcodeEditor = innerState.projectConfig.get(path); + if (leetcodeEditor != null && host.equals(leetcodeEditor.getHost())) { + return leetcodeEditor; + } else { + return null; + } + } + public static class InnerState { @NotNull @MapAnnotation diff --git a/src/main/java/com/shuzijun/leetcode/plugin/setting/SettingUI.form b/src/main/java/com/shuzijun/leetcode/plugin/setting/SettingUI.form index e9980418..9436aa01 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/setting/SettingUI.form +++ b/src/main/java/com/shuzijun/leetcode/plugin/setting/SettingUI.form @@ -21,24 +21,6 @@ - - - - - - - - - - - - - - - - - - @@ -50,15 +32,16 @@ - + - - + + + @@ -73,20 +56,10 @@ - - - - - - - - - - - + @@ -123,20 +96,38 @@ - + + + + + + + + + + - + + + + + + + + + - + + - + @@ -145,28 +136,74 @@ - + - + + + + + + + + + - + - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + - + @@ -306,7 +343,9 @@ - + + + diff --git a/src/main/java/com/shuzijun/leetcode/plugin/setting/SettingUI.java b/src/main/java/com/shuzijun/leetcode/plugin/setting/SettingUI.java index c26356ac..51b4a398 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/setting/SettingUI.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/setting/SettingUI.java @@ -8,6 +8,9 @@ import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.fileTypes.FileTypeManager; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; import com.intellij.openapi.ui.TextBrowseFolderListener; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.ui.components.JBPasswordField; @@ -15,18 +18,17 @@ import com.intellij.ui.components.JBTextField; import com.intellij.util.net.HttpConfigurable; import com.shuzijun.leetcode.plugin.listener.ColorListener; +import com.shuzijun.leetcode.plugin.listener.ConfigNotifier; import com.shuzijun.leetcode.plugin.listener.DonateListener; import com.shuzijun.leetcode.plugin.model.CodeTypeEnum; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.Constant; -import com.shuzijun.leetcode.plugin.renderer.CustomTreeCellRenderer; -import com.shuzijun.leetcode.plugin.timer.TimerBarWidget; +import com.shuzijun.leetcode.plugin.model.PluginConstant; import com.shuzijun.leetcode.plugin.utils.MTAUtils; import com.shuzijun.leetcode.plugin.utils.PropertiesUtils; import com.shuzijun.leetcode.plugin.utils.URLUtils; -import com.shuzijun.leetcode.plugin.window.HttpLogin; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; import org.apache.commons.lang.StringUtils; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; @@ -39,9 +41,9 @@ */ public class SettingUI { private JPanel mainPanel; - private JCheckBox questionEditorCheckBox; - private JComboBox webComboBox; - private JComboBox codeComboBox; + private JComboBox questionEditorBox; + private JComboBox webComboBox; + private JComboBox codeComboBox; private JBTextField userNameField; private JBPasswordField passwordField; private JLabel easyLabel; @@ -57,11 +59,13 @@ public class SettingUI { private JPanel codeFileName; private JPanel codeTemplate; private JPanel templateConstant; - private JCheckBox jcefCheckBox; + private JCheckBox cookieCheckBox; private JCheckBox multilineCheckBox; private JCheckBox htmlContentCheckBox; private JCheckBox showTopicsCheckBox; private JCheckBox showToolIconCheckBox; + private JCheckBox convergeEditorCheckBox; + private JCheckBox showEditorSignCheckBox; private Editor fileNameEditor = null; @@ -90,17 +94,15 @@ public void initUI() { customCodeBox.addActionListener(new DonateListener(customCodeBox)); proxyCheckBox.setSelected(HttpConfigurable.getInstance().USE_HTTP_PROXY || HttpConfigurable.getInstance().USE_PROXY_PAC); - proxyCheckBox.addMouseListener(new MouseAdapter(){ + proxyCheckBox.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { - if(HttpConfigurable.editConfigurable(mainPanel)){ + if (HttpConfigurable.editConfigurable(mainPanel)) { proxyCheckBox.setSelected(HttpConfigurable.getInstance().USE_HTTP_PROXY || HttpConfigurable.getInstance().USE_PROXY_PAC); } } }); - jcefCheckBox.setEnabled(HttpLogin.isSupportedJcef()); - templateConfigHelp.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { @@ -155,6 +157,10 @@ public void mouseClicked(MouseEvent e) { templateHelpEditorSettings.setVirtualSpace(false); templateConstant.add(templateHelpEditor.getComponent(), BorderLayout.CENTER); + questionEditorBox.addItem("Disable"); + questionEditorBox.addItem("Left"); + questionEditorBox.addItem("Right"); + loadSetting(); } @@ -189,12 +195,21 @@ private void loadSetting() { mediumLabel.setForeground(colors[1]); hardLabel.setForeground(colors[2]); - jcefCheckBox.setSelected(config.getJcef()); - questionEditorCheckBox.setSelected(config.getQuestionEditor()); + cookieCheckBox.setSelected(config.isCookie()); + if (config.getQuestionEditor().equals("true")) { + questionEditorBox.setSelectedItem("Left"); + } else if (config.getQuestionEditor().equals("false")) { + questionEditorBox.setSelectedItem("Disable"); + } else { + questionEditorBox.setSelectedItem(config.getQuestionEditor()); + } + multilineCheckBox.setSelected(config.getMultilineComment()); htmlContentCheckBox.setSelected(config.getHtmlContent()); showTopicsCheckBox.setSelected(config.getShowTopics()); showToolIconCheckBox.setSelected(config.getShowToolIcon()); + convergeEditorCheckBox.setSelected(config.getConvergeEditor()); + showEditorSignCheckBox.setSelected(config.isShowQuestionEditorSign()); } else { Color[] colors = new Config().getFormatLevelColour(); easyLabel.setForeground(colors[0]); @@ -204,6 +219,7 @@ private void loadSetting() { fileNameEditor.getDocument().setText(Constant.CUSTOM_FILE_NAME); templateEditor.getDocument().setText(Constant.CUSTOM_TEMPLATE); }); + questionEditorBox.setSelectedItem("Left"); } @@ -234,9 +250,12 @@ public boolean isModified() { public void apply() { Config config = PersistentConfig.getInstance().getInitConfig(); + Config oldConfig = null; if (config == null) { config = new Config(); config.setId(MTAUtils.getI("")); + } else { + oldConfig = config.clone(); } process(config); File file = new File(config.getFilePath() + File.separator + PersistentConfig.PATH + File.separator); @@ -244,14 +263,19 @@ public void apply() { file.mkdirs(); } PersistentConfig.getInstance().setInitConfig(config); - PersistentConfig.getInstance().savePassword(passwordField.getText(),config.getLoginName()); - CustomTreeCellRenderer.loaColor(); - TimerBarWidget.loaColor(); - NavigatorTable.loaColor(); + PersistentConfig.getInstance().savePassword(passwordField.getText(), config.getLoginName()); + Config finalOldConfig = oldConfig; + Config finalConfig = config; + ProgressManager.getInstance().run(new Task.Backgroundable(null, PluginConstant.PLUGIN_NAME + " Apply Config", false) { + @Override + public void run(@NotNull ProgressIndicator progressIndicator) { + ApplicationManager.getApplication().getMessageBus().syncPublisher(ConfigNotifier.TOPIC).change(finalOldConfig, finalConfig); + } + }); } public void process(Config config) { - if(config.getVersion() == null) { + if (config.getVersion() == null) { config.setVersion(Constant.PLUGIN_CONFIG_VERSION_3); } config.setLoginName(userNameField.getText()); @@ -264,12 +288,14 @@ public void process(Config config) { config.setCustomTemplate(templateEditor.getDocument().getText()); config.setFormatLevelColour(easyLabel.getForeground(), mediumLabel.getForeground(), hardLabel.getForeground()); config.setEnglishContent(englishContentBox.isSelected()); - config.setJcef(jcefCheckBox.isSelected()); - config.setQuestionEditor(questionEditorCheckBox.isSelected()); + config.setCookie(cookieCheckBox.isSelected()); + config.setQuestionEditor(questionEditorBox.getSelectedItem().toString()); config.setMultilineComment(multilineCheckBox.isSelected()); config.setHtmlContent(htmlContentCheckBox.isSelected()); config.setShowTopics(showTopicsCheckBox.isSelected()); config.setShowToolIcon(showToolIconCheckBox.isSelected()); + config.setConvergeEditor(convergeEditorCheckBox.isSelected()); + config.setShowQuestionEditorSign(showEditorSignCheckBox.isSelected()); } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/setting/StatisticsData.java b/src/main/java/com/shuzijun/leetcode/plugin/setting/StatisticsData.java new file mode 100644 index 00000000..656b4f89 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/setting/StatisticsData.java @@ -0,0 +1,76 @@ +package com.shuzijun.leetcode.plugin.setting; + +import com.intellij.openapi.components.PersistentStateComponent; +import com.intellij.openapi.components.State; +import com.intellij.openapi.components.Storage; +import com.intellij.openapi.project.Project; +import com.intellij.util.xmlb.annotations.MapAnnotation; +import com.shuzijun.leetcode.plugin.manager.SessionManager; +import com.shuzijun.leetcode.plugin.model.PluginConstant; +import com.shuzijun.leetcode.plugin.model.Session; +import com.shuzijun.leetcode.plugin.model.Statistics; +import com.shuzijun.leetcode.plugin.utils.URLUtils; +import org.apache.commons.collections.CollectionUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author shuzijun + */ +@State(name = "LeetcodeEditorStatistics" + PluginConstant.ACTION_SUFFIX, storages = {@Storage(value = PluginConstant.ACTION_PREFIX + "/statistics.xml")}, externalStorageOnly = true) +public class StatisticsData implements PersistentStateComponent { + + @Nullable + public static StatisticsData getInstance(Project project) { + return project.getService(StatisticsData.class); + } + + private InnerState innerState = new InnerState(); + + @Nullable + @Override + public StatisticsData.InnerState getState() { + return innerState; + } + + @Override + public void loadState(@NotNull StatisticsData.InnerState innerState) { + this.innerState = innerState; + } + + public void refresh(String host, Statistics statistics) { + this.innerState.statistics.put(host, statistics); + } + + public static void refresh(Project project) { + StatisticsData statisticsData = StatisticsData.getInstance(project); + List sessionList = SessionManager.getSession(project, true); + if (CollectionUtils.isEmpty(sessionList)) { + return; + } + Session session = sessionList.get(0); + Statistics statistics = new Statistics(); + statistics.setQuestionTotal(session.getQuestionTotal()); + statistics.setSolvedTotal(session.getSolvedTotal()); + statistics.setEasy(session.getEasy()); + statistics.setMedium(session.getMedium()); + statistics.setHard(session.getHard()); + statisticsData.refresh(URLUtils.getLeetcodeHost(), statistics); + } + + + public static class InnerState { + @NotNull + @MapAnnotation + public Map statistics; + + InnerState() { + statistics = new HashMap<>(); + } + } + +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/timer/TimerBarWidget.java b/src/main/java/com/shuzijun/leetcode/plugin/timer/TimerBarWidget.java index 4c60bd8d..e5c759ee 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/timer/TimerBarWidget.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/timer/TimerBarWidget.java @@ -1,12 +1,14 @@ package com.shuzijun.leetcode.plugin.timer; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.wm.CustomStatusBarWidget; import com.intellij.openapi.wm.StatusBar; +import com.intellij.util.messages.MessageBusConnection; +import com.shuzijun.leetcode.plugin.listener.ConfigNotifier; import com.shuzijun.leetcode.plugin.model.Config; import com.shuzijun.leetcode.plugin.model.PluginConstant; import com.shuzijun.leetcode.plugin.setting.PersistentConfig; -import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -33,10 +35,12 @@ public class TimerBarWidget implements CustomStatusBarWidget { public TimerBarWidget(Project project) { this.project = project; - loaColor(); + loaColor(PersistentConfig.getInstance().getInitConfig()); + MessageBusConnection messageBusConnection = ApplicationManager.getApplication().getMessageBus().connect(this); + messageBusConnection.subscribe(ConfigNotifier.TOPIC, (oldConfig, newConfig) -> loaColor(newConfig)); } - public static void loaColor(){ - Config config = PersistentConfig.getInstance().getInitConfig(); + + private void loaColor(Config config) { if (config != null) { Color[] colors = config.getFormatLevelColour(); Level1 = colors[0]; @@ -90,30 +94,6 @@ public void mouseClicked(MouseEvent e) { } } }); - Config config = PersistentConfig.getInstance().getInitConfig(); - if (config != null) { - if (StringUtils.isNotBlank(config.getLevelColour())) { - String[] colors = config.getLevelColour().split(";"); - if (colors.length > 0) { - try { - Level1 = new Color(Integer.parseInt(colors[0].replace("#",""), 16)); - } catch (Exception ignore) { - } - } - if (colors.length > 1) { - try { - Level2 = new Color(Integer.parseInt(colors[1].replace("#",""), 16)); - } catch (Exception ignore) { - } - } - if (colors.length > 2) { - try { - Level3 = new Color(Integer.parseInt(colors[2].replace("#",""), 16)); - } catch (Exception ignore) { - } - } - } - } } @Override diff --git a/src/main/java/com/shuzijun/leetcode/plugin/utils/CodeTopURLUtils.java b/src/main/java/com/shuzijun/leetcode/plugin/utils/CodeTopURLUtils.java new file mode 100644 index 00000000..ffb65b60 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/utils/CodeTopURLUtils.java @@ -0,0 +1,28 @@ +package com.shuzijun.leetcode.plugin.utils; + +/** + * @author shuzijun + */ +public class CodeTopURLUtils { + + public static final String codetop = "codetop.cc" ; + + private static String codetopUrl = "https://" ; + + private static String tags = "/api/tags/" ; + private static String companies = "/api/companies/" ; + + private static String questions = "/api/questions/"; + + public static String getTags() { + return codetopUrl + codetop + tags; + } + + public static String getCompanies(){ + return codetopUrl + codetop + companies; + } + + public static String getQuestions() { + return codetopUrl + codetop + questions; + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/utils/DataKeys.java b/src/main/java/com/shuzijun/leetcode/plugin/utils/DataKeys.java index 7fa6ba23..2168fa7c 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/utils/DataKeys.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/utils/DataKeys.java @@ -1,20 +1,18 @@ package com.shuzijun.leetcode.plugin.utils; -import com.intellij.openapi.actionSystem.ActionToolbar; +import com.intellij.execution.ui.ConsoleView; import com.intellij.openapi.actionSystem.DataKey; -import com.intellij.ui.components.JBScrollPane; -import com.shuzijun.leetcode.plugin.window.NavigatorTable; - -import javax.swing.*; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; +import com.shuzijun.leetcode.plugin.window.NavigatorTabsPanel; /** * @author shuzijun */ public class DataKeys { - public static final DataKey LEETCODE_PROJECTS_TREE = DataKey.create("LEETCODE_PROJECTS_TREE"); - public static final DataKey LEETCODE_PROJECTS_SCROLL = DataKey.create("LEETCODE_PROJECTS_SCROLL"); - public static final DataKey LEETCODE_PROJECTS_TERRFIND = DataKey.create("LEETCODE_PROJECTS_TERRFIND"); - public static final DataKey LEETCODE_TOOLBAR_FIND = DataKey.create("LEETCODE_TOOLBAR_FIND"); - public static final DataKey LEETCODE_TOOLBAR_SORT = DataKey.create("LEETCODE_TOOLBAR_SORT"); + public static final DataKey LEETCODE_CONSOLE_VIEW = DataKey.create("LEETCODE_CONSOLE_VIEW"); + + public static final DataKey LEETCODE_PROJECTS_TABS = DataKey.create("LEETCODE_PROJECTS_TABS"); + + public static final DataKey LEETCODE_PROJECTS_NAVIGATORACTION = DataKey.create("LEETCODE_PROJECTS_NAVIGATORACTION"); } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/utils/FileUtils.java b/src/main/java/com/shuzijun/leetcode/plugin/utils/FileUtils.java index 5f9b1d96..10998408 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/utils/FileUtils.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/utils/FileUtils.java @@ -215,7 +215,7 @@ private static void doCopyFile(File srcFile, File destFile, boolean preserveFile } public static void openFileEditor(File file, Project project) { - ApplicationManager.getApplication().invokeAndWait(() -> { + ApplicationManager.getApplication().invokeLater(() -> { VirtualFile vf = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); OpenFileDescriptor descriptor = new OpenFileDescriptor(project, vf); FileEditorManager.getInstance(project).openTextEditor(descriptor, false); @@ -225,7 +225,7 @@ public static void openFileEditor(File file, Project project) { public static void openFileEditorAndSaveState(File file, Project project, Question question, BiConsumer consumer,boolean isOpen) { - ApplicationManager.getApplication().invokeAndWait(() -> { + ApplicationManager.getApplication().invokeLater(() -> { VirtualFile vf = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); LeetcodeEditor leetcodeEditor = ProjectConfig.getInstance(project).getDefEditor(URLUtils.getLeetcodeHost()+question.getFrontendQuestionId()); leetcodeEditor.setFrontendQuestionId(URLUtils.getLeetcodeHost()+question.getFrontendQuestionId()); diff --git a/src/main/java/com/shuzijun/leetcode/plugin/utils/HttpRequest.java b/src/main/java/com/shuzijun/leetcode/plugin/utils/HttpRequest.java deleted file mode 100644 index 15583eea..00000000 --- a/src/main/java/com/shuzijun/leetcode/plugin/utils/HttpRequest.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.shuzijun.leetcode.plugin.utils; - -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.Map; - -/** - * @author shuzijun - */ -public class HttpRequest { - - private String url; - - private String body; - /** - * POST - */ - private String contentType; - - private Map Header = new HashMap<>(); - - public static HttpRequest get(String url) { - return new HttpRequest(url, null); - } - - public static HttpRequest post(String url, String contentType) { - return new HttpRequest(url, contentType); - } - - public static HttpRequest put(String url, String contentType) { - return new HttpRequest(url, contentType); - } - - private HttpRequest(String url, String contentType) { - this.url = url; - this.contentType = contentType; - } - - public String getUrl() { - return url; - } - - public String getBody() { - return body; - } - - public void setBody(String body) { - this.body = body; - } - - public String getContentType() { - return contentType; - } - - public void addHeader(String name, String value) { - Header.put(name, value); - } - - public Map getHeader() { - return Header; - } - - public void addParam(String key, String value) throws UnsupportedEncodingException { - if (body == null || body.isEmpty()) { - body = key + "=" + value; - } else { - body = body + "&" + key + "=" +value; - } - } -} \ No newline at end of file diff --git a/src/main/java/com/shuzijun/leetcode/plugin/utils/HttpRequestUtils.java b/src/main/java/com/shuzijun/leetcode/plugin/utils/HttpRequestUtils.java index 31c597a1..e34b6d9e 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/utils/HttpRequestUtils.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/utils/HttpRequestUtils.java @@ -1,6 +1,10 @@ package com.shuzijun.leetcode.plugin.utils; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.intellij.openapi.project.Project; import com.intellij.util.io.HttpRequests; +import com.shuzijun.leetcode.plugin.model.HttpRequest; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpHeaders; import org.jetbrains.annotations.NotNull; @@ -9,60 +13,78 @@ import java.net.*; import java.util.List; import java.util.Map; +import java.util.concurrent.TimeUnit; /** * @author shuzijun */ public class HttpRequestUtils { - private static final CookieManager cookieManager = new CookieManager(); + private static final Cache httpResponseCache = CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.SECONDS).build(); + + private static final CookieManager cookieManager = new CookieManager(null, (uri, cookie) -> { + if (uri == null || cookie == null || uri.getHost().equals("hm.baidu.com")) { + return false; + } + return HttpCookie.domainMatches(cookie.getDomain(), uri.getHost()); + }); static { CookieHandler.setDefault(cookieManager); } + @NotNull public static HttpResponse executeGet(HttpRequest httpRequest) { - HttpResponse httpResponse = new HttpResponse(); - try { - HttpRequests.request(httpRequest.getUrl()) - .throwStatusCodeException(false) - .tuner(new HttpRequestTuner(httpRequest)) - .connect(new HttpResponseProcessor(httpRequest, httpResponse)); + return CacheProcessor.processor(httpRequest, request -> { + HttpResponse httpResponse = new HttpResponse(); + try { + HttpRequests.request(request.getUrl()). + throwStatusCodeException(false). + tuner(new HttpRequestTuner(request)). + connect(new HttpResponseProcessor(request, httpResponse)); + + } catch (IOException e) { + LogUtils.LOG.error("HttpRequestUtils request error:", e); + httpResponse.setStatusCode(-1); + } + return httpResponse; + }); + - } catch (IOException e) { - LogUtils.LOG.error("HttpRequestUtils request error:", e); - httpResponse.setStatusCode(-1); - } - return httpResponse; } + @NotNull public static HttpResponse executePost(HttpRequest httpRequest) { - HttpResponse httpResponse = new HttpResponse(); - try { - HttpRequests.post(httpRequest.getUrl(), httpRequest.getContentType()) - .throwStatusCodeException(false) - .tuner(new HttpRequestTuner(httpRequest)) - .connect(new HttpResponseProcessor(httpRequest, httpResponse)); - } catch (IOException e) { - LogUtils.LOG.error("HttpRequestUtils request error:", e); - httpResponse.setStatusCode(-1); - } - return httpResponse; + return CacheProcessor.processor(httpRequest, request -> { + HttpResponse httpResponse = new HttpResponse(); + try { + HttpRequests.post(request.getUrl(), request.getContentType()) + .throwStatusCodeException(false) + .tuner(new HttpRequestTuner(request)) + .connect(new HttpResponseProcessor(request, httpResponse)); + } catch (IOException e) { + LogUtils.LOG.error("HttpRequestUtils request error:", e); + httpResponse.setStatusCode(-1); + } + return httpResponse; + }); } public static HttpResponse executePut(HttpRequest httpRequest) { - HttpResponse httpResponse = new HttpResponse(); - try { - HttpRequests.put(httpRequest.getUrl(), httpRequest.getContentType()) - .throwStatusCodeException(false) - .tuner(new HttpRequestTuner(httpRequest)) - .connect(new HttpResponseProcessor(httpRequest, httpResponse)); - } catch (IOException e) { - LogUtils.LOG.error("HttpRequestUtils request error:", e); - httpResponse.setStatusCode(-1); - } - return httpResponse; + return CacheProcessor.processor(httpRequest, request -> { + HttpResponse httpResponse = new HttpResponse(); + try { + HttpRequests.put(request.getUrl(), request.getContentType()) + .throwStatusCodeException(false) + .tuner(new HttpRequestTuner(request)) + .connect(new HttpResponseProcessor(request, httpResponse)); + } catch (IOException e) { + LogUtils.LOG.error("HttpRequestUtils request error:", e); + httpResponse.setStatusCode(-1); + } + return httpResponse; + }); } public static String getToken() { @@ -70,7 +92,8 @@ public static String getToken() { return null; } for (HttpCookie cookie : cookieManager.getCookieStore().getCookies()) { - if ("csrftoken".equals(cookie.getName())) { + if (StringUtils.isNotBlank(cookie.getDomain()) && + cookie.getDomain().toLowerCase().contains(URLUtils.getLeetcodeHost()) && "csrftoken".equals(cookie.getName())) { return cookie.getValue(); } @@ -78,9 +101,8 @@ public static String getToken() { return null; } - public static boolean isLogin() { - HttpRequest request = HttpRequest.get(URLUtils.getLeetcodePoints()); - HttpResponse response = executeGet(request); + public static boolean isLogin(Project project) { + HttpResponse response = HttpRequest.builderGet(URLUtils.getLeetcodePoints()).request(); if (response.getStatusCode() == 200) { return Boolean.TRUE; } @@ -113,7 +135,7 @@ private static void defaultHeader(HttpRequest httpRequest) { private static class HttpRequestTuner implements HttpRequests.ConnectionTuner { - private HttpRequest httpRequest; + private final HttpRequest httpRequest; public HttpRequestTuner(HttpRequest httpRequest) { this.httpRequest = httpRequest; @@ -122,14 +144,14 @@ public HttpRequestTuner(HttpRequest httpRequest) { @Override public void tune(@NotNull URLConnection urlConnection) throws IOException { - if (StringUtils.isNotBlank(getToken())) { + if (StringUtils.isNotBlank(getToken()) && (urlConnection.getURL().toString().contains(URLUtils.leetcode) || urlConnection.getURL().toString().contains(URLUtils.leetcodecn))) { urlConnection.addRequestProperty("x-csrftoken", getToken()); } urlConnection.addRequestProperty("referer", urlConnection.getURL().toString()); //urlConnection.addRequestProperty(":path", urlConnection.getURL().getPath()); defaultHeader(httpRequest); - httpRequest.getHeader().forEach((k, v) -> urlConnection.addRequestProperty(k, v)); + httpRequest.getHeader().forEach(urlConnection::addRequestProperty); } } @@ -168,4 +190,35 @@ public HttpResponse process(@NotNull HttpRequests.Request request) throws IOExce } } + private static class CacheProcessor { + public static HttpResponse processor(HttpRequest httpRequest, HttpRequestUtils.Callable callable) { + + String key = httpRequest.hashCode() + ""; + if (httpRequest.isCache() && httpResponseCache.getIfPresent(key) != null) { + return httpResponseCache.getIfPresent(key); + } + if (httpRequest.isCache()) { + synchronized (key.intern()) { + if (httpResponseCache.getIfPresent(key) != null) { + return httpResponseCache.getIfPresent(key); + } else { + HttpResponse httpResponse = callable.call(httpRequest); + if (httpResponse.getStatusCode() == 200) { + httpResponseCache.put(key, httpResponse); + } + return httpResponse; + } + } + } else { + return callable.call(httpRequest); + + } + } + } + + @FunctionalInterface + private interface Callable { + V call(HttpRequest request); + } + } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/utils/IOUtils.java b/src/main/java/com/shuzijun/leetcode/plugin/utils/IOUtils.java index f0c0c573..79439bec 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/utils/IOUtils.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/utils/IOUtils.java @@ -83,7 +83,6 @@ public static byte[] toByteArray(Reader input, String encoding) throws IOExcepti return output.toByteArray(); } - /** @deprecated */ public static byte[] toByteArray(String input) throws IOException { return input.getBytes(); } @@ -124,12 +123,10 @@ public static String toString(Reader input) throws IOException { return sw.toString(); } - /** @deprecated */ public static String toString(byte[] input) throws IOException { return new String(input); } - /** @deprecated */ public static String toString(byte[] input, String encoding) throws IOException { return encoding == null?new String(input):new String(input, encoding); } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/utils/MTAUtils.java b/src/main/java/com/shuzijun/leetcode/plugin/utils/MTAUtils.java index ab5c92ff..e15211d4 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/utils/MTAUtils.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/utils/MTAUtils.java @@ -80,7 +80,7 @@ public void run() { .setParameter("cf", version) .setParameter("ck", "0") .setParameter("cl", Toolkit.getDefaultToolkit().getScreenResolution() + "-bit") - .setParameter("ds", (int) screensize.getWidth() + "x" + (int) screensize.getHeight()) + .setParameter("ds", (int)screensize.getWidth() + "x" + (int)screensize.getHeight()) .setParameter("vl", "") .setParameter("ep", "3392,2371") .setParameter("ep", "3") @@ -94,8 +94,8 @@ public void run() { .setParameter("lv", "2") .setParameter("sn", "44949") .setParameter("r", "0") - .setParameter("ww", String.valueOf((int) screensize.getWidth())) - .setParameter("u", "http://leetcode-editor.shuzijun.cn/" + actionsId) + .setParameter("ww", String.valueOf((int)screensize.getWidth())) + .setParameter("u", "http://leetcode-editor.shuzijun.cn/" + actionsId ) .build(); HttpRequests.request(uri.toURL().toString()).userAgent(userAgent).tuner(connection -> { connection.addRequestProperty("Cookie", "HMACCOUNT=" + config.getId() + ";" + "HMACCOUNT_BFESS" + config.getId()); diff --git a/src/main/java/com/shuzijun/leetcode/plugin/utils/MessageUtils.java b/src/main/java/com/shuzijun/leetcode/plugin/utils/MessageUtils.java index 371d4853..2d5de595 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/utils/MessageUtils.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/utils/MessageUtils.java @@ -1,35 +1,51 @@ package com.shuzijun.leetcode.plugin.utils; +import com.intellij.execution.ui.ConsoleView; +import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.notification.Notification; import com.intellij.notification.NotificationType; import com.intellij.notification.Notifications; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.Service; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.popup.Balloon; import com.intellij.openapi.ui.popup.BalloonBuilder; import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.ui.JBColor; import com.intellij.ui.awt.RelativePoint; import com.shuzijun.leetcode.plugin.model.PluginConstant; -import org.jetbrains.annotations.Nullable; +import com.shuzijun.leetcode.plugin.window.ConsoleWindowFactory; +import org.apache.commons.lang.time.DateFormatUtils; +import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; +import java.util.Date; /** * @author shuzijun */ @Service -public final class MessageUtils { +public final class MessageUtils implements Disposable { + + public static String FLAG = "\033"; private Project project; + private ConsoleView consoleView; + private ToolWindow toolWindow; public MessageUtils(Project project) { this.project = project; + this.toolWindow = ToolWindowManager.getInstance(project).getToolWindow(ConsoleWindowFactory.ID); } - @Nullable + @NotNull public static MessageUtils getInstance(Project project) { return project.getService(MessageUtils.class); } @@ -47,15 +63,64 @@ public static void showMsg(JComponent component, MessageType messageType, String } public void showInfoMsg(String title, String body) { - Notifications.Bus.notify(new Notification(PluginConstant.NOTIFICATION_GROUP, title, body, NotificationType.INFORMATION), project); + showConsole(() -> { + printTitle(title, ConsoleViewContentType.NORMAL_OUTPUT); + printBody(body, ConsoleViewContentType.NORMAL_OUTPUT); + consoleView.print("\n", ConsoleViewContentType.NORMAL_OUTPUT); + }); } public void showWarnMsg(String title, String body) { - Notifications.Bus.notify(new Notification(PluginConstant.NOTIFICATION_GROUP, title, body, NotificationType.WARNING), project); + showConsole(() -> { + printTitle(title, ConsoleViewContentType.LOG_INFO_OUTPUT); + printBody(body, ConsoleViewContentType.LOG_INFO_OUTPUT); + consoleView.print("\n", ConsoleViewContentType.LOG_INFO_OUTPUT); + }); } public void showErrorMsg(String title, String body) { - Notifications.Bus.notify(new Notification(PluginConstant.NOTIFICATION_GROUP, title, body, NotificationType.ERROR), project); + showConsole(() -> { + printTitle(title, ConsoleViewContentType.ERROR_OUTPUT); + printBody(body, ConsoleViewContentType.ERROR_OUTPUT); + consoleView.print("\n", ConsoleViewContentType.ERROR_OUTPUT); + }); + } + + private void printTitle(String title, ConsoleViewContentType contentType) { + if (title.equals("info") || title.equals("warning") || title.equals("error")) { + consoleView.print("> " + DateFormatUtils.format(new Date(), "yyyy/MM/dd' 'HH:mm:ss") + "\n", contentType); + } else { + consoleView.print("> " + DateFormatUtils.format(new Date(), "yyyy/MM/dd' 'HH:mm:ss") + "\t" + title + "\n", contentType); + } + } + + private void printBody(String body, ConsoleViewContentType contentType) { + String[] bodys = body.split("\n"); + for (String s : bodys) { + if (s.contains(FLAG)) { + String[] sc = s.split(FLAG); + for (int i = 0; i < sc.length; i++) { + if (i % 2 == 0) { + consoleView.print(sc[i], contentType); + } else { + String childStr = sc[i]; + if (childStr.startsWith("I")) { + consoleView.print(sc[i].substring(1), ConsoleViewContentType.NORMAL_OUTPUT); + } else if (childStr.startsWith("W")) { + consoleView.print(sc[i].substring(1), ConsoleViewContentType.LOG_INFO_OUTPUT); + } else if (childStr.startsWith("E")) { + consoleView.print(sc[i].substring(1), ConsoleViewContentType.ERROR_OUTPUT); + } else { + consoleView.print(sc[i].substring(1), contentType); + } + } + } + consoleView.print("\n", contentType); + } else { + consoleView.print(s + "\n", contentType); + } + + } } public static void showAllWarnMsg(String title, String body) { @@ -66,5 +131,78 @@ public String getComponentName() { return this.getClass().getName(); } + public static String format(String body, String type) { + return FLAG + type + body.replace("\n", FLAG + "\n" + FLAG + type) + FLAG; + } + + public static String formatDiff(String expected, String output) { + if ((StringUtils.isBlank(expected) && StringUtils.isNotBlank(output)) || (StringUtils.isNotBlank(expected) && StringUtils.isBlank(output))) { + return FLAG + "E" + output + FLAG; + } else if (StringUtils.isBlank(expected) || StringUtils.isBlank(output) || output.equals(expected)) { + return output; + } else { + boolean isDiff = false; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < output.length(); i++) { + if (i >= expected.length()) { + if (!isDiff) { + sb.append(FLAG).append("E"); + } + sb.append(output.substring(i)).append(FLAG); + isDiff = true; + break; + } else { + if (output.charAt(i) == expected.charAt(i)) { + if (isDiff) { + sb.append(FLAG); + isDiff = false; + } + sb.append(output.charAt(i)); + } else { + if (!isDiff) { + sb.append(FLAG).append("E"); + isDiff = true; + } + sb.append(output.charAt(i)); + } + } + } + if (isDiff) { + sb.append(FLAG); + } + return sb.toString(); + } + } + + private void showConsole(Runnable runnable) { + ApplicationManager.getApplication().invokeLater(() -> { + if (toolWindow == null) { + toolWindow = ToolWindowManager.getInstance(project).getToolWindow(ConsoleWindowFactory.ID); + } + if (toolWindow == null) { + return; + } + if (!toolWindow.isAvailable()) { + toolWindow.setAvailable(true); + } + if (!toolWindow.isActive()) { + toolWindow.activate(null); + } + if (consoleView == null) { + this.consoleView = ConsoleWindowFactory.getDataContext(project).getData(DataKeys.LEETCODE_CONSOLE_VIEW); + } + consoleView.requestScrollingToEnd(); + runnable.run(); + }); + + + } + + @Override + public void dispose() { + if (consoleView != null) { + Disposer.dispose(consoleView); + } + } } diff --git a/src/main/java/com/shuzijun/leetcode/plugin/utils/doc/CleanNodeFormatter.java b/src/main/java/com/shuzijun/leetcode/plugin/utils/doc/CleanNodeFormatter.java index d4034141..14894cc4 100644 --- a/src/main/java/com/shuzijun/leetcode/plugin/utils/doc/CleanNodeFormatter.java +++ b/src/main/java/com/shuzijun/leetcode/plugin/utils/doc/CleanNodeFormatter.java @@ -66,7 +66,7 @@ private void render(@NotNull InlineLaTexNode texNode, @NotNull NodeFormatterCont } private void render(@NotNull AttributesNode attributesNode, @NotNull NodeFormatterContext nodeFormatterContext, @NotNull MarkdownWriter lineInfos) { - if(attributesNode.getText().startsWith(":align") ||attributesNode.getText().startsWith(":width") ){ + if (attributesNode.getText().startsWith(":align") || attributesNode.getText().startsWith(":width")) { return; } else { nodeFormatterContext.delegateRender(); @@ -86,6 +86,9 @@ private void render(FencedCodeBlock node, NodeFormatterContext context, Markdown markdown.blankLine(); markdown.append("* ").append(node.getInfo().toString()); } + if(node.getInfo().equals("python3",true)){ + node.setInfo(node.getInfo().subSequence(0,6)); + } context.delegateRender(); } @@ -99,6 +102,18 @@ private void render(HtmlInline node, NodeFormatterContext context, MarkdownWrite markdown.append("
    Video is not supported."); } else if (node.getChars().startsWith(""); + } else if (node.getChars().startsWith(""); + } 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 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(project)) { + HttpLogin.loginSuccess(project, cookieList); + MessageUtils.getInstance(project).showWarnMsg("", PropertiesUtils.getInfo("browser.login.success")); + ApplicationManager.getApplication().invokeLater(() -> okAction.actionPerformed(null)); + successDispose = true; + } else { + cookieList.clear(); + LogUtils.LOG.info("login failure"); + } + } + return true; + } + }); + } + }, getCefBrowser()); + loadURL(URLUtils.getLeetcodeLogin()); + } + + @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/navigator/AllNavigatorPanel.java b/src/main/java/com/shuzijun/leetcode/plugin/window/navigator/AllNavigatorPanel.java new file mode 100644 index 00000000..3363a442 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/window/navigator/AllNavigatorPanel.java @@ -0,0 +1,269 @@ +package com.shuzijun.leetcode.plugin.window.navigator; + + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.ActionToolbar; +import com.intellij.openapi.actionSystem.DefaultActionGroup; +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.SimpleToolWindowPanel; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.ui.components.JBTextField; +import com.intellij.util.messages.MessageBusConnection; +import com.shuzijun.leetcode.plugin.listener.AllQuestionNotifier; +import com.shuzijun.leetcode.plugin.listener.ConfigNotifier; +import com.shuzijun.leetcode.plugin.listener.LoginNotifier; +import com.shuzijun.leetcode.plugin.listener.QueryKeyListener; +import com.shuzijun.leetcode.plugin.manager.FindManager; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; +import com.shuzijun.leetcode.plugin.manager.ViewManager; +import com.shuzijun.leetcode.plugin.model.*; +import com.shuzijun.leetcode.plugin.utils.URLUtils; +import com.shuzijun.leetcode.plugin.window.NavigatorPanelAction; +import com.shuzijun.leetcode.plugin.window.NavigatorTableData; +import org.apache.commons.collections.map.HashedMap; +import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.util.Map; + +/** + * @author shuzijun + */ +public class AllNavigatorPanel extends SimpleToolWindowPanel implements NavigatorPanelAction, Disposable { + + + private Map findMap = new HashedMap(); + private JPanel queryPanel; + private JTextField queryField; + private AllNavigatorTable navigatorTable; + private ActionToolbar findToolbar; + private ActionToolbar actionSortToolbar; + private Project myProject; + + private final NavigatorAction myNavigatorAction; + + public AllNavigatorPanel(ToolWindow toolWindow, Project project) { + super(Boolean.TRUE, Boolean.TRUE); + this.myProject = project; + this.myNavigatorAction = createMyNavigatorAction(); + navigatorTable = new AllNavigatorTable(project, myNavigatorAction); + Disposer.register(this, navigatorTable); + + final ActionManager actionManager = ActionManager.getInstance(); + 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)); + queryField = new JBTextField(); + queryField.setToolTipText("Enter Search"); + queryField.addKeyListener(new QueryKeyListener(queryField, myNavigatorAction, project)); + queryPanel.add(queryField); + + findToolbar = actionManager.createActionToolbar(PluginConstant.LEETCODE_ALL_FIND_TOOLBAR, (DefaultActionGroup) actionManager.getAction(PluginConstant.LEETCODE_ALL_FIND_TOOLBAR), true); + findToolbar.setTargetComponent(navigatorTable); + actionSortToolbar = actionManager.createActionToolbar(PluginConstant.LEETCODE_ALL_FIND_SORT_TOOLBAR, (DefaultActionGroup) actionManager.getAction(PluginConstant.LEETCODE_ALL_FIND_SORT_TOOLBAR), true); + actionSortToolbar.setTargetComponent(navigatorTable); + queryPanel.add(findToolbar.getComponent()); + queryPanel.add(actionSortToolbar.getComponent()); + + queryPanel.setVisible(false); + toolWindowPanel.setToolbar(queryPanel); + setContent(toolWindowPanel); + initFind(); + subscribe(); + + } + + private void subscribe() { + MessageBusConnection messageBusConnection = ApplicationManager.getApplication().getMessageBus().connect(this); + messageBusConnection.subscribe(LoginNotifier.TOPIC, new LoginNotifier() { + @Override + public void login(Project project, String host) { + ProgressManager.getInstance().run(new Task.Backgroundable(myProject, "Refresh data", false) { + @Override + public void run(@NotNull ProgressIndicator progressIndicator) { + if (!project.equals(myProject) && myNavigatorAction.getPageInfo().getRowTotal() <= 0) { + return; + } + myNavigatorAction.resetServiceData(); + ApplicationManager.getApplication().getMessageBus().syncPublisher(AllQuestionNotifier.TOPIC).reset(); + } + }); + } + + @Override + public void logout(Project project, String host) { + ProgressManager.getInstance().run(new Task.Backgroundable(myProject, "Refresh data", false) { + @Override + public void run(@NotNull ProgressIndicator progressIndicator) { + if (!project.equals(myProject) && myNavigatorAction.getPageInfo().getRowTotal() <= 0) { + return; + } + myNavigatorAction.resetServiceData(); + ApplicationManager.getApplication().getMessageBus().syncPublisher(AllQuestionNotifier.TOPIC).reset(); + } + }); + } + }); + messageBusConnection.subscribe(ConfigNotifier.TOPIC, new ConfigNotifier() { + @Override + public void change(Config oldConfig, Config newConfig) { + if (oldConfig != null && !oldConfig.getUrl().equalsIgnoreCase(newConfig.getUrl())) { + if (navigatorTable.getPageInfo().getRowTotal() > 0) { + myNavigatorAction.loadServiceData(); + } + } + } + }); + } + + private NavigatorAction createMyNavigatorAction() { + return new NavigatorAction.Adapter() { + @Override + public void updateUI() { + findToolbar.getComponent().updateUI(); + actionSortToolbar.getComponent().updateUI(); + } + + @Override + public JPanel queryPanel() { + return queryPanel; + } + + @Override + public boolean selectedRow(String slug) { + return navigatorTable.selectedRow(slug); + } + + @Override + public Find getFind() { + return findMap.get(URLUtils.getLeetcodeHost()); + } + + @Override + public void findClear() { + navigatorTable.getPageInfo().clearFilter(); + getFind().clearFilter(); + ViewManager.loadAllServiceData(this, myProject); + } + + @Override + public void findChange(String filterKey, boolean b, Tag tag) { + if ("categorySlug".equals(filterKey)) { + if (b) { + navigatorTable.getPageInfo().setCategorySlug(tag.getName()); + } else { + navigatorTable.getPageInfo().setCategorySlug(""); + } + } else { + navigatorTable.getPageInfo().disposeFilters(filterKey, tag.getSlug(), b); + } + ViewManager.loadAllServiceData(this, myProject); + } + + @Override + public void sort(Sort sort) { + if (sort.getType() == 0) { + navigatorTable.getPageInfo().disposeFilters("orderBy", "", false); + navigatorTable.getPageInfo().disposeFilters("sortOrder", "", false); + } else if (sort.getType() == 1) { + navigatorTable.getPageInfo().disposeFilters("orderBy", sort.getSlug(), true); + navigatorTable.getPageInfo().disposeFilters("sortOrder", "DESCENDING", true); + } else if (sort.getType() == 2) { + navigatorTable.getPageInfo().disposeFilters("orderBy", sort.getSlug(), true); + navigatorTable.getPageInfo().disposeFilters("sortOrder", "ASCENDING", true); + } + ViewManager.loadAllServiceData(this, myProject); + } + + @Override + public QuestionView getSelectedRowData() { + return navigatorTable.getSelectedRowData(); + } + + @Override + public NavigatorTableData.PagePanel getPagePanel() { + return navigatorTable.getPagePanel(); + } + + @Override + public PageInfo getPageInfo() { + return navigatorTable.getPageInfo(); + } + + @Override + public void loadData(String slug) { + navigatorTable.refreshData(slug); + } + + @Override + public void loadServiceData() { + ViewManager.loadAllServiceData(this, myProject); + } + + @Override + public void resetServiceData() { + getFind().resetFilterData(Constant.FIND_TYPE_LISTS, FindManager.getLists(myProject)); + ViewManager.loadAllServiceData(this, myProject, null, true); + } + + @Override + public boolean position(String slug) { + if (StringUtils.isBlank(slug)) { + return true; + } + if (selectedRow(slug)) { + return true; + } + navigatorTable.getPageInfo().clearFilter(); + navigatorTable.getPageInfo().getFilters().setSearchKeywords(""); + queryField.setText(""); + + getFind().clearFilter(); + ViewManager.loadAllServiceData(this, myProject, slug, false); + return selectedRow(slug); + } + }; + } + + @Override + public Object getData(String dataId) { + return super.getData(dataId); + } + + @Override + public void dispose() { + navigatorTable.dispose(); + } + + @Override + public NavigatorAction getNavigatorAction() { + return myNavigatorAction; + } + + private void initFind() { + Find cnFind = new Find(); + cnFind.addSort(Constant.SORT_TYPE_TITLE, new Sort(Constant.SORT_TYPE_TITLE, "TITLE")); + cnFind.addSort(Constant.SORT_TYPE_DIFFICULTY, new Sort(Constant.SORT_TYPE_DIFFICULTY, "DIFFICULTY")); + cnFind.addSort(Constant.SORT_TYPE_STATES, new Sort(Constant.SORT_TYPE_STATES, "STATES")); + findMap.put(URLUtils.leetcodecn, cnFind); + Find enFind = new Find(); + enFind.addSort(Constant.SORT_TYPE_TITLE, new Sort(Constant.SORT_TYPE_TITLE, "TITLE")); + enFind.addSort(Constant.SORT_TYPE_DIFFICULTY, new Sort(Constant.SORT_TYPE_DIFFICULTY, "DIFFICULTY")); + enFind.addSort(Constant.SORT_TYPE_STATES, new Sort(Constant.SORT_TYPE_STATES, "STATES")); + findMap.put(URLUtils.leetcode, enFind); + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/navigator/AllNavigatorTable.java b/src/main/java/com/shuzijun/leetcode/plugin/window/navigator/AllNavigatorTable.java new file mode 100644 index 00000000..47055bb4 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/window/navigator/AllNavigatorTable.java @@ -0,0 +1,154 @@ +package com.shuzijun.leetcode.plugin.window.navigator; + +import com.intellij.openapi.project.Project; +import com.shuzijun.leetcode.plugin.listener.JTableKeyAdapter; +import com.shuzijun.leetcode.plugin.listener.TreeMouseListener; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; +import com.shuzijun.leetcode.plugin.model.PageInfo; +import com.shuzijun.leetcode.plugin.model.Question; +import com.shuzijun.leetcode.plugin.model.QuestionView; +import com.shuzijun.leetcode.plugin.window.NavigatorTableData; +import icons.LeetCodeEditorIcons; + +import javax.swing.*; +import javax.swing.text.Style; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyleContext; +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +/** + * @author shuzijun + */ +public class AllNavigatorTable extends NavigatorTableData { + + + private NavigatorAction myNavigatorAction; + + public AllNavigatorTable(Project project, NavigatorAction navigatorAction) { + super(project); + this.myNavigatorAction = navigatorAction; + } + + @Override + protected boolean dataNotifier(QuestionView myData, Question question) { + if (myData.getTitleSlug().equals(question.getTitleSlug())) { + myData.setStatus(question.getStatus()); + return true; + } + return false; + } + + @Override + protected PagePanel createMyPagePanel(PageInfo myPageInfo, Project project) { + return null; + } + + @Override + protected JTextPane firstToolTip() { + List icons = new ArrayList<>(); + icons.add(LeetCodeEditorIcons.CONFIG); + icons.add(LeetCodeEditorIcons.LOGIN); + icons.add(LeetCodeEditorIcons.REFRESH); + icons.add(LeetCodeEditorIcons.TOGGLE); + icons.add(LeetCodeEditorIcons.LOGIN); + icons.add(LeetCodeEditorIcons.LOGOUT); + icons.add(LeetCodeEditorIcons.REFRESH); + icons.add(LeetCodeEditorIcons.RANDOM); + icons.add(LeetCodeEditorIcons.FIND); + icons.add(LeetCodeEditorIcons.POSITION); + icons.add(LeetCodeEditorIcons.PROGRESS); + icons.add(LeetCodeEditorIcons.TOGGLE); + icons.add(LeetCodeEditorIcons.CONFIG); + icons.add(LeetCodeEditorIcons.CLEAR); + icons.add(LeetCodeEditorIcons.HELP); + + Style style = new StyleContext().addStyle("boldStyle", null); + StyleConstants.setBold(style, true); + List styleList ; + if(Locale.getDefault().getLanguage().equals(Locale.CHINESE.getLanguage())){ + styleList = Arrays.asList(new MyStyle(5, 7, style)); + }else { + styleList = Arrays.asList(new MyStyle(18, 16, style)); + } + return createTip("allTip", icons, styleList); + } + + @Override + protected MyJBTable createMyTable(MyTableModel myTableModel, Project project) { + MyJBTable myJBTable = new MyJBTable(myTableModel) { + @Override + protected void prepareRenderer(Component component, Object value, int row, int column) { + if (column == 2) { + 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); + } + } + + + }; + + myJBTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + myJBTable.getTableHeader().setReorderingAllowed(false); + myJBTable.setRowSelectionAllowed(true); + myJBTable.setFillsViewportHeight(true); + myJBTable.addMouseListener(new TreeMouseListener(this, project)); + myJBTable.addKeyListener(new JTableKeyAdapter(this, project)); + myJBTable.setShowGrid(false); + return myJBTable; + } + + @Override + protected MyTableModel createMyTableModel() { + return new MyTableModel(new String[]{"Status", "Title", "Difficulty"}, new String[]{"S", "Title", "DD"}) { + @Override + public Object getValue(QuestionView question, int columnIndex) { + if (columnIndex == 0) { + return question.getStatusSign(); + } + if (columnIndex == 1) { + return question.getFormTitle(); + } + + if (columnIndex == 2) { + Integer level = question.getLevel(); + if (level == 1) { + return "Easy"; + } else if (level == 2) { + return "Medium"; + } else if (level == 3) { + return "Hard"; + } else { + return level; + } + } + return null; + } + }; + } + + + public boolean compareSlug(QuestionView myData, String titleSlug) { + return myData.getTitleSlug().equals(titleSlug); + } + + protected void setColumnWidth(MyJBTable myJBTable) { + myJBTable.getColumnModel().getColumn(0).setMaxWidth(20); + myJBTable.getColumnModel().getColumn(2).setMaxWidth(60); + } + +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/navigator/NavigatorPanel.java b/src/main/java/com/shuzijun/leetcode/plugin/window/navigator/NavigatorPanel.java new file mode 100644 index 00000000..2a30729f --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/window/navigator/NavigatorPanel.java @@ -0,0 +1,279 @@ +package com.shuzijun.leetcode.plugin.window.navigator; + + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.ActionToolbar; +import com.intellij.openapi.actionSystem.DefaultActionGroup; +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.SimpleToolWindowPanel; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.ui.components.JBTextField; +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.QueryKeyListener; +import com.shuzijun.leetcode.plugin.manager.FindManager; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; +import com.shuzijun.leetcode.plugin.manager.QuestionManager; +import com.shuzijun.leetcode.plugin.manager.ViewManager; +import com.shuzijun.leetcode.plugin.model.*; +import com.shuzijun.leetcode.plugin.utils.URLUtils; +import com.shuzijun.leetcode.plugin.window.NavigatorPanelAction; +import com.shuzijun.leetcode.plugin.window.NavigatorTableData; +import org.apache.commons.collections.map.HashedMap; +import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.util.Map; + +/** + * @author shuzijun + */ +public class NavigatorPanel extends SimpleToolWindowPanel implements NavigatorPanelAction, Disposable { + + + private Map findMap = new HashedMap(); + private JPanel queryPanel; + private JTextField queryField; + private NavigatorTable navigatorTable; + private ActionToolbar findToolbar; + private ActionToolbar actionSortToolbar; + private Project myProject; + + private final NavigatorAction myNavigatorAction; + + public NavigatorPanel(ToolWindow toolWindow, Project project) { + super(Boolean.TRUE, Boolean.TRUE); + this.myProject = project; + this.myNavigatorAction = createMyNavigatorAction(); + navigatorTable = new NavigatorTable(project, myNavigatorAction); + Disposer.register(this, navigatorTable); + + final ActionManager actionManager = ActionManager.getInstance(); + 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)); + queryField = new JBTextField(); + queryField.setToolTipText("Enter Search"); + queryField.addKeyListener(new QueryKeyListener(queryField, myNavigatorAction, 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); + initFind(); + subscribe(); + + } + + private void subscribe() { + MessageBusConnection messageBusConnection = ApplicationManager.getApplication().getMessageBus().connect(this); + messageBusConnection.subscribe(LoginNotifier.TOPIC, new LoginNotifier() { + @Override + public void login(Project project, String host) { + ProgressManager.getInstance().run(new Task.Backgroundable(myProject, "Refresh data", false) { + @Override + public void run(@NotNull ProgressIndicator progressIndicator) { + if (!project.equals(myProject) && myNavigatorAction.getPageInfo().getRowTotal() <= 0) { + return; + } + myNavigatorAction.resetServiceData(); + } + }); + } + + @Override + public void logout(Project project, String host) { + ProgressManager.getInstance().run(new Task.Backgroundable(myProject, "Refresh data", false) { + @Override + public void run(@NotNull ProgressIndicator progressIndicator) { + if (!project.equals(myProject) && myNavigatorAction.getPageInfo().getRowTotal() <= 0) { + return; + } + myNavigatorAction.resetServiceData(); + } + }); + } + }); + messageBusConnection.subscribe(ConfigNotifier.TOPIC, new ConfigNotifier() { + @Override + public void change(Config oldConfig, Config newConfig) { + if (oldConfig != null && !oldConfig.getUrl().equalsIgnoreCase(newConfig.getUrl())) { + if (navigatorTable.getPageInfo().getRowTotal() > 0) { + myNavigatorAction.loadServiceData(); + } + } + } + }); + } + + private NavigatorAction createMyNavigatorAction() { + return new NavigatorAction.Adapter() { + @Override + public void updateUI() { + findToolbar.getComponent().updateUI(); + actionSortToolbar.getComponent().updateUI(); + } + + @Override + public JPanel queryPanel() { + return queryPanel; + } + + @Override + public boolean selectedRow(String slug) { + return navigatorTable.selectedRow(slug); + } + + @Override + public Find getFind() { + return findMap.get(URLUtils.getLeetcodeHost()); + } + + @Override + public void findClear() { + navigatorTable.getPageInfo().clearFilter(); + getFind().clearFilter(); + ViewManager.loadServiceData(this, myProject); + } + + @Override + public void findChange(String filterKey, boolean b, Tag tag) { + if ("categorySlug".equals(filterKey)) { + if (b) { + navigatorTable.getPageInfo().setCategorySlug(tag.getSlug()); + } else { + navigatorTable.getPageInfo().setCategorySlug(""); + } + } else { + navigatorTable.getPageInfo().disposeFilters(filterKey, tag.getSlug(), b); + } + navigatorTable.getPageInfo().setPageIndex(1); + ViewManager.loadServiceData(this, myProject); + } + + @Override + public void sort(Sort sort) { + if (sort.getType() == 0) { + navigatorTable.getPageInfo().disposeFilters("orderBy", "", false); + navigatorTable.getPageInfo().disposeFilters("sortOrder", "", false); + } else if (sort.getType() == 1) { + navigatorTable.getPageInfo().disposeFilters("orderBy", sort.getSlug(), true); + navigatorTable.getPageInfo().disposeFilters("sortOrder", "DESCENDING", true); + } else if (sort.getType() == 2) { + navigatorTable.getPageInfo().disposeFilters("orderBy", sort.getSlug(), true); + navigatorTable.getPageInfo().disposeFilters("sortOrder", "ASCENDING", true); + } + ViewManager.loadServiceData(this, myProject); + } + + @Override + public QuestionView getSelectedRowData() { + return navigatorTable.getSelectedRowData(); + } + + @Override + public NavigatorTableData.PagePanel getPagePanel() { + return navigatorTable.getPagePanel(); + } + + @Override + public PageInfo getPageInfo() { + return navigatorTable.getPageInfo(); + } + + @Override + public void loadData(String slug) { + navigatorTable.refreshData(slug); + } + + @Override + public void loadServiceData() { + ViewManager.loadServiceData(this, myProject); + } + + @Override + public void resetServiceData() { + getFind().resetFilterData(Constant.FIND_TYPE_LISTS, FindManager.getLists(myProject)); + ViewManager.loadServiceData(this, myProject); + } + + @Override + public boolean position(String slug) { + if (StringUtils.isBlank(slug)) { + return true; + } + if (selectedRow(slug)) { + return true; + } + QuestionIndex questionIndex = QuestionManager.getQuestionIndex(slug); + if (questionIndex == null) { + return false; + } + getFind().operationType(""); + getFind().clearFilter(); + navigatorTable.getPageInfo().clear(); + + navigatorTable.getPageInfo().getFilters().setSearchKeywords(""); + queryField.setText(""); + + navigatorTable.getPageInfo().setPageIndex((questionIndex.getIndex() / navigatorTable.getPageInfo().getPageSize()) + 1); + ViewManager.loadServiceData(this, myProject, slug); + return selectedRow(slug); + } + }; + } + + @Override + public Object getData(String dataId) { + return super.getData(dataId); + } + + @Override + public void dispose() { + navigatorTable.dispose(); + } + + @Override + public NavigatorAction getNavigatorAction() { + return myNavigatorAction; + } + + private void initFind() { + Find cnFind = new Find(); + cnFind.addSort(Constant.SORT_TYPE_TITLE, new Sort(Constant.SORT_TYPE_TITLE, "FRONTEND_ID")); + cnFind.addSort(Constant.SORT_TYPE_SOLUTION, new Sort(Constant.SORT_TYPE_SOLUTION, "SOLUTION_NUM")); + cnFind.addSort(Constant.SORT_TYPE_ACCEPTANCE, new Sort(Constant.SORT_TYPE_ACCEPTANCE, "AC_RATE")); + cnFind.addSort(Constant.SORT_TYPE_DIFFICULTY, new Sort(Constant.SORT_TYPE_DIFFICULTY, "DIFFICULTY")); + cnFind.addSort(Constant.SORT_TYPE_FREQUENCY, new Sort(Constant.SORT_TYPE_FREQUENCY, "FREQUENCY")); + findMap.put(URLUtils.leetcodecn, cnFind); + Find enFind = new Find(); + enFind.addSort(Constant.SORT_TYPE_TITLE, new Sort(Constant.SORT_TYPE_TITLE, "FRONTEND_ID")); + enFind.addSort(Constant.SORT_TYPE_SOLUTION, new Sort(Constant.SORT_TYPE_SOLUTION, "SOLUTION_NUM")); + enFind.addSort(Constant.SORT_TYPE_ACCEPTANCE, new Sort(Constant.SORT_TYPE_ACCEPTANCE, "AC_RATE")); + enFind.addSort(Constant.SORT_TYPE_DIFFICULTY, new Sort(Constant.SORT_TYPE_DIFFICULTY, "DIFFICULTY")); + enFind.addSort(Constant.SORT_TYPE_FREQUENCY, new Sort(Constant.SORT_TYPE_FREQUENCY, "FREQUENCY")); + findMap.put(URLUtils.leetcode, enFind); + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/navigator/NavigatorTable.java b/src/main/java/com/shuzijun/leetcode/plugin/window/navigator/NavigatorTable.java new file mode 100644 index 00000000..a0c81b24 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/window/navigator/NavigatorTable.java @@ -0,0 +1,182 @@ +package com.shuzijun.leetcode.plugin.window.navigator; + +import com.intellij.openapi.project.Project; +import com.shuzijun.leetcode.plugin.listener.JTableKeyAdapter; +import com.shuzijun.leetcode.plugin.listener.TreeMouseListener; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; +import com.shuzijun.leetcode.plugin.model.PageInfo; +import com.shuzijun.leetcode.plugin.model.Question; +import com.shuzijun.leetcode.plugin.model.QuestionView; +import com.shuzijun.leetcode.plugin.utils.URLUtils; +import com.shuzijun.leetcode.plugin.window.NavigatorTableData; +import icons.LeetCodeEditorIcons; + +import javax.swing.*; +import javax.swing.text.Style; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyleContext; +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +/** + * @author shuzijun + */ +public class NavigatorTable extends NavigatorTableData { + + + private NavigatorAction myNavigatorAction; + + public NavigatorTable(Project project, NavigatorAction navigatorAction) { + super(project); + this.myNavigatorAction = navigatorAction; + } + + @Override + protected boolean dataNotifier(QuestionView myData, Question question) { + if (myData.getTitleSlug().equals(question.getTitleSlug())) { + myData.setStatus(question.getStatus()); + return true; + } + return false; + } + + @Override + protected JTextPane firstToolTip() { + List icons = new ArrayList<>(); + icons.add(LeetCodeEditorIcons.CONFIG); + icons.add(LeetCodeEditorIcons.LOGIN); + icons.add(LeetCodeEditorIcons.REFRESH); + icons.add(LeetCodeEditorIcons.TOGGLE); + icons.add(LeetCodeEditorIcons.LOGIN); + icons.add(LeetCodeEditorIcons.LOGOUT); + icons.add(LeetCodeEditorIcons.REFRESH); + icons.add(LeetCodeEditorIcons.RANDOM); + icons.add(LeetCodeEditorIcons.FIND); + icons.add(LeetCodeEditorIcons.POSITION); + icons.add(LeetCodeEditorIcons.PROGRESS); + icons.add(LeetCodeEditorIcons.TOGGLE); + icons.add(LeetCodeEditorIcons.CONFIG); + icons.add(LeetCodeEditorIcons.CLEAR); + icons.add(LeetCodeEditorIcons.HELP); + + Style style = new StyleContext().addStyle("boldStyle", null); + StyleConstants.setBold(style, true); + List styleList ; + if(Locale.getDefault().getLanguage().equals(Locale.CHINESE.getLanguage())){ + styleList = Arrays.asList(new MyStyle(5, 7, style)); + }else { + styleList = Arrays.asList(new MyStyle(18, 22, style)); + } + return createTip("pageTip", icons, styleList); + } + + @Override + protected PagePanel createMyPagePanel(PageInfo myPageInfo, Project project) { + return new PagePanel(project, myPageInfo) { + @Override + public Integer[] pageSizeData() { + return new Integer[]{20, 50, 100}; + } + + @Override + public void previousRunnable() { + myNavigatorAction.loadServiceData(); + } + + @Override + public void nextRunnable() { + myNavigatorAction.loadServiceData(); + } + + @Override + public void goRunnable() { + myNavigatorAction.loadServiceData(); + } + }; + } + + @Override + protected MyJBTable createMyTable(MyTableModel myTableModel, Project project) { + MyJBTable myJBTable = new MyJBTable(myTableModel) { + @Override + protected void prepareRenderer(Component component, Object value, int row, int column) { + if (column == 3) { + 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); + } + } + + }; + + myJBTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + myJBTable.getTableHeader().setReorderingAllowed(false); + myJBTable.setRowSelectionAllowed(true); + myJBTable.setFillsViewportHeight(true); + myJBTable.addMouseListener(new TreeMouseListener(this, project)); + myJBTable.addKeyListener(new JTableKeyAdapter(this, project)); + return myJBTable; + } + + @Override + protected MyTableModel createMyTableModel() { + return new MyTableModel(new String[]{"Status", "Title", "Acceptance", "Difficulty", "Frequency"}, new String[]{"S", "Title", "AC", "DD", "F"}) { + @Override + public Object getValue(QuestionView 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; + } + }; + } + + + public boolean compareSlug(QuestionView myData, String titleSlug) { + return myData.getTitleSlug().equals(titleSlug); + } + + protected void setColumnWidth(MyJBTable myJBTable) { + myJBTable.getColumnModel().getColumn(0).setMaxWidth(20); + myJBTable.getColumnModel().getColumn(2).setMaxWidth(50); + myJBTable.getColumnModel().getColumn(3).setMaxWidth(60); + myJBTable.getColumnModel().getColumn(4).setMaxWidth(50); + } + +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/navigator/TopNavigatorPanel.java b/src/main/java/com/shuzijun/leetcode/plugin/window/navigator/TopNavigatorPanel.java new file mode 100644 index 00000000..5f4e4cd4 --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/window/navigator/TopNavigatorPanel.java @@ -0,0 +1,213 @@ +package com.shuzijun.leetcode.plugin.window.navigator; + + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.ActionToolbar; +import com.intellij.openapi.actionSystem.DefaultActionGroup; +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.util.messages.MessageBusConnection; +import com.shuzijun.leetcode.plugin.listener.AllQuestionNotifier; +import com.shuzijun.leetcode.plugin.listener.ConfigNotifier; +import com.shuzijun.leetcode.plugin.manager.CodeTopManager; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; +import com.shuzijun.leetcode.plugin.model.*; +import com.shuzijun.leetcode.plugin.utils.URLUtils; +import com.shuzijun.leetcode.plugin.window.NavigatorPanelAction; +import com.shuzijun.leetcode.plugin.window.NavigatorTableData; +import org.apache.commons.collections.map.HashedMap; + +import javax.swing.*; +import java.util.Map; + +/** + * @author shuzijun + */ +public class TopNavigatorPanel extends SimpleToolWindowPanel implements NavigatorPanelAction, Disposable { + + private Map findMap = new HashedMap(); + private JPanel queryPanel; + private TopNavigatorTable topNavigatorTable; + private ActionToolbar findToolbar; + private ActionToolbar actionSortToolbar; + private Project project; + + private final NavigatorAction myNavigatorAction; + + public TopNavigatorPanel(ToolWindow toolWindow, Project project) { + super(Boolean.TRUE, Boolean.TRUE); + this.project = project; + final ActionManager actionManager = ActionManager.getInstance(); + + this.myNavigatorAction = createMyNavigatorAction(); + + topNavigatorTable = new TopNavigatorTable(project, myNavigatorAction); + Disposer.register(this, topNavigatorTable); + + ActionToolbar actionToolbar = actionManager.createActionToolbar(PluginConstant.LEETCODE_CODETOP_NAVIGATOR_ACTIONS_TOOLBAR, (DefaultActionGroup) actionManager.getAction(PluginConstant.LEETCODE_CODETOP_NAVIGATOR_ACTIONS_TOOLBAR), true); + actionToolbar.setTargetComponent(topNavigatorTable); + setToolbar(actionToolbar.getComponent()); + + SimpleToolWindowPanel toolWindowPanel = new SimpleToolWindowPanel(Boolean.TRUE, Boolean.TRUE); + + toolWindowPanel.setContent(topNavigatorTable); + + queryPanel = new JPanel(); + queryPanel.setLayout(new BoxLayout(queryPanel, BoxLayout.Y_AXIS)); + + findToolbar = actionManager.createActionToolbar(PluginConstant.LEETCODE_CODETOP_FIND_TOOLBAR, (DefaultActionGroup) actionManager.getAction(PluginConstant.LEETCODE_CODETOP_FIND_TOOLBAR), true); + findToolbar.setTargetComponent(topNavigatorTable); + actionSortToolbar = actionManager.createActionToolbar(PluginConstant.LEETCODE_CODETOP_FIND_SORT_TOOLBAR, (DefaultActionGroup) actionManager.getAction(PluginConstant.LEETCODE_CODETOP_FIND_SORT_TOOLBAR), true); + actionSortToolbar.setTargetComponent(topNavigatorTable); + queryPanel.add(findToolbar.getComponent()); + queryPanel.add(actionSortToolbar.getComponent()); + + queryPanel.setVisible(false); + toolWindowPanel.setToolbar(queryPanel); + setContent(toolWindowPanel); + initFind(); + subscribe(); + + } + + private void subscribe() { + MessageBusConnection messageBusConnection = ApplicationManager.getApplication().getMessageBus().connect(this); + messageBusConnection.subscribe(AllQuestionNotifier.TOPIC, new AllQuestionNotifier() { + @Override + public void reset() { + myNavigatorAction.resetServiceData(); + } + }); + messageBusConnection.subscribe(ConfigNotifier.TOPIC, new ConfigNotifier() { + @Override + public void change(Config oldConfig, Config newConfig) { + if (oldConfig != null && !oldConfig.getUrl().equalsIgnoreCase(newConfig.getUrl())) { + myNavigatorAction.resetServiceData(); + } + } + }); + } + + private NavigatorAction createMyNavigatorAction() { + return new NavigatorAction.Adapter() { + @Override + public void updateUI() { + findToolbar.getComponent().updateUI(); + actionSortToolbar.getComponent().updateUI(); + } + + @Override + public JPanel queryPanel() { + return queryPanel; + } + + @Override + public boolean selectedRow(String slug) { + return topNavigatorTable.selectedRow(slug); + } + + @Override + public void findClear() { + topNavigatorTable.getPageInfo().clearFilter(); + getFind().clearFilter(); + CodeTopManager.loadServiceData(this, project); + } + + @Override + public void findChange(String filterKey, boolean b, Tag tag) { + if ("tags".equalsIgnoreCase(filterKey) && b) { + if (topNavigatorTable.getPageInfo().getFilters().getTags() != null) { + topNavigatorTable.getPageInfo().getFilters().getTags().clear(); + } + + } + topNavigatorTable.getPageInfo().disposeFilters(filterKey, tag.getSlug(), b); + topNavigatorTable.getPageInfo().setPageIndex(1); + CodeTopManager.loadServiceData(this, project); + } + + @Override + public Find getFind() { + return findMap.get(URLUtils.getLeetcodeHost()); + } + + @Override + public void sort(Sort sort) { + if (sort.getType() == 0) { + topNavigatorTable.getPageInfo().disposeFilters("orderBy", "", false); + topNavigatorTable.getPageInfo().disposeFilters("sortOrder", "", false); + } else if (sort.getType() == 1) { + topNavigatorTable.getPageInfo().disposeFilters("orderBy", sort.getSlug(), true); + topNavigatorTable.getPageInfo().disposeFilters("sortOrder", "DESCENDING", true); + } else if (sort.getType() == 2) { + topNavigatorTable.getPageInfo().disposeFilters("orderBy", sort.getSlug(), true); + topNavigatorTable.getPageInfo().disposeFilters("sortOrder", "ASCENDING", true); + } + CodeTopManager.loadServiceData(this, project); + } + + @Override + public CodeTopQuestionView getSelectedRowData() { + return topNavigatorTable.getSelectedRowData(); + } + + @Override + public NavigatorTableData.PagePanel getPagePanel() { + return topNavigatorTable.getPagePanel(); + } + + @Override + public PageInfo getPageInfo() { + return topNavigatorTable.getPageInfo(); + } + + @Override + public void loadData(String slug) { + topNavigatorTable.refreshData(slug); + } + + @Override + public void loadServiceData() { + CodeTopManager.loadServiceData(this, project); + } + + @Override + public void resetServiceData() { + if (topNavigatorTable.getPageInfo().getRowTotal() > 0) { + CodeTopManager.loadServiceData(this, project); + } + } + }; + } + + @Override + public Object getData(String dataId) { + return super.getData(dataId); + } + + private void initFind() { + Find cnFind = new Find(); + cnFind.addSort(Constant.CODETOP_SORT_TYPE_TITLE, new Sort(Constant.CODETOP_SORT_TYPE_TITLE, "leetcode")); + cnFind.addSort(Constant.CODETOP_SORT_TYPE_TIME, new Sort(Constant.CODETOP_SORT_TYPE_TIME, "time")); + cnFind.addSort(Constant.CODETOP_SORT_TYPE_FREQUENCY, new Sort(Constant.CODETOP_SORT_TYPE_FREQUENCY, "frequency")); + findMap.put(URLUtils.leetcodecn, cnFind); + Find enFind = new Find(); + enFind.addSort(Constant.CODETOP_SORT_TYPE_TITLE, new Sort(Constant.CODETOP_SORT_TYPE_TITLE, "leetcode")); + enFind.addSort(Constant.CODETOP_SORT_TYPE_TIME, new Sort(Constant.CODETOP_SORT_TYPE_TIME, "time")); + enFind.addSort(Constant.CODETOP_SORT_TYPE_FREQUENCY, new Sort(Constant.CODETOP_SORT_TYPE_FREQUENCY, "frequency")); + findMap.put(URLUtils.leetcode, enFind); + } + + @Override + public NavigatorAction getNavigatorAction() { + return myNavigatorAction; + } + + public void dispose() { + topNavigatorTable.dispose(); + } +} diff --git a/src/main/java/com/shuzijun/leetcode/plugin/window/navigator/TopNavigatorTable.java b/src/main/java/com/shuzijun/leetcode/plugin/window/navigator/TopNavigatorTable.java new file mode 100644 index 00000000..c87e609a --- /dev/null +++ b/src/main/java/com/shuzijun/leetcode/plugin/window/navigator/TopNavigatorTable.java @@ -0,0 +1,185 @@ +package com.shuzijun.leetcode.plugin.window.navigator; + +import com.intellij.openapi.project.Project; +import com.shuzijun.leetcode.plugin.listener.JTableKeyAdapter; +import com.shuzijun.leetcode.plugin.listener.TreeMouseListener; +import com.shuzijun.leetcode.plugin.manager.NavigatorAction; +import com.shuzijun.leetcode.plugin.model.CodeTopQuestionView; +import com.shuzijun.leetcode.plugin.model.PageInfo; +import com.shuzijun.leetcode.plugin.model.Question; +import com.shuzijun.leetcode.plugin.window.NavigatorTableData; +import icons.LeetCodeEditorIcons; + +import javax.swing.*; +import javax.swing.text.Style; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyleContext; +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +/** + * @author shuzijun + */ +public class TopNavigatorTable extends NavigatorTableData { + + private NavigatorAction myNavigatorAction; + + public TopNavigatorTable(Project project, NavigatorAction navigatorAction) { + super(project); + this.myNavigatorAction = navigatorAction; + } + + @Override + protected boolean dataNotifier(CodeTopQuestionView myData, Question question) { + if (myData.getTitleSlug().equals(question.getTitleSlug())) { + myData.setStatus(question.getStatus()); + return true; + } + return false; + } + + @Override + protected JTextPane firstToolTip() { + List icons = new ArrayList<>(); + icons.add(LeetCodeEditorIcons.SHARE); + icons.add(LeetCodeEditorIcons.CONFIG); + icons.add(LeetCodeEditorIcons.REFRESH); + icons.add(LeetCodeEditorIcons.TOGGLE); + icons.add(LeetCodeEditorIcons.LOGIN); + icons.add(LeetCodeEditorIcons.LOGOUT); + icons.add(LeetCodeEditorIcons.REFRESH); + icons.add(LeetCodeEditorIcons.FIND); + icons.add(LeetCodeEditorIcons.SHARE); + icons.add(LeetCodeEditorIcons.TOGGLE); + icons.add(LeetCodeEditorIcons.CONFIG); + icons.add(LeetCodeEditorIcons.CLEAR); + icons.add(LeetCodeEditorIcons.HELP); + + Style style = new StyleContext().addStyle("boldStyle", null); + StyleConstants.setBold(style, true); + List styleList; + if (Locale.getDefault().getLanguage().equals(Locale.CHINESE.getLanguage())) { + styleList = Arrays.asList(new MyStyle(5, 12, style)); + } else { + styleList = Arrays.asList(new MyStyle(18, 20, style)); + } + + return createTip("codeTopTip", icons, styleList); + } + + @Override + protected PagePanel createMyPagePanel(PageInfo myPageInfo, Project project) { + return new PagePanel(project, myPageInfo) { + @Override + public Integer[] pageSizeData() { + return new Integer[]{20}; + } + + @Override + public void previousRunnable() { + myNavigatorAction.loadServiceData(); + } + + @Override + public void nextRunnable() { + myNavigatorAction.loadServiceData(); + } + + @Override + public void goRunnable() { + myNavigatorAction.loadServiceData(); + } + }; + } + + @Override + protected MyJBTable createMyTable(MyTableModel myTableModel, Project project) { + MyJBTable myJBTable = new MyJBTable(myTableModel) { + @Override + protected void prepareRenderer(Component component, Object value, int row, int column) { + if (column == 2) { + 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); + } + } + + }; + myJBTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + myJBTable.getTableHeader().setReorderingAllowed(false); + myJBTable.setRowSelectionAllowed(true); + myJBTable.setFillsViewportHeight(true); + myJBTable.addMouseListener(new TreeMouseListener(this, project)); + myJBTable.addKeyListener(new JTableKeyAdapter(this, project)); + return myJBTable; + } + + @Override + protected MyTableModel createMyTableModel() { + return new MyTableModel(new String[]{"状态", "标题", "难度", "考察时间", "考察频率"}, new String[]{"S", "Title", "DD", "Time", "F"}) { + @Override + public Object getValue(CodeTopQuestionView question, int columnIndex) { + if (columnIndex == 0) { + return question.getStatusSign(); + } + if (columnIndex == 1) { + return question.getFormTitle(); + } + + if (columnIndex == 2) { + 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 == 3) { + return question.getInspectTime(); + } + + if (columnIndex == 4) { + return question.getInspectFrequency(); + } + return null; + } + }; + } + + @Override + protected PageInfo createMyPageInfo() { + return new PageInfo<>(1, 20); + } + + @Override + public boolean compareSlug(CodeTopQuestionView myData, String titleSlug) { + return myData.getTitleSlug().equals(titleSlug); + } + + @Override + protected void setColumnWidth(MyJBTable myJBTable) { + myJBTable.getColumnModel().getColumn(0).setMaxWidth(20); + myJBTable.getColumnModel().getColumn(2).setMaxWidth(60); + myJBTable.getColumnModel().getColumn(3).setMaxWidth(80); + myJBTable.getColumnModel().getColumn(4).setMaxWidth(50); + } + + +} diff --git a/src/main/java/icons/LeetCodeEditorIcons.java b/src/main/java/icons/LeetCodeEditorIcons.java index 1e9f177f..511fa5be 100644 --- a/src/main/java/icons/LeetCodeEditorIcons.java +++ b/src/main/java/icons/LeetCodeEditorIcons.java @@ -15,7 +15,7 @@ public interface LeetCodeEditorIcons { Icon CLEAN = IconLoader.getIcon("/icons/clean.svg"); Icon CLEAR = IconLoader.getIcon("/icons/clear.svg"); Icon COLLAPSE = IconLoader.getIcon("/icons/collapse.svg"); - Icon CONFIG = IconLoader.getIcon("/icons/config.svg"); + Icon CONFIG = IconLoader.getIcon("/icons/config_lc.svg"); Icon DESC = IconLoader.getIcon("/icons/desc.svg"); Icon EDIT_DOC = IconLoader.getIcon("/icons/edit_doc.svg"); Icon FAVORITE = IconLoader.getIcon("/icons/favorite.svg"); @@ -40,5 +40,9 @@ public interface LeetCodeEditorIcons { Icon NOTE = IconLoader.getIcon("/icons/note.svg"); Icon LCV = IconLoader.getIcon("/icons/lcv.svg"); Icon DONATE = IconLoader.getIcon("/icons/donate.svg"); - + Icon SHARE = IconLoader.getIcon("/icons/share.svg"); + Icon TOGGLE = IconLoader.getIcon("/icons/toggle.svg"); + Icon SHOW = IconLoader.getIcon("/icons/show.svg"); + Icon PULL = IconLoader.getIcon("/icons/pull.svg"); + Icon PUSH = IconLoader.getIcon("/icons/push.svg"); } diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 6741f39f..054bc328 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -2,7 +2,7 @@ leetcode-editor LeetCode Editor 8.1 - shuzijun + shuzijun @@ -115,20 +115,7 @@
    ]]> - -
  • v8.0
    - 1.更新题目列表展示方式.
    - 2.修复bugs
    - 3.新年快乐
    -
  • -
  • v8.0
    - 1.Update the display method of the question list.
    - 2.Fix bugs.
    - 3.Happy new year
    -
  • - - ]]> + @@ -138,20 +125,24 @@ on how to target different products --> com.intellij.modules.lang -    + -      + - + + @@ -170,7 +161,11 @@ + + + + @@ -206,6 +201,10 @@ text="Help" description="Help" icon="LeetCodeEditorIcons.HELP"> + + + @@ -240,6 +239,8 @@ + @@ -248,8 +249,10 @@ + + @@ -276,13 +279,13 @@ + text="ShowNote" description="Show Note" icon="LeetCodeEditorIcons.SHOW"> + text="PullNote" description="Pull Note" icon="LeetCodeEditorIcons.PULL"> + text="PushNote" description="Push Note" icon="LeetCodeEditorIcons.PUSH"> @@ -315,7 +318,6 @@ - @@ -354,19 +356,17 @@ text="open in web" description="open in web(editor)" icon="LeetCodeEditorIcons.POPUP"> - + + + text="ShowNote" description="Show Note" icon="LeetCodeEditorIcons.SHOW"> - + - + @@ -412,6 +412,113 @@ class="com.shuzijun.leetcode.plugin.actions.toolbar.SortAction" text="Frequency" description="Sort By Frequency" icon="LeetCodeEditorIcons.SORT_ASC"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/graphql/addQuestionToFavorite.graphql b/src/main/resources/graphql/addQuestionToFavorite.graphql new file mode 100644 index 00000000..f5f09e67 --- /dev/null +++ b/src/main/resources/graphql/addQuestionToFavorite.graphql @@ -0,0 +1,9 @@ +mutation addQuestionToFavorite($favoriteIdHash: String!, $questionId: String!) { + addQuestionToFavorite(favoriteIdHash: $favoriteIdHash, questionId: $questionId) { + ok + error + favoriteIdHash + questionId + __typename + } +} diff --git a/src/main/resources/graphql/allQuestions.graphql b/src/main/resources/graphql/allQuestions.graphql new file mode 100644 index 00000000..d5f5f581 --- /dev/null +++ b/src/main/resources/graphql/allQuestions.graphql @@ -0,0 +1,12 @@ +query allQuestions { + allQuestions { + title + titleSlug + frontendQuestionId: questionFrontendId + questionId + status + level: difficulty + isPaidOnly + category: categoryTitle + } +} \ No newline at end of file diff --git a/src/main/resources/graphql/allQuestions_cn.graphql b/src/main/resources/graphql/allQuestions_cn.graphql new file mode 100644 index 00000000..0fb4337c --- /dev/null +++ b/src/main/resources/graphql/allQuestions_cn.graphql @@ -0,0 +1,17 @@ +query allQuestions { + allQuestions { + ...questionSummaryFields + } +} + +fragment questionSummaryFields on QuestionNode { + title + titleSlug + translatedTitle + frontendQuestionId: questionFrontendId + questionId + status + level: difficulty + isPaidOnly + category: categoryTitle +} diff --git a/src/main/resources/graphql/getNote.graphql b/src/main/resources/graphql/getNote.graphql new file mode 100644 index 00000000..0fcdfa66 --- /dev/null +++ b/src/main/resources/graphql/getNote.graphql @@ -0,0 +1,7 @@ +query getNote($titleSlug: String!) { + question(titleSlug: $titleSlug) { + questionId + note + __typename + } +} diff --git a/src/main/resources/graphql/problemsetQuestionList.graphql b/src/main/resources/graphql/problemsetQuestionList.graphql new file mode 100644 index 00000000..57ba3fd5 --- /dev/null +++ b/src/main/resources/graphql/problemsetQuestionList.graphql @@ -0,0 +1,27 @@ +query problemsetQuestionList($categorySlug: String, $limit: Int, $skip: Int, $filters: QuestionListFilterInput) { + problemsetQuestionList: questionList( + categorySlug: $categorySlug + limit: $limit + skip: $skip + filters: $filters + ) { + total: totalNum + questions: data { + acRate + difficulty + freqBar + frontendQuestionId: questionFrontendId + paidOnly: isPaidOnly + status + title + titleSlug + topicTags { + name + id + slug + } + hasSolution + } + } +} + \ No newline at end of file diff --git a/src/main/resources/graphql/problemsetQuestionList_cn.graphql b/src/main/resources/graphql/problemsetQuestionList_cn.graphql new file mode 100644 index 00000000..76d15a2c --- /dev/null +++ b/src/main/resources/graphql/problemsetQuestionList_cn.graphql @@ -0,0 +1,30 @@ +query problemsetQuestionList($categorySlug: String, $limit: Int, $skip: Int, $filters: QuestionListFilterInput) { + problemsetQuestionList( + categorySlug: $categorySlug + limit: $limit + skip: $skip + filters: $filters + ) { + hasMore + total + questions { + acRate + difficulty + freqBar + frontendQuestionId + paidOnly + solutionNum + status + title + titleCn + titleSlug + topicTags { + name + nameTranslated + id + slug + } + } + } +} + \ No newline at end of file diff --git a/src/main/resources/graphql/questionData.graphql b/src/main/resources/graphql/questionData.graphql new file mode 100644 index 00000000..1404aece --- /dev/null +++ b/src/main/resources/graphql/questionData.graphql @@ -0,0 +1,38 @@ +query questionData($titleSlug: String!) { + question(titleSlug: $titleSlug) { + questionId + questionFrontendId + title + titleSlug + content + translatedTitle + translatedContent + isPaidOnly + difficulty + likes + dislikes + isLiked + exampleTestcases + topicTags { + name + slug + translatedName + } + codeSnippets { + lang + langSlug + code + } + hints + solution { + id + canSeeDetail + } + status + sampleTestCase + judgerAvailable + judgeType + mysqlSchemas + libraryUrl + } +} diff --git a/src/main/resources/graphql/questionOfToday.graphql b/src/main/resources/graphql/questionOfToday.graphql new file mode 100644 index 00000000..1ca19c77 --- /dev/null +++ b/src/main/resources/graphql/questionOfToday.graphql @@ -0,0 +1,23 @@ +query questionOfToday { + activeDailyCodingChallengeQuestion { + date + userStatus + question { + acRate + difficulty + freqBar + frontendQuestionId: questionFrontendId + paidOnly: isPaidOnly + status + title + titleSlug + hasSolution + topicTags { + name + id + slug + } + } + } +} + \ No newline at end of file diff --git a/src/main/resources/graphql/questionOfToday_cn.graphql b/src/main/resources/graphql/questionOfToday_cn.graphql new file mode 100644 index 00000000..dcc4935c --- /dev/null +++ b/src/main/resources/graphql/questionOfToday_cn.graphql @@ -0,0 +1,26 @@ +query questionOfToday { + activeDailyCodingChallengeQuestion: todayRecord { + date + userStatus + question { + questionId + frontendQuestionId: questionFrontendId + difficulty + title + titleCn: translatedTitle + titleSlug + paidOnly: isPaidOnly + freqBar + isFavor + acRate + status + solutionNum + hasVideoSolution + topicTags { + name + nameTranslated: translatedName + id + } + } + } +} diff --git a/src/main/resources/graphql/questionSolutionArticles.graphql b/src/main/resources/graphql/questionSolutionArticles.graphql new file mode 100644 index 00000000..9a12d082 --- /dev/null +++ b/src/main/resources/graphql/questionSolutionArticles.graphql @@ -0,0 +1,27 @@ +query questionSolutionArticles($questionSlug: String!, $skip: Int, $first: Int, $orderBy: SolutionArticleOrderBy, $userInput: String, $tagSlugs: [String!]) { + questionSolutionArticles(questionSlug: $questionSlug, skip: $skip, first: $first, orderBy: $orderBy, userInput: $userInput, tagSlugs: $tagSlugs) { + totalNum + edges { + node { + ...solutionArticle + __typename + } + __typename + } + __typename + } +} + +fragment solutionArticle on SolutionArticleNode { + uuid + title + slug + status + identifier + tags { + name + } + summary + hitCount + __typename +} diff --git a/src/main/resources/graphql/questionSolutionArticles_cn.graphql b/src/main/resources/graphql/questionSolutionArticles_cn.graphql new file mode 100644 index 00000000..9a12d082 --- /dev/null +++ b/src/main/resources/graphql/questionSolutionArticles_cn.graphql @@ -0,0 +1,27 @@ +query questionSolutionArticles($questionSlug: String!, $skip: Int, $first: Int, $orderBy: SolutionArticleOrderBy, $userInput: String, $tagSlugs: [String!]) { + questionSolutionArticles(questionSlug: $questionSlug, skip: $skip, first: $first, orderBy: $orderBy, userInput: $userInput, tagSlugs: $tagSlugs) { + totalNum + edges { + node { + ...solutionArticle + __typename + } + __typename + } + __typename + } +} + +fragment solutionArticle on SolutionArticleNode { + uuid + title + slug + status + identifier + tags { + name + } + summary + hitCount + __typename +} diff --git a/src/main/resources/graphql/randomQuestion.graphql b/src/main/resources/graphql/randomQuestion.graphql new file mode 100644 index 00000000..ead0f4cb --- /dev/null +++ b/src/main/resources/graphql/randomQuestion.graphql @@ -0,0 +1,5 @@ +query randomQuestion($categorySlug: String, $filters: QuestionListFilterInput) { + randomQuestion(categorySlug: $categorySlug, filters: $filters) { + titleSlug + } +} \ No newline at end of file diff --git a/src/main/resources/graphql/randomQuestion_cn.graphql b/src/main/resources/graphql/randomQuestion_cn.graphql new file mode 100644 index 00000000..8a3f9567 --- /dev/null +++ b/src/main/resources/graphql/randomQuestion_cn.graphql @@ -0,0 +1,3 @@ +query randomQuestion($categorySlug: String!, $filters: QuestionListFilterInput) { + randomQuestion: problemsetRandomFilteredQuestion(categorySlug: $categorySlug, filters: $filters) +} diff --git a/src/main/resources/graphql/removeQuestionFromFavorite.graphql b/src/main/resources/graphql/removeQuestionFromFavorite.graphql new file mode 100644 index 00000000..87429d12 --- /dev/null +++ b/src/main/resources/graphql/removeQuestionFromFavorite.graphql @@ -0,0 +1,9 @@ +mutation removeQuestionFromFavorite($favoriteIdHash: String!, $questionId: String!) { + removeQuestionFromFavorite(favoriteIdHash: $favoriteIdHash, questionId: $questionId) { + ok + error + favoriteIdHash + questionId + __typename + } +} diff --git a/src/main/resources/graphql/solutionDetailArticle.graphql b/src/main/resources/graphql/solutionDetailArticle.graphql new file mode 100644 index 00000000..0d046d15 --- /dev/null +++ b/src/main/resources/graphql/solutionDetailArticle.graphql @@ -0,0 +1,7 @@ +query solutionDetailArticle($titleSlug: String!) { + solutionArticle: question(titleSlug: $titleSlug) { + solution { + content + } + } +} diff --git a/src/main/resources/graphql/solutionDetailArticle_cn.graphql b/src/main/resources/graphql/solutionDetailArticle_cn.graphql new file mode 100644 index 00000000..227d9d91 --- /dev/null +++ b/src/main/resources/graphql/solutionDetailArticle_cn.graphql @@ -0,0 +1,5 @@ +query solutionDetailArticle($slug: String!, $orderBy: SolutionArticleOrderBy!) { + solutionArticle(slug: $slug, orderBy: $orderBy) { + content + } +} diff --git a/src/main/resources/graphql/submissionDetail_cn.graphql b/src/main/resources/graphql/submissionDetail_cn.graphql new file mode 100644 index 00000000..f7b8a436 --- /dev/null +++ b/src/main/resources/graphql/submissionDetail_cn.graphql @@ -0,0 +1,34 @@ +query submissionDetail($id: ID!) { + submissionDetail(submissionId: $id) { + id + code + runtime + memory + statusDisplay + timestamp + lang + passedTestCaseCnt + totalTestCaseCnt + sourceUrl + question { + titleSlug + title + translatedTitle + questionId + __typename + } + ... on GeneralSubmissionNode { + outputDetail { + codeOutput + expectedOutput + input + compileError + runtimeError + lastTestcase + __typename + } + __typename + } + __typename + } +} \ No newline at end of file diff --git a/src/main/resources/graphql/submissions.graphql b/src/main/resources/graphql/submissions.graphql new file mode 100644 index 00000000..18afe565 --- /dev/null +++ b/src/main/resources/graphql/submissions.graphql @@ -0,0 +1,18 @@ +query submissions($offset: Int!, $limit: Int!, $lastKey: String, $questionSlug: String!) { + submissionList(offset: $offset, limit: $limit, lastKey: $lastKey, questionSlug: $questionSlug) { + lastKey + hasNext + submissions { + id + statusDisplay + lang + runtime + timestamp + url + isPending + memory + __typename + } + __typename + } +} \ No newline at end of file diff --git a/src/main/resources/graphql/updateNote.graphql b/src/main/resources/graphql/updateNote.graphql new file mode 100644 index 00000000..b87bc81d --- /dev/null +++ b/src/main/resources/graphql/updateNote.graphql @@ -0,0 +1,12 @@ +mutation updateNote($titleSlug: String!, $content: String!) { + updateNote(titleSlug: $titleSlug, content: $content) { + ok + error + question { + questionId + note + __typename + } + __typename + } +} diff --git a/src/main/resources/graphql/userStatus.graphql b/src/main/resources/graphql/userStatus.graphql new file mode 100644 index 00000000..4747a545 --- /dev/null +++ b/src/main/resources/graphql/userStatus.graphql @@ -0,0 +1,12 @@ +query userStatus { + userStatus { + isSignedIn + isPremium + username + avatar + isAdmin + isSuperuser + isTranslator + isVerified + } +} diff --git a/src/main/resources/graphql/userStatus_cn.graphql b/src/main/resources/graphql/userStatus_cn.graphql new file mode 100644 index 00000000..6d736325 --- /dev/null +++ b/src/main/resources/graphql/userStatus_cn.graphql @@ -0,0 +1,13 @@ +query userStatus { + userStatus { + isSignedIn + isPremium + username + avatar + isAdmin + isSuperuser + isTranslator + isVerified + isPhoneVerified + } +} diff --git a/src/main/resources/i18n/info.properties b/src/main/resources/i18n/info.properties index cd105375..ff61d7f9 100644 --- a/src/main/resources/i18n/info.properties +++ b/src/main/resources/i18n/info.properties @@ -40,4 +40,5 @@ tree.null=Questions returned are empty tree.select=Please select a valid question in the list Lang=en_US browser.login.success=Login is successful. close the window -tree.host=The current topic does not match the URL in the configuration \ No newline at end of file +tree.host=The current topic does not match the URL in the configuration +note.load=The current question notes are not synchronized, please synchronize \ No newline at end of file diff --git a/src/main/resources/i18n/info_zh.properties b/src/main/resources/i18n/info_zh.properties index 3a1b0142..29b8f1b2 100644 --- a/src/main/resources/i18n/info_zh.properties +++ b/src/main/resources/i18n/info_zh.properties @@ -40,4 +40,5 @@ tree.null=\u83B7\u53D6\u9898\u76EE\u4E3A\u7A7A,\u8BF7\u5C1D\u8BD5\u91CD\u65B0\u4 tree.select=\u8BF7\u5728\u5217\u8868\u4E2D\u9009\u62E9\u4E00\u4E2A\u6709\u6548\u7684\u9898\u76EE Lang=zh_CN browser.login.success=\u767B\u5F55\u6210\u529F,\u8BF7\u624B\u52A8\u5173\u95ED\u6B64\u7A97\u53E3 -tree.host=\u5F53\u524D\u9898\u76EE\u4E0E\u914D\u7F6E\u4E2D\u7684URL\u4E0D\u7B26 \ No newline at end of file +tree.host=\u5F53\u524D\u9898\u76EE\u4E0E\u914D\u7F6E\u4E2D\u7684URL\u4E0D\u7B26 +note.load=\u5F53\u524D\u9898\u76EE\u7B14\u8BB0\u672A\u540C\u6B65,\u8BF7\u540C\u6B65 \ No newline at end of file diff --git a/src/main/resources/icons/config_lc.svg b/src/main/resources/icons/config_lc.svg new file mode 100644 index 00000000..aaa48977 --- /dev/null +++ b/src/main/resources/icons/config_lc.svg @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/icons/config_lc_dark.svg b/src/main/resources/icons/config_lc_dark.svg new file mode 100644 index 00000000..aba1d916 --- /dev/null +++ b/src/main/resources/icons/config_lc_dark.svg @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/icons/pull.svg b/src/main/resources/icons/pull.svg new file mode 100644 index 00000000..a0421ea5 --- /dev/null +++ b/src/main/resources/icons/pull.svg @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/icons/pull_dark.svg b/src/main/resources/icons/pull_dark.svg new file mode 100644 index 00000000..59a10f86 --- /dev/null +++ b/src/main/resources/icons/pull_dark.svg @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/icons/push.svg b/src/main/resources/icons/push.svg new file mode 100644 index 00000000..e5cf82ec --- /dev/null +++ b/src/main/resources/icons/push.svg @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/icons/push_dark.svg b/src/main/resources/icons/push_dark.svg new file mode 100644 index 00000000..905b5978 --- /dev/null +++ b/src/main/resources/icons/push_dark.svg @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/icons/share.svg b/src/main/resources/icons/share.svg new file mode 100644 index 00000000..4b41277e --- /dev/null +++ b/src/main/resources/icons/share.svg @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/icons/share_dark.svg b/src/main/resources/icons/share_dark.svg new file mode 100644 index 00000000..4fbfe8ce --- /dev/null +++ b/src/main/resources/icons/share_dark.svg @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/icons/show.svg b/src/main/resources/icons/show.svg new file mode 100644 index 00000000..b02ddcac --- /dev/null +++ b/src/main/resources/icons/show.svg @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/icons/show_dark.svg b/src/main/resources/icons/show_dark.svg new file mode 100644 index 00000000..753ed5a8 --- /dev/null +++ b/src/main/resources/icons/show_dark.svg @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/icons/toggle.svg b/src/main/resources/icons/toggle.svg new file mode 100644 index 00000000..2c5d06cb --- /dev/null +++ b/src/main/resources/icons/toggle.svg @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/icons/toggle_dark.svg b/src/main/resources/icons/toggle_dark.svg new file mode 100644 index 00000000..e4e189b6 --- /dev/null +++ b/src/main/resources/icons/toggle_dark.svg @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/template/allTip.txt b/src/main/resources/template/allTip.txt new file mode 100644 index 00000000..6a359496 --- /dev/null +++ b/src/main/resources/template/allTip.txt @@ -0,0 +1,16 @@ +You are browsing "All Problem List" window. +For first-time installation, Click {0} to configure the plugin. +Click {1} or {2} to load questions,Click {3} to switch to other windows. + +Toolbar introduction: + {4} Log in. (The login accounts of the two websites are not interoperable, users need to reconfigure while switching the corresponding websites.) + {5} Log out. (Exit the current account, if you encounter a login error, try to exit first.) + {6} Load or refresh problems. (You still could refresh or load questions even if you are not logged in, but you could not submit the answer.) + {7} Open a problem randomly. + {8} Open filter panel. (You can search, filter and sort.) + {9} Based on the current editor content, locate the position of the corresponding problem in the list. + {10} Open the Session panel. (You can view or switch sessions.) + {11} Switch to other list windows, including "All Problem List" , "Paginated Problem List" , "CodeTop Problem List". + {12} Open configuration panel. + {13} Clear all problem cache files. + {14} Open help page. \ No newline at end of file diff --git a/src/main/resources/template/allTip_cn.txt b/src/main/resources/template/allTip_cn.txt new file mode 100644 index 00000000..e9b04c95 --- /dev/null +++ b/src/main/resources/template/allTip_cn.txt @@ -0,0 +1,16 @@ +正在浏览"所有的题目列表"窗口. +首次安装请先点击{0}进行配置. +点击{1}或者{2}加载题目,点击{3}切换到其他窗口. + +工具栏介绍: + {4} 登录(两个网站的登录账号不互通,在切换网站时需要重新配置用户.) + {5} 退出登录(退出当前账号,遇到登录问题时可以尝试先退出.) + {6} 加载或刷新题目(即使没有登录,仍然可以刷新或加载题目,但无法提交答案.) + {7} 随机一个题目. + {8} 打开筛选面板(可以进行搜索、过滤或者排序.) + {9} 根据当前编辑器内容,定位对应题目在列表中的位置. + {10} 打开进度面板(可以查看或者切换进度.) + {11} 切换到其他列表窗口,包括"所有题目列表"、"分页题目列表"、"CodeTop题目列表". + {12} 打开配置面板. + {13} 清空所有题目缓存文件. + {14} 打开帮助页面. \ No newline at end of file diff --git a/src/main/resources/template/codeTopTip.txt b/src/main/resources/template/codeTopTip.txt new file mode 100644 index 00000000..a670ad39 --- /dev/null +++ b/src/main/resources/template/codeTopTip.txt @@ -0,0 +1,15 @@ +You are browsing "CodeTop Problem List" window.The data is from CodeTop. +Click {0} to open the CodeTop webpage for more functions. +For first-time installation, Click {1} to configure the plugin. +Click {2} to load questions,Click {3} to switch to other windows. + +Toolbar introduction: + {4} Log in LeetCode,Sync Problems status.(The login accounts of the two websites are not interoperable, users need to reconfigure while switching the corresponding websites.) + {5} Log out. (Exit the current account, if you encounter a login error, try to exit first.) + {6} Load or refresh problems. (You still could refresh or load questions even if you are not logged in, but you could not submit the answer.) + {7} Open filter panel. (You can filter and sort.) + {8} Open the CodeTop webpage + {9} Switch to other list windows, including "All Problem List" , "Paginated Problem List" , "CodeTop Problem List". + {10} Open configuration panel. + {11} Clear all problem cache files. + {12} Open help page. \ No newline at end of file diff --git a/src/main/resources/template/codeTopTip_cn.txt b/src/main/resources/template/codeTopTip_cn.txt new file mode 100644 index 00000000..113112ab --- /dev/null +++ b/src/main/resources/template/codeTopTip_cn.txt @@ -0,0 +1,15 @@ +正在浏览"CodeTop的题目列表"窗口,数据来自CodeTop,更多功能请点击{0}打开CodeTop网页. +首次安装请先点击{1}进行配置. +点击{2}加载题目,点击{3}切换到其他窗口. + + +工具栏介绍: + {4} 登录LeetCode,同步题目状态(两个网站的登录账号不互通,在切换网站时需要重新配置用户.) + {5} 退出登录(退出当前账号,遇到登录问题时可以尝试先退出.) + {6} 加载或刷新题目(即使没有登录,仍然可以刷新或加载题目,但无法提交答案.) + {7} 打开筛选面板(可以进行过滤或者排序.) + {8} 打开CodeTop网页. + {9} 切换到其他列表窗口,包括"所有题目列表"、"分页题目列表"、"CodeTop题目列表". + {10} 打开配置面板. + {11} 清空所有题目缓存. + {12} 打开帮助页面. \ No newline at end of file diff --git a/src/main/resources/template/pageTip.txt b/src/main/resources/template/pageTip.txt new file mode 100644 index 00000000..99ff29e4 --- /dev/null +++ b/src/main/resources/template/pageTip.txt @@ -0,0 +1,16 @@ +You are browsing "Paginated Problem List" window. +For first-time installation, Click {0} to configure the plugin. +Click {1} or {2} to load questions,Click {3} to switch to other windows. + +Toolbar introduction: + {4} Log in. (The login accounts of the two websites are not interoperable, users need to reconfigure while switching the corresponding websites.) + {5} Log out. (Exit the current account, if you encounter a login error, try to exit first.) + {6} Load or refresh problems. (You still could refresh or load questions even if you are not logged in, but you could not submit the answer.) + {7} Open a problem randomly. + {8} Open filter panel. (You can search, filter and sort.) + {9} Based on the current editor content, locate the position of the corresponding problem in the list. + {10} Open the Session panel. (You can view or switch sessions.) + {11} Switch to other list windows, including "All Problem List" , "Paginated Problem List" , "CodeTop Problem List". + {12} Open configuration panel. + {13} Clear all problem cache files. + {14} Open help page. \ No newline at end of file diff --git a/src/main/resources/template/pageTip_cn.txt b/src/main/resources/template/pageTip_cn.txt new file mode 100644 index 00000000..9d233129 --- /dev/null +++ b/src/main/resources/template/pageTip_cn.txt @@ -0,0 +1,16 @@ +正在浏览"分页的题目列表"窗口. +首次安装请先点击{0}进行配置. +点击{1}或者{2}加载题目,点击{3}切换到其他窗口. + +工具栏介绍: + {4} 登录(两个网站的登录账号不互通,在切换网站时需要重新配置用户.) + {5} 退出登录(退出当前账号,遇到登录问题时可以尝试先退出.) + {6} 加载或刷新题目(即使没有登录,仍然可以刷新或加载题目,但无法提交答案.) + {7} 随机一个题目. + {8} 打开筛选面板(可以进行搜索、过滤或者排序.) + {9} 根据当前编辑器内容,定位对应题目在列表中的位置. + {10} 打开进度面板(可以查看或者切换进度) + {11} 切换到其他列表窗口,包括"所有题目列表"、"分页题目列表"、"CodeTop题目列表". + {12} 打开配置面板. + {13} 清空所有题目缓存文件. + {14} 打开帮助页面. \ No newline at end of file