├── .clang-format
├── .github
├── dependabot.yml
└── workflows
│ ├── ci_build.yml
│ └── codeql.yml
├── .gitignore
├── .gitmodules
├── LICENSE
├── README.md
├── external
└── npp
│ ├── Docking.h
│ ├── DockingDlgInterface.h
│ ├── Notepad_plus_msgs.h
│ ├── PluginInterface.h
│ ├── Scintilla.h
│ ├── StaticDialog.cpp
│ ├── StaticDialog.h
│ ├── URLCtrl.cpp
│ ├── URLCtrl.h
│ ├── Window.h
│ ├── dockingResource.h
│ └── menuCmdID.h
├── src
├── NPPJSONViewer.sln
├── NppJsonViewer
│ ├── AboutDlg.cpp
│ ├── AboutDlg.h
│ ├── Define.h
│ ├── JsonHandler.cpp
│ ├── JsonHandler.h
│ ├── JsonNode.h
│ ├── JsonViewDlg.cpp
│ ├── JsonViewDlg.h
│ ├── NPPJSONViewer.vcxproj
│ ├── NPPJSONViewer.vcxproj.filters
│ ├── NppJsonPlugin.cpp
│ ├── NppJsonPlugin.h
│ ├── Profile.cpp
│ ├── Profile.h
│ ├── RapidJsonHandler.cpp
│ ├── RapidJsonHandler.h
│ ├── ScintillaEditor.cpp
│ ├── ScintillaEditor.h
│ ├── SettingsDlg.cpp
│ ├── SettingsDlg.h
│ ├── ShortcutCommand.cpp
│ ├── ShortcutCommand.h
│ ├── SliderCtrl.cpp
│ ├── SliderCtrl.h
│ ├── StopWatch.h
│ ├── TrackingStream.h
│ ├── TreeHandler.h
│ ├── TreeViewCtrl.cpp
│ ├── TreeViewCtrl.h
│ ├── dllmain.cpp
│ ├── res
│ │ ├── Icon.ico
│ │ ├── Refresh.ico
│ │ ├── format.ico
│ │ ├── search.ico
│ │ └── validate.ico
│ ├── resource.h
│ └── resource.rc
├── NppJsonViewerCommon.props
└── UtilityLib
│ ├── Execute.cpp
│ ├── Execute.h
│ ├── StringHelper.cpp
│ ├── StringHelper.h
│ ├── Utility.cpp
│ ├── Utility.h
│ ├── UtilityLib.vcxproj
│ └── UtilityLib.vcxproj.filters
└── tests
└── UnitTest
├── JsonCompressTest.cpp
├── JsonFormatTest.cpp
├── JsonHandlerTest.cpp
├── NavigationTest.cpp
├── ProfileTest.cpp
├── StringHelperTest.cpp
├── UnitTest.vcxproj
├── UnitTest.vcxproj.filters
├── UtilityTest.cpp
└── main.cpp
/.clang-format:
--------------------------------------------------------------------------------
1 | ---
2 | BasedOnStyle: Microsoft
3 | AccessModifierOffset: '-4'
4 | AlignAfterOpenBracket: AlwaysBreak
5 | AlignConsecutiveMacros: 'true'
6 | AlignConsecutiveAssignments: 'true'
7 | AlignConsecutiveDeclarations: 'true'
8 | AlignEscapedNewlines: Left
9 | AlignOperands: 'true'
10 | AlignTrailingComments: 'true'
11 | AllowAllArgumentsOnNextLine: 'false'
12 | AllowAllConstructorInitializersOnNextLine: 'true'
13 | AllowAllParametersOfDeclarationOnNextLine: 'false'
14 | AllowShortBlocksOnASingleLine: 'true'
15 | AllowShortCaseLabelsOnASingleLine: 'false'
16 | AllowShortFunctionsOnASingleLine: Empty
17 | AllowShortEnumsOnASingleLine: 'true'
18 | AllowShortIfStatementsOnASingleLine: Never
19 | AllowShortLambdasOnASingleLine: Empty
20 | AllowShortLoopsOnASingleLine: 'false'
21 | AlwaysBreakAfterReturnType: None
22 | AlwaysBreakBeforeMultilineStrings: 'false'
23 | AlwaysBreakTemplateDeclarations: 'Yes'
24 | BinPackArguments: 'false'
25 | BinPackParameters: 'false'
26 | BreakBeforeBinaryOperators: All
27 | BreakBeforeBraces: Allman
28 | BreakBeforeTernaryOperators: 'true'
29 | BreakConstructorInitializers: BeforeComma
30 | BreakInheritanceList: BeforeComma
31 | BreakStringLiterals: 'true'
32 | ColumnLimit: '180'
33 | CompactNamespaces: 'false'
34 | ConstructorInitializerAllOnOneLineOrOnePerLine: 'false'
35 | Cpp11BracedListStyle: 'true'
36 | DisableFormat: 'false'
37 | FixNamespaceComments: 'true'
38 | IncludeBlocks: Regroup
39 | IndentPPDirectives: BeforeHash
40 | IndentWidth: '4'
41 | KeepEmptyLinesAtTheStartOfBlocks: 'false'
42 | Language: Cpp
43 | MaxEmptyLinesToKeep: '2'
44 | NamespaceIndentation: All
45 | PointerAlignment: Left
46 | ReflowComments: 'true'
47 | SortIncludes: 'false'
48 | SortUsingDeclarations: 'true'
49 | SpaceAfterCStyleCast: 'false'
50 | SpaceAfterLogicalNot: 'false'
51 | SpaceAfterTemplateKeyword: 'true'
52 | SpaceBeforeAssignmentOperators: 'true'
53 | SpaceBeforeCpp11BracedList: 'true'
54 | SpaceBeforeCtorInitializerColon: 'true'
55 | SpaceBeforeInheritanceColon: 'true'
56 | SpaceBeforeParens: ControlStatements
57 | SpaceBeforeRangeBasedForLoopColon: 'true'
58 | SpaceInEmptyParentheses: 'false'
59 | SpacesBeforeTrailingComments: '4'
60 | SpacesInAngles: 'false'
61 | SpacesInCStyleCastParentheses: 'false'
62 | SpacesInContainerLiterals: 'false'
63 | SpacesInParentheses: 'false'
64 | SpacesInSquareBrackets: 'false'
65 | Standard: Cpp11
66 | TabWidth: '4'
67 | UseTab: Never
68 |
69 | ...
70 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # Basic set up for updating github-actions
2 |
3 | version: 2
4 | updates:
5 |
6 | # Maintain dependencies for GitHub Actions
7 | - package-ecosystem: "github-actions"
8 | directory: "/"
9 | schedule:
10 | interval: "monthly"
11 |
--------------------------------------------------------------------------------
/.github/workflows/ci_build.yml:
--------------------------------------------------------------------------------
1 | name: Build and Test
2 |
3 | on:
4 | push:
5 | branches: [ "master" ]
6 | pull_request:
7 | branches: [ "master" ]
8 |
9 | env:
10 | BUILD_DIR: src\Build\Bin
11 | MSBUILD_TOOLSET: v143
12 | ARTIFACT_PREFIX: NppJSONViewer_
13 |
14 | jobs:
15 | build:
16 | runs-on: windows-latest
17 | strategy:
18 | fail-fast: false
19 | matrix:
20 | build_configuration: [Release, Debug]
21 | build_platform: [Win32, x64, ARM64]
22 |
23 | steps:
24 | # Step 1: Check out the code from the repo
25 | - name: Checkout repo
26 | uses: actions/checkout@v4
27 | with:
28 | submodules: recursive
29 |
30 | # Step 2: Prepare for build
31 | - name: Setup MSBuild
32 | uses: microsoft/setup-msbuild@v2
33 |
34 | # Step 3: Build projects and unit test
35 | - name: Build code
36 | working-directory: src
37 | run: msbuild NppJSONViewer.sln /m /p:configuration="${{matrix.build_configuration}}" /p:platform="${{matrix.build_platform}}" /p:PlatformToolset=${{env.MSBUILD_TOOLSET}}
38 |
39 | # Step 4: Upload build binary artifacts for deployment
40 | - name: Archive binaries artifacts
41 | uses: actions/upload-artifact@v4
42 | with:
43 | name: ${{env.ARTIFACT_PREFIX}}${{matrix.build_platform}}_${{matrix.build_configuration}}
44 | path: ${{env.BUILD_DIR }}\${{matrix.build_configuration}}\${{matrix.build_platform}}\NPPJSONViewer.dll
45 |
46 | # Step 5: Upload build pdb artifacts
47 | - name: Archive symbols artifacts
48 | uses: actions/upload-artifact@v4
49 | with:
50 | name: ${{env.ARTIFACT_PREFIX}}${{matrix.build_platform}}_${{matrix.build_configuration}}_pdb
51 | path: ${{env.BUILD_DIR }}\${{matrix.build_configuration}}\${{matrix.build_platform}}\NPPJSONViewer.pdb
52 |
53 | # Step 6: Run unit tests for x86 and x64
54 | - name: Run unit tests
55 | if: matrix.build_platform == 'Win32' || matrix.build_platform == 'x64'
56 | run: |
57 | cd ${{env.BUILD_DIR}}\${{matrix.build_configuration}}\${{matrix.build_platform}}
58 | ./UnitTest.exe
59 |
60 | upload-full-artifacts:
61 | # Trigger this job only after all 'build' jobs are complete
62 | needs: build
63 | runs-on: windows-latest
64 | strategy:
65 | fail-fast: true
66 |
67 | steps:
68 | # Step 7: Download all artifacts from the build job
69 | - name: Download all artifacts
70 | uses: actions/download-artifact@v4
71 | with:
72 | pattern: ${{env.ARTIFACT_PREFIX}}*
73 | path: all_artifacts\
74 |
75 | # Step 8: Upload consolidated artifacts as a single artifact
76 | - name: Upload full artifact
77 | uses: actions/upload-artifact@v4
78 | with:
79 | name: ${{env.ARTIFACT_PREFIX}}ALL
80 | path: all_artifacts\**
81 |
--------------------------------------------------------------------------------
/.github/workflows/codeql.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "Code Scanning"
13 |
14 | on:
15 | push:
16 | branches: [ "master" ]
17 | pull_request:
18 | branches: [ "master" ]
19 | schedule:
20 | - cron: '34 11 * * 1'
21 |
22 | permissions:
23 | contents: read
24 |
25 | concurrency:
26 | group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
27 | cancel-in-progress: true
28 |
29 | jobs:
30 | analyze:
31 | name: Analyze
32 | runs-on: windows-latest
33 | timeout-minutes: 20
34 | permissions:
35 | actions: read
36 | contents: read
37 | security-events: write
38 |
39 | strategy:
40 | fail-fast: false
41 | matrix:
42 | language: [ 'c-cpp' ]
43 |
44 | steps:
45 | - name: Checkout repository
46 | uses: actions/checkout@v4
47 | with:
48 | submodules: recursive
49 |
50 | # Initializes the CodeQL tools for scanning.
51 | - name: Initialize CodeQL
52 | uses: github/codeql-action/init@v3
53 | with:
54 | languages: ${{ matrix.language }}
55 |
56 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
57 | # If this step fails, then you should remove it and run the build manually (see below)
58 | - name: Autobuild
59 | uses: github/codeql-action/autobuild@v3
60 |
61 | - name: Perform CodeQL Analysis
62 | uses: github/codeql-action/analyze@v3
63 |
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # Visual Studio/ VSCode cache/options directory
11 | .vs/
12 | .vscode/
13 |
14 | # Visual C++ cache files
15 | *.aps
16 | *.ncb
17 | *.opendb
18 | *.opensdf
19 | *.sdf
20 | *.cachefile
21 | *.obj
22 | *.tlog
23 | *.exp
24 | *.log
25 | *.pch
26 | *.ilk
27 | *.idb
28 |
29 | # Build Results/artifacts
30 | src/Build/
31 | *.dll
32 | *.exe
33 | *.lib
34 | *.pdb
35 | *.recipe
36 |
37 | # Others
38 | *.zip
39 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "external/rapidjson"]
2 | path = external/rapidjson
3 | url = https://github.com/NPP-JSONViewer/rapidjson.git
4 | [submodule "external/googletest"]
5 | path = external/googletest
6 | url = https://github.com/google/googletest.git
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Kapil Ratnani
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JSONViewer for Notepad++
2 | [](../../releases/latest)
3 | [](https://github.com/kapilratnani/JSON-Viewer/actions/workflows/ci_build.yml)
4 | [](https://github.com/kapilratnani/JSON-Viewer/actions/workflows/codeql.yml)
5 |
6 | This plugin is designed to display JSON strings in a Treeview format and highlight the error position if any parsing issues occur. It's a simple and efficient tool, compatible with [Notepad++](https://github.com/notepad-plus-plus/notepad-plus-plus).
7 |
8 |
9 | ## Instructions:
10 | 1. Copy the file `NPPJSONViewer.dll` to the `plugins\NPPJSONViewer` folder in the Notepad++ installation directory..
11 | 2. Restart Notepad++ and ensure the plugin appears under the Plugins menu.
12 | 3. Open a document containing a JSON string (or paste in some JSON text).
13 | 4. Select the JSON fragment and go to Plugins > JSON Viewer > Show JSON Viewer or press or press Ctrl+Alt+Shift+J.
14 | 5. Voila, that's it! If the JSON is valid, it will be displayed in a Treeview format.
15 |
16 |
17 | ## Latest Updates:
18 |
19 | ### 2.1.1.0
20 |
21 | 1. New features:
22 | 1. Zoom tree view with ctrl + `mouse wheel` or slider.
23 |
24 |
25 | 2. Bug/regression fixes:
26 | 1. Updated to the latest RapidJSON parser.
27 | 2. Minor code enhancements for improved performance.
28 | 3. Added unit tests
29 |
30 |
31 | ### 2.1.0.0
32 |
33 | 1. New features:
34 | 1. Navigate directly to the JSON node in the editor upon node selection (using left mouse click or arrow keys).
35 | 2. Select the JSON key in the editor when double-clicking on a node.
36 |
37 |
38 | 2. Bug/regression fixes:
39 | 1. Updated to the latest RapidJSON parser.
40 | 2. Minor code enhancements for improved performance.
41 | 3. Added unit tests
42 |
43 |
44 | ### 2.0.8.0
45 |
46 | 1. New features:
47 | 1. Sort ascending by key
48 | 2. Add file name in the title for visibility
49 |
50 |
51 | 2. Bug/regression fixes:
52 | 1. Updated license text on UI as per GitHub link
53 | 2. Explicit callout for no support on multi selection
54 | 3. Some other minor code and UI enhancements
55 |
56 |
57 | ### 2.0.7.0
58 | Bug/regression fixes:
59 | 1. "Copy value" / "Copy" not always return complete text
60 | 2. Format JSON option does not work if focused tab is in other view
61 | 3. Corrected some typos on setting dialog
62 | 4. Updated icons to match with dark mode as well
63 | 5. Removed quotes from the key in Treeview
64 | 6. Some other minor enhancements
65 |
66 | ### 2.0.6.0
67 | 1. New feature:
68 | 1. Replace value 'undefined' with 'null'. This is configurable feature.
69 | 2. Bug/regression fixes:
70 | 1. Cyrillic text is not properly shown in json tree view dialog
71 |
72 | ### 2.0.5.0
73 | 1. New feature:
74 | 1. Make json highlighter configurable
75 | 2. Bug/regression fixes:
76 | 1. Handle json for both the views.
77 | 2. Update treeview on reopen
78 | 3. When file type is json, then error message is shown twice on npp launch if viewer dock was kept opened on previous instance
79 | 4. Don't show error message on startup for non json files
80 |
81 | ### 2.0.4.0
82 | 1. New feature:
83 | 1. Show element count for list/array
84 | 2. Bug/regression fixes:
85 | 1. Crash fix: Setting dialog is not shown if about dialog is opened before it.
86 | 2. Set language type JSON properly
87 | 3. Some minor UI enhancements
88 |
89 | ### 2.0.3.0
90 | 1. New feature:
91 | 1. Search in json tree window
92 | 2. Handle NaN, Inf, -Inf, Infinity, -Infinity properly
93 | 2. Bug/regression fixes:
94 | 1. Handle all types of arrays which does not have any key
95 | 2. Corrected typos in setting json
96 | 3. Don't use double qoutes for other than string type
97 |
98 |
99 | ### 2.0.2.0
100 | 1. Provided UI to control formatting option via setting dialog
101 | 1. Setting for indentation
102 | 2. Setting for line ending
103 | 3. Setting for line format
104 | 4. Make json parsing configurable e.g. ignore trailing comma, ignore comment
105 | 2. Added couple of new feature
106 | 1. Follow json tree for current tab if it is json file
107 | 2. Auto format json file when opened (by direct or by tab switching)
108 | 3. Few bug/regression fixes
109 |
110 | ### 2.0.1.0
111 | 1. Redeveloped UI
112 | 1. Provided menu icon
113 | 2. Json view panel is redesigned which is button like, refresh, validate, format etc.
114 | 3. It uses well performed class instead of plain function
115 | 2. Current selected node path is given on the bottom of json view window
116 | 3. Many feature support such as copy node, copy value, copy path, expand/collapse all etc.
117 | 4. Few bug fixes
118 |
119 |
120 | ### 1.41
121 | 1. Support for ARM64
122 | 2. Dropped Windows XP support as Notepad++ is no more supporting Windows XP.
123 | 3. Upgrade Visual Studio to 2022
124 |
125 |
126 | ### 1.40
127 | 1. issue-55 Format JSON should also set the language to JSON #FeatureRequest
128 | 2. issue-56 Format Should Follow Line Break Settings
129 | 3. issue-57, issue-60 "Should add a function to remove line breaks and spaces" Thanks @neoarc
130 | 4. issue-68 Crashing Notepad++
131 | 5. issue-72 tab setting from notepad++ settings are not honored
132 | 6. issue-73 Display tree for Array of Object
133 | 7. issue-80 use line ending setting from editor
134 | 8. Relaxed parsing. Supports trailing commas, comments(only parsing), NaN and infinity JS literals.
135 |
136 | ### 1.34
137 | 1. Fix Access Violation issue #51
138 | 2. Fix issue #47
139 | 3. Fix issue #43
140 |
141 | ### 1.31
142 | 1. Reads tab setting from notepad++ settings
143 |
144 | ### 1.30a
145 | 1. Now using rapidjson
146 |
147 | ### 1.24
148 | 1. 64 bit support. Thanks @chcg
149 |
150 | ### 1.23
151 | 1. Select all text when no selection
152 | Thanks @vakio
153 | 2. fix memory leak and close About dialog when clicking "Close" button
154 | Thanks @quangnh89
155 |
156 | ### 1.22
157 | 1. Fixed display of boolean values. Now displaying as "key":True/False
158 | Thanks @yoyokenny
159 | 2. Fixed hang on faulty JSON.
160 | Thanks @vancekic
161 |
162 | ### 1.21
163 | 1. Fixed display of UTF-8 characters.
164 |
165 | ### 1.20
166 | 1. Fixed bug "#3 quoted doublequotes-Jan Huschauer"
167 |
168 | ### 1.19
169 | 1. Added a command to format JSON
170 |
171 | ### 1.175
172 | 1. Now displays a message box when JSON string is not selected.
173 |
174 | ### 1.17
175 | 1. Fixed dialog display issue, that occurred in 1.16 release.
176 |
177 | ### 1.16
178 | 1. Fixed bug - 3305433 do not find error on second try and do not build tree
179 | 2. Fixed a memory leak..was not de-allocating memory allocated to json strings
180 |
181 | ### 1.15
182 | 1. Fixed bug 3203739 "Unable to parse JSON Arrays"
183 |
184 | ### 1.1
185 | 1. Fixed hotkey, now press CTRL+SHIFT+ALT+J(default).
186 | 2. Marks error position in JSON
187 |
188 |
189 | ## Contributors
190 |
191 |
192 |
193 |
194 |
195 |
196 |
--------------------------------------------------------------------------------
/external/npp/Docking.h:
--------------------------------------------------------------------------------
1 | /*
2 | this file is part of Function List Plugin for Notepad++
3 | Copyright (C)2005 Jens Lorenz
4 |
5 | This program is free software; you can redistribute it and/or
6 | modify it under the terms of the GNU General Public License
7 | as published by the Free Software Foundation; either
8 | version 2 of the License, or (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program; if not, write to the Free Software
17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 | */
19 |
20 | #ifndef DOCKING_H
21 | #define DOCKING_H
22 |
23 | // ATTENTION : It's a part of interface header, so don't include the others header here
24 |
25 | // styles for containers
26 | #define CAPTION_TOP TRUE
27 | #define CAPTION_BOTTOM FALSE
28 |
29 | // defines for docking manager
30 | #define CONT_LEFT 0
31 | #define CONT_RIGHT 1
32 | #define CONT_TOP 2
33 | #define CONT_BOTTOM 3
34 | #define DOCKCONT_MAX 4
35 |
36 | // mask params for plugins of internal dialogs
37 | #define DWS_ICONTAB 0x00000001 // Icon for tabs are available
38 | #define DWS_ICONBAR 0x00000002 // Icon for icon bar are available (currently not supported)
39 | #define DWS_ADDINFO 0x00000004 // Additional information are in use
40 | #define DWS_PARAMSALL (DWS_ICONTAB|DWS_ICONBAR|DWS_ADDINFO)
41 |
42 | // default docking values for first call of plugin
43 | #define DWS_DF_CONT_LEFT (CONT_LEFT << 28) // default docking on left
44 | #define DWS_DF_CONT_RIGHT (CONT_RIGHT << 28) // default docking on right
45 | #define DWS_DF_CONT_TOP (CONT_TOP << 28) // default docking on top
46 | #define DWS_DF_CONT_BOTTOM (CONT_BOTTOM << 28) // default docking on bottom
47 | #define DWS_DF_FLOATING 0x80000000 // default state is floating
48 |
49 |
50 | typedef struct {
51 | HWND hClient; // client Window Handle
52 | TCHAR *pszName; // name of plugin (shown in window)
53 | int dlgID; // a funcItem provides the function pointer to start a dialog. Please parse here these ID
54 |
55 | // user modifications
56 | UINT uMask; // mask params: look to above defines
57 | HICON hIconTab; // icon for tabs
58 | TCHAR *pszAddInfo; // for plugin to display additional informations
59 |
60 | // internal data, do not use !!!
61 | RECT rcFloat; // floating position
62 | int iPrevCont; // stores the privious container (toggling between float and dock)
63 | const TCHAR* pszModuleName; // it's the plugin file name. It's used to identify the plugin
64 | } tTbData;
65 |
66 |
67 | typedef struct {
68 | HWND hWnd; // the docking manager wnd
69 | RECT rcRegion[DOCKCONT_MAX]; // position of docked dialogs
70 | } tDockMgr;
71 |
72 |
73 | #define HIT_TEST_THICKNESS 20
74 | #define SPLITTER_WIDTH 4
75 |
76 |
77 | #endif // DOCKING_H
78 |
--------------------------------------------------------------------------------
/external/npp/DockingDlgInterface.h:
--------------------------------------------------------------------------------
1 | /*
2 | this file is part of Function List Plugin for Notepad++
3 | Copyright (C)2005 Jens Lorenz
4 |
5 | This program is free software; you can redistribute it and/or
6 | modify it under the terms of the GNU General Public License
7 | as published by the Free Software Foundation; either
8 | version 2 of the License, or (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program; if not, write to the Free Software
17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 | */
19 |
20 | #pragma once
21 |
22 | #include "StaticDialog.h"
23 | #include "dockingResource.h"
24 | #include "Docking.h"
25 | #include
26 |
27 |
28 | class DockingDlgInterface : public StaticDialog
29 | {
30 | public:
31 | DockingDlgInterface() : StaticDialog() {};
32 | DockingDlgInterface(int dlgID) : StaticDialog(), _dlgID(dlgID) {};
33 |
34 | virtual void init(HINSTANCE hInst, HWND parent)
35 | {
36 | StaticDialog::init(hInst, parent);
37 | ::GetModuleFileName((HMODULE)hInst, _moduleName, MAX_PATH);
38 | lstrcpy(_moduleName, PathFindFileName(_moduleName));
39 | }
40 |
41 | void create(tTbData * data, bool isRTL = false)
42 | {
43 | StaticDialog::create(_dlgID, isRTL);
44 | ::GetWindowText(_hSelf, _pluginName, _countof(_pluginName));
45 |
46 | // user information
47 | data->hClient = _hSelf;
48 | data->pszName = _pluginName;
49 |
50 | // supported features by plugin
51 | data->uMask = 0;
52 |
53 | // additional info
54 | data->pszAddInfo = NULL;
55 | _data = data;
56 |
57 | }
58 |
59 | virtual void updateDockingDlg(void)
60 | {
61 | ::SendMessage(_hParent, NPPM_DMMUPDATEDISPINFO, 0, (LPARAM)_hSelf);
62 | }
63 |
64 | virtual void destroy() {}
65 |
66 | virtual void display(bool toShow = true) const
67 | {
68 | ::SendMessage(_hParent, toShow ? NPPM_DMMSHOW : NPPM_DMMHIDE, 0, (LPARAM)_hSelf);
69 | }
70 |
71 | const TCHAR * getPluginFileName() const { return _moduleName; }
72 |
73 | protected:
74 | virtual INT_PTR CALLBACK run_dlgProc(UINT message, WPARAM /*wParam*/, LPARAM lParam)
75 | {
76 | switch (message)
77 | {
78 |
79 | case WM_NOTIFY:
80 | {
81 | LPNMHDR pnmh = (LPNMHDR)lParam;
82 |
83 | if (pnmh->hwndFrom == _hParent)
84 | {
85 | switch (LOWORD(pnmh->code))
86 | {
87 | case DMN_CLOSE:
88 | {
89 | break;
90 | }
91 | case DMN_FLOAT:
92 | {
93 | _isFloating = true;
94 | break;
95 | }
96 | case DMN_DOCK:
97 | {
98 | _isFloating = false;
99 | break;
100 | }
101 | default:
102 | break;
103 | }
104 | }
105 | break;
106 | }
107 | default:
108 | break;
109 | }
110 | return FALSE;
111 | };
112 |
113 | // Handles
114 | HWND _HSource = nullptr;
115 | tTbData* _data = nullptr;
116 | int _dlgID = 0;
117 | bool _isFloating = false;
118 | TCHAR _moduleName[MAX_PATH] = {};
119 | TCHAR _pluginName[MAX_PATH] = {};
120 | };
121 |
--------------------------------------------------------------------------------
/external/npp/PluginInterface.h:
--------------------------------------------------------------------------------
1 | // This file is part of Notepad++ project
2 | // Copyright (C)2003 Don HO
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either
7 | // version 2 of the License, or (at your option) any later version.
8 | //
9 | // Note that the GPL places important restrictions on "derived works", yet
10 | // it does not provide a detailed definition of that term. To avoid
11 | // misunderstandings, we consider an application to constitute a
12 | // "derivative work" for the purpose of this license if it does any of the
13 | // following:
14 | // 1. Integrates source code from Notepad++.
15 | // 2. Integrates/includes/aggregates Notepad++ into a proprietary executable
16 | // installer, such as those produced by InstallShield.
17 | // 3. Links to a library or executes a program that does any of the above.
18 | //
19 | // This program is distributed in the hope that it will be useful,
20 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | // GNU General Public License for more details.
23 | //
24 | // You should have received a copy of the GNU General Public License
25 | // along with this program; if not, write to the Free Software
26 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 |
28 |
29 | #ifndef PLUGININTERFACE_H
30 | #define PLUGININTERFACE_H
31 |
32 | #ifndef SCINTILLA_H
33 | #include "Scintilla.h"
34 | #endif //SCINTILLA_H
35 |
36 | #ifndef NOTEPAD_PLUS_MSGS_H
37 | #include "Notepad_plus_msgs.h"
38 | #endif //NOTEPAD_PLUS_MSGS_H
39 |
40 | const int nbChar = 64;
41 |
42 | typedef const TCHAR * (__cdecl * PFUNCGETNAME)();
43 |
44 | struct NppData
45 | {
46 | HWND _nppHandle;
47 | HWND _scintillaMainHandle;
48 | HWND _scintillaSecondHandle;
49 | };
50 |
51 | typedef void (__cdecl * PFUNCSETINFO)(NppData);
52 | typedef void (__cdecl * PFUNCPLUGINCMD)();
53 | typedef void (__cdecl * PBENOTIFIED)(SCNotification *);
54 | typedef LRESULT (__cdecl * PMESSAGEPROC)(UINT Message, WPARAM wParam, LPARAM lParam);
55 |
56 |
57 | struct ShortcutKey
58 | {
59 | bool _isCtrl;
60 | bool _isAlt;
61 | bool _isShift;
62 | UCHAR _key;
63 | };
64 |
65 | struct FuncItem
66 | {
67 | TCHAR _itemName[nbChar];
68 | PFUNCPLUGINCMD _pFunc;
69 | int _cmdID;
70 | bool _init2Check;
71 | ShortcutKey *_pShKey;
72 | };
73 |
74 | typedef FuncItem * (__cdecl * PFUNCGETFUNCSARRAY)(int *);
75 |
76 | // You should implement (or define an empty function body) those functions which are called by Notepad++ plugin manager
77 | extern "C" __declspec(dllexport) void setInfo(NppData);
78 | extern "C" __declspec(dllexport) const TCHAR * getName();
79 | extern "C" __declspec(dllexport) FuncItem * getFuncsArray(int *);
80 | extern "C" __declspec(dllexport) void beNotified(SCNotification *);
81 | extern "C" __declspec(dllexport) LRESULT messageProc(UINT Message, WPARAM wParam, LPARAM lParam);
82 |
83 | // This API return always true now, since Notepad++ isn't compiled in ANSI mode anymore
84 | extern "C" __declspec(dllexport) BOOL isUnicode();
85 |
86 |
87 | #endif //PLUGININTERFACE_H
88 |
--------------------------------------------------------------------------------
/external/npp/StaticDialog.cpp:
--------------------------------------------------------------------------------
1 | //this file is part of notepad++
2 | //Copyright (C)2003 Don HO ( donho@altern.org )
3 | //
4 | //This program is free software; you can redistribute it and/or
5 | //modify it under the terms of the GNU General Public License
6 | //as published by the Free Software Foundation; either
7 | //version 2 of the License, or (at your option) any later version.
8 | //
9 | //This program is distributed in the hope that it will be useful,
10 | //but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | //GNU General Public License for more details.
13 | //
14 | //You should have received a copy of the GNU General Public License
15 | //along with this program; if not, write to the Free Software
16 | //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 |
18 | #include
19 | #include "StaticDialog.h"
20 |
21 | void StaticDialog::goToCenter()
22 | {
23 | RECT rc;
24 | ::GetClientRect(_hParent, &rc);
25 | POINT center;
26 | center.x = rc.left + (rc.right - rc.left)/2;
27 | center.y = rc.top + (rc.bottom - rc.top)/2;
28 | ::ClientToScreen(_hParent, ¢er);
29 |
30 | int x = center.x - (_rc.right - _rc.left)/2;
31 | int y = center.y - (_rc.bottom - _rc.top)/2;
32 |
33 | ::SetWindowPos(_hSelf, HWND_TOP, x, y, _rc.right - _rc.left, _rc.bottom - _rc.top, SWP_SHOWWINDOW);
34 | }
35 |
36 | HGLOBAL StaticDialog::makeRTLResource(int dialogID, DLGTEMPLATE **ppMyDlgTemplate)
37 | {
38 | // Get Dlg Template resource
39 | HRSRC hDialogRC = ::FindResource(_hInst, MAKEINTRESOURCE(dialogID), RT_DIALOG);
40 | if (!hDialogRC)
41 | return NULL;
42 |
43 | HGLOBAL hDlgTemplate = ::LoadResource(_hInst, hDialogRC);
44 | if (!hDlgTemplate)
45 | return NULL;
46 |
47 | DLGTEMPLATE *pDlgTemplate = reinterpret_cast(::LockResource(hDlgTemplate));
48 | if (!pDlgTemplate)
49 | return NULL;
50 |
51 | // Duplicate Dlg Template resource
52 | unsigned long sizeDlg = ::SizeofResource(_hInst, hDialogRC);
53 | HGLOBAL hMyDlgTemplate = ::GlobalAlloc(GPTR, sizeDlg);
54 | if (hMyDlgTemplate)
55 | {
56 | *ppMyDlgTemplate = reinterpret_cast(::GlobalLock(hMyDlgTemplate));
57 | if (*ppMyDlgTemplate)
58 | {
59 | ::memcpy(*ppMyDlgTemplate, pDlgTemplate, sizeDlg);
60 |
61 | DLGTEMPLATEEX *pMyDlgTemplateEx = reinterpret_cast(*ppMyDlgTemplate);
62 | if (pMyDlgTemplateEx->signature == 0xFFFF)
63 | pMyDlgTemplateEx->exStyle |= WS_EX_LAYOUTRTL;
64 | else
65 | (*ppMyDlgTemplate)->dwExtendedStyle |= WS_EX_LAYOUTRTL;
66 | }
67 | }
68 |
69 | return hMyDlgTemplate;
70 | }
71 |
72 | void StaticDialog::create(int dialogID, bool isRTL)
73 | {
74 | if (isRTL)
75 | {
76 | DLGTEMPLATE *pMyDlgTemplate = NULL;
77 | HGLOBAL hMyDlgTemplate = makeRTLResource(dialogID, &pMyDlgTemplate);
78 | _hSelf = ::CreateDialogIndirectParam(_hInst, pMyDlgTemplate, _hParent, dlgProc, reinterpret_cast(this));
79 | ::GlobalFree(hMyDlgTemplate);
80 | }
81 | else
82 | _hSelf = ::CreateDialogParam(_hInst, MAKEINTRESOURCE(dialogID), _hParent, dlgProc, reinterpret_cast(this));
83 |
84 | if (!_hSelf)
85 | {
86 | DWORD err = ::GetLastError();
87 | char errMsg[256] {};
88 | sprintf_s(errMsg, "CreateDialogParam() return NULL.\rGetLastError() == %lu", err);
89 | ::MessageBoxA(NULL, errMsg, "In StaticDialog::create()", MB_OK);
90 | return;
91 | }
92 |
93 | // if the destination of message NPPM_MODELESSDIALOG is not its parent, then it's the grand-parent
94 | ::SendMessage(_hParent, NPPM_MODELESSDIALOG, MODELESSDIALOGADD, reinterpret_cast(_hSelf));
95 | }
96 |
97 | INT_PTR CALLBACK StaticDialog::dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
98 | {
99 | switch (message)
100 | {
101 | case WM_INITDIALOG:
102 | {
103 | StaticDialog *pStaticDlg = reinterpret_cast(lParam);
104 | pStaticDlg->_hSelf = hwnd;
105 | ::SetWindowLongPtr(hwnd, GWLP_USERDATA, static_cast(lParam));
106 | ::GetWindowRect(hwnd, &(pStaticDlg->_rc));
107 | pStaticDlg->run_dlgProc(message, wParam, lParam);
108 |
109 | return TRUE;
110 | }
111 |
112 | default:
113 | {
114 | StaticDialog *pStaticDlg = reinterpret_cast(::GetWindowLongPtr(hwnd, GWLP_USERDATA));
115 | if (!pStaticDlg)
116 | return FALSE;
117 | return pStaticDlg->run_dlgProc(message, wParam, lParam);
118 | }
119 | }
120 | }
121 |
122 | void StaticDialog::alignWith(HWND handle, HWND handle2Align, PosAlign pos, POINT & point)
123 | {
124 | RECT rc, rc2;
125 | ::GetWindowRect(handle, &rc);
126 |
127 | point.x = rc.left;
128 | point.y = rc.top;
129 |
130 | switch (pos)
131 | {
132 | case PosAlign::left:
133 | {
134 | ::GetWindowRect(handle2Align, &rc2);
135 | point.x -= rc2.right - rc2.left;
136 | break;
137 | }
138 | case PosAlign::right:
139 | {
140 | ::GetWindowRect(handle, &rc2);
141 | point.x += rc2.right - rc2.left;
142 | break;
143 | }
144 | case PosAlign::top:
145 | {
146 | ::GetWindowRect(handle2Align, &rc2);
147 | point.y -= rc2.bottom - rc2.top;
148 | break;
149 | }
150 | case PosAlign::bottom:
151 | {
152 | ::GetWindowRect(handle, &rc2);
153 | point.y += rc2.bottom - rc2.top;
154 | break;
155 | }
156 | }
157 |
158 | ::ScreenToClient(_hSelf, &point);
159 | }
160 |
161 |
--------------------------------------------------------------------------------
/external/npp/StaticDialog.h:
--------------------------------------------------------------------------------
1 | //this file is part of notepad++
2 | //Copyright (C)2003 Don HO ( donho@altern.org )
3 | //
4 | //This program is free software; you can redistribute it and/or
5 | //modify it under the terms of the GNU General Public License
6 | //as published by the Free Software Foundation; either
7 | //version 2 of the License, or (at your option) any later version.
8 | //
9 | //This program is distributed in the hope that it will be useful,
10 | //but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | //GNU General Public License for more details.
13 | //
14 | //You should have received a copy of the GNU General Public License
15 | //along with this program; if not, write to the Free Software
16 | //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 |
18 | #pragma once
19 |
20 | #include "Window.h"
21 | #include "Notepad_plus_msgs.h"
22 | typedef HRESULT(WINAPI* ETDTProc) (HWND, DWORD);
23 |
24 | enum class PosAlign { left, right, top, bottom };
25 |
26 | struct DLGTEMPLATEEX {
27 | WORD dlgVer;
28 | WORD signature;
29 | DWORD helpID;
30 | DWORD exStyle;
31 | DWORD style;
32 | WORD cDlgItems;
33 | short x;
34 | short y;
35 | short cx;
36 | short cy;
37 | // The structure has more fields but are variable length
38 | } ;
39 |
40 | class StaticDialog : public Window
41 | {
42 | public :
43 | StaticDialog() : Window() {};
44 | ~StaticDialog(){
45 | if (isCreated()) {
46 | ::SetWindowLongPtr(_hSelf, GWLP_USERDATA, (long)NULL); //Prevent run_dlgProc from doing anything, since its virtual
47 | destroy();
48 | }
49 | };
50 | virtual void create(int dialogID, bool isRTL = false);
51 |
52 | virtual bool isCreated() const {
53 | return (_hSelf != NULL);
54 | };
55 |
56 | void goToCenter();
57 | void destroy() {
58 | ::SendMessage(_hParent, NPPM_MODELESSDIALOG, MODELESSDIALOGREMOVE, (WPARAM)_hSelf);
59 | ::DestroyWindow(_hSelf);
60 | };
61 |
62 | protected :
63 | RECT _rc{};
64 | static INT_PTR CALLBACK dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
65 | virtual INT_PTR CALLBACK run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) = 0;
66 |
67 | void alignWith(HWND handle, HWND handle2Align, PosAlign pos, POINT & point);
68 | HGLOBAL makeRTLResource(int dialogID, DLGTEMPLATE **ppMyDlgTemplate);
69 | };
70 |
71 |
--------------------------------------------------------------------------------
/external/npp/URLCtrl.cpp:
--------------------------------------------------------------------------------
1 | // This file is part of Notepad++ project
2 | // Copyright (C)2003 Don HO
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either
7 | // version 2 of the License, or (at your option) any later version.
8 | //
9 | // Note that the GPL places important restrictions on "derived works", yet
10 | // it does not provide a detailed definition of that term. To avoid
11 | // misunderstandings, we consider an application to constitute a
12 | // "derivative work" for the purpose of this license if it does any of the
13 | // following:
14 | // 1. Integrates source code from Notepad++.
15 | // 2. Integrates/includes/aggregates Notepad++ into a proprietary executable
16 | // installer, such as those produced by InstallShield.
17 | // 3. Links to a library or executes a program that does any of the above.
18 | //
19 | // This program is distributed in the hope that it will be useful,
20 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | // GNU General Public License for more details.
23 | //
24 | // You should have received a copy of the GNU General Public License
25 | // along with this program; if not, write to the Free Software
26 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 |
28 |
29 | #include "URLCtrl.h"
30 |
31 | void URLCtrl::create(HWND itemHandle, const TCHAR* link, COLORREF linkColor)
32 | {
33 | // turn on notify style
34 | ::SetWindowLongPtr(itemHandle, GWL_STYLE, ::GetWindowLongPtr(itemHandle, GWL_STYLE) | SS_NOTIFY);
35 |
36 | // set the URL text (not the display text)
37 | if (link)
38 | _URL = link;
39 |
40 | // set the hyperlink colour
41 | _linkColor = linkColor;
42 |
43 | // set the visited colour
44 | _visitedColor = RGB(128, 0, 128);
45 |
46 | // subclass the static control
47 | _oldproc = reinterpret_cast(::SetWindowLongPtr(itemHandle, GWLP_WNDPROC, reinterpret_cast(URLCtrlProc)));
48 |
49 | // associate the URL structure with the static control
50 | ::SetWindowLongPtr(itemHandle, GWLP_USERDATA, reinterpret_cast(this));
51 |
52 | // save hwnd
53 | _hSelf = itemHandle;
54 | }
55 | void URLCtrl::create(HWND itemHandle, int cmd, HWND msgDest)
56 | {
57 | // turn on notify style
58 | ::SetWindowLongPtr(itemHandle, GWL_STYLE, ::GetWindowLongPtr(itemHandle, GWL_STYLE) | SS_NOTIFY);
59 |
60 | _cmdID = cmd;
61 | _msgDest = msgDest;
62 |
63 | // set the hyperlink colour
64 | _linkColor = RGB(0, 0, 255);
65 |
66 | // subclass the static control
67 | _oldproc = reinterpret_cast(::SetWindowLongPtr(itemHandle, GWLP_WNDPROC, reinterpret_cast(URLCtrlProc)));
68 |
69 | // associate the URL structure with the static control
70 | ::SetWindowLongPtr(itemHandle, GWLP_USERDATA, reinterpret_cast(this));
71 |
72 | // save hwnd
73 | _hSelf = itemHandle;
74 | }
75 |
76 | void URLCtrl::destroy()
77 | {
78 | if (_hfUnderlined)
79 | ::DeleteObject(_hfUnderlined);
80 | if (_hCursor)
81 | ::DestroyCursor(_hCursor);
82 | }
83 |
84 | void URLCtrl::action()
85 | {
86 | if (_cmdID)
87 | {
88 | ::SendMessage(_msgDest ? _msgDest : _hParent, WM_COMMAND, _cmdID, 0);
89 | }
90 | else
91 | {
92 | _linkColor = _visitedColor;
93 |
94 | ::InvalidateRect(_hSelf, 0, 0);
95 | ::UpdateWindow(_hSelf);
96 |
97 | // Open a browser
98 | if (_URL != TEXT(""))
99 | {
100 | ::ShellExecute(NULL, TEXT("open"), _URL.c_str(), NULL, NULL, SW_SHOWNORMAL);
101 | }
102 | else
103 | {
104 | TCHAR szWinText[MAX_PATH];
105 | ::GetWindowText(_hSelf, szWinText, MAX_PATH);
106 | ::ShellExecute(NULL, TEXT("open"), szWinText, NULL, NULL, SW_SHOWNORMAL);
107 | }
108 | }
109 | }
110 |
111 | COLORREF URLCtrl::getCtrlBgColor(HWND hWnd)
112 | {
113 | COLORREF crRet = CLR_INVALID;
114 | if (hWnd && IsWindow(hWnd))
115 | {
116 | RECT rc;
117 | if (GetClientRect(hWnd, &rc))
118 | {
119 | HDC hDC = GetDC(hWnd);
120 | if (hDC)
121 | {
122 | HDC hdcMem = CreateCompatibleDC(hDC);
123 | if (hdcMem)
124 | {
125 | HBITMAP hBmp = CreateCompatibleBitmap(hDC,
126 | rc.right, rc.bottom);
127 | if (hBmp)
128 | {
129 | HGDIOBJ hOld = SelectObject(hdcMem, hBmp);
130 | if (hOld)
131 | {
132 | if (SendMessage(hWnd, WM_ERASEBKGND, reinterpret_cast(hdcMem), 0))
133 | {
134 | crRet = GetPixel(hdcMem, 2, 2); // 0, 0 is usually on the border
135 | }
136 | SelectObject(hdcMem, hOld);
137 | }
138 | DeleteObject(hBmp);
139 | }
140 | DeleteDC(hdcMem);
141 | }
142 | ReleaseDC(hWnd, hDC);
143 | }
144 | }
145 | }
146 | return crRet;
147 | }
148 |
149 | LRESULT URLCtrl::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
150 | {
151 | switch (Message)
152 | {
153 | // Free up the structure we allocated
154 | case WM_NCDESTROY:
155 | //HeapFree(GetProcessHeap(), 0, url);
156 | break;
157 |
158 | // Paint the static control using our custom
159 | // colours, and with an underline text style
160 | case WM_PAINT:
161 | {
162 | DWORD dwStyle = static_cast(::GetWindowLongPtr(hwnd, GWL_STYLE));
163 | DWORD dwDTStyle = DT_SINGLELINE;
164 |
165 | //Test if centered horizontally or vertically
166 | if (dwStyle & SS_CENTER) dwDTStyle |= DT_CENTER;
167 | if (dwStyle & SS_RIGHT) dwDTStyle |= DT_RIGHT;
168 | if (dwStyle & SS_CENTERIMAGE) dwDTStyle |= DT_VCENTER;
169 |
170 | RECT rect;
171 | ::GetClientRect(hwnd, &rect);
172 |
173 | PAINTSTRUCT ps;
174 | HDC hdc = ::BeginPaint(hwnd, &ps);
175 |
176 | ::SetTextColor(hdc, _linkColor);
177 |
178 | ::SetBkColor(hdc, getCtrlBgColor(GetParent(hwnd))); ///*::GetSysColor(COLOR_3DFACE)*/);
179 |
180 | // Create an underline font
181 | if (_hfUnderlined == 0)
182 | {
183 | // Get the default GUI font
184 | LOGFONT lf;
185 | HFONT hf = (HFONT)::GetStockObject(DEFAULT_GUI_FONT);
186 |
187 | // Add UNDERLINE attribute
188 | GetObject(hf, sizeof lf, &lf);
189 | lf.lfUnderline = TRUE;
190 |
191 | // Create a new font
192 | _hfUnderlined = ::CreateFontIndirect(&lf);
193 | }
194 |
195 | HANDLE hOld = SelectObject(hdc, _hfUnderlined);
196 |
197 | // Draw the text!
198 | TCHAR szWinText[MAX_PATH];
199 | ::GetWindowText(hwnd, szWinText, MAX_PATH);
200 | ::DrawText(hdc, szWinText, -1, &rect, dwDTStyle);
201 |
202 | ::SelectObject(hdc, hOld);
203 |
204 | ::EndPaint(hwnd, &ps);
205 |
206 | return 0;
207 | }
208 |
209 | case WM_SETTEXT:
210 | {
211 | LRESULT ret = ::CallWindowProc(_oldproc, hwnd, Message, wParam, lParam);
212 | ::InvalidateRect(hwnd, 0, 0);
213 | return ret;
214 | }
215 | // Provide a hand cursor when the mouse moves over us
216 | case WM_SETCURSOR:
217 | case WM_MOUSEMOVE:
218 | {
219 | if (_hCursor == 0)
220 | _hCursor = LoadCursor(NULL, IDC_HAND);
221 |
222 | SetCursor(_hCursor);
223 | return TRUE;
224 | }
225 |
226 | case WM_LBUTTONDOWN:
227 | _clicking = true;
228 | break;
229 |
230 | case WM_LBUTTONUP:
231 | if (_clicking)
232 | {
233 | _clicking = false;
234 |
235 | action();
236 | }
237 |
238 | break;
239 |
240 | //Support using space to activate this object
241 | case WM_KEYDOWN:
242 | if (wParam == VK_SPACE)
243 | _clicking = true;
244 | break;
245 |
246 | case WM_KEYUP:
247 | if (wParam == VK_SPACE && _clicking)
248 | {
249 | _clicking = false;
250 |
251 | action();
252 | }
253 | break;
254 |
255 | // A standard static control returns HTTRANSPARENT here, which
256 | // prevents us from receiving any mouse messages. So, return
257 | // HTCLIENT instead.
258 | case WM_NCHITTEST:
259 | return HTCLIENT;
260 | }
261 | return ::CallWindowProc(_oldproc, hwnd, Message, wParam, lParam);
262 | }
263 |
--------------------------------------------------------------------------------
/external/npp/URLCtrl.h:
--------------------------------------------------------------------------------
1 | // This file is part of Notepad++ project
2 | // Copyright (C)2003 Don HO
3 | //
4 | // This program is free software; you can redistribute it and/or
5 | // modify it under the terms of the GNU General Public License
6 | // as published by the Free Software Foundation; either
7 | // version 2 of the License, or (at your option) any later version.
8 | //
9 | // Note that the GPL places important restrictions on "derived works", yet
10 | // it does not provide a detailed definition of that term. To avoid
11 | // misunderstandings, we consider an application to constitute a
12 | // "derivative work" for the purpose of this license if it does any of the
13 | // following:
14 | // 1. Integrates source code from Notepad++.
15 | // 2. Integrates/includes/aggregates Notepad++ into a proprietary executable
16 | // installer, such as those produced by InstallShield.
17 | // 3. Links to a library or executes a program that does any of the above.
18 | //
19 | // This program is distributed in the hope that it will be useful,
20 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | // GNU General Public License for more details.
23 | //
24 | // You should have received a copy of the GNU General Public License
25 | // along with this program; if not, write to the Free Software
26 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 |
28 |
29 | #pragma once
30 |
31 | #include "Window.h"
32 | #include
33 |
34 | class URLCtrl : public Window
35 | {
36 | public:
37 | URLCtrl() = default;
38 |
39 | void create(HWND itemHandle, const TCHAR* link, COLORREF linkColor = RGB(0, 0, 255));
40 | void create(HWND itemHandle, int cmd, HWND msgDest = NULL);
41 | void destroy();
42 |
43 | private:
44 | void action();
45 | COLORREF getCtrlBgColor(HWND hWnd);
46 |
47 | protected:
48 | std::wstring _URL = TEXT("");
49 | HFONT _hfUnderlined = nullptr;
50 | HCURSOR _hCursor = nullptr;
51 | HWND _msgDest = nullptr;
52 | unsigned long _cmdID = 0;
53 |
54 | WNDPROC _oldproc = nullptr;
55 | COLORREF _linkColor;
56 | COLORREF _visitedColor;
57 | bool _clicking = false;
58 |
59 | static LRESULT CALLBACK URLCtrlProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
60 | {
61 | return (reinterpret_cast(::GetWindowLongPtr(hwnd, GWLP_USERDATA)))->runProc(hwnd, Message, wParam, lParam);
62 | }
63 |
64 | LRESULT runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);
65 | };
66 |
67 |
--------------------------------------------------------------------------------
/external/npp/Window.h:
--------------------------------------------------------------------------------
1 | //this file is part of notepad++
2 | //Copyright (C)2003 Don HO
3 | //
4 | //This program is free software; you can redistribute it and/or
5 | //modify it under the terms of the GNU General Public License
6 | //as published by the Free Software Foundation; either
7 | //version 2 of the License, or (at your option) any later version.
8 | //
9 | //This program is distributed in the hope that it will be useful,
10 | //but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | //GNU General Public License for more details.
13 | //
14 | //You should have received a copy of the GNU General Public License
15 | //along with this program; if not, write to the Free Software
16 | //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 |
18 | #ifndef WINDOW_CONTROL_H
19 | #define WINDOW_CONTROL_H
20 |
21 | #include
22 |
23 | class Window
24 | {
25 | public:
26 | Window(): _hInst(NULL), _hParent(NULL), _hSelf(NULL){};
27 | virtual ~Window() {};
28 |
29 | virtual void init(HINSTANCE hInst, HWND parent)
30 | {
31 | _hInst = hInst;
32 | _hParent = parent;
33 | }
34 |
35 | virtual void destroy() = 0;
36 |
37 | virtual void display(bool toShow = true) const {
38 | ::ShowWindow(_hSelf, toShow?SW_SHOW:SW_HIDE);
39 | };
40 |
41 | virtual void reSizeTo(RECT & rc) // should NEVER be const !!!
42 | {
43 | ::MoveWindow(_hSelf, rc.left, rc.top, rc.right, rc.bottom, TRUE);
44 | redraw();
45 | };
46 |
47 | virtual void reSizeToWH(RECT & rc) // should NEVER be const !!!
48 | {
49 | ::MoveWindow(_hSelf, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
50 | redraw();
51 | };
52 |
53 | virtual void redraw(bool forceUpdate = false) const {
54 | ::InvalidateRect(_hSelf, NULL, TRUE);
55 | if (forceUpdate)
56 | ::UpdateWindow(_hSelf);
57 | };
58 |
59 | virtual void getClientRect(RECT & rc) const {
60 | ::GetClientRect(_hSelf, &rc);
61 | };
62 |
63 | virtual void getWindowRect(RECT & rc) const {
64 | ::GetWindowRect(_hSelf, &rc);
65 | };
66 |
67 | virtual int getWidth() const {
68 | RECT rc;
69 | ::GetClientRect(_hSelf, &rc);
70 | return (rc.right - rc.left);
71 | };
72 |
73 | virtual int getHeight() const {
74 | RECT rc;
75 | ::GetClientRect(_hSelf, &rc);
76 | if (::IsWindowVisible(_hSelf) == TRUE)
77 | return (rc.bottom - rc.top);
78 | return 0;
79 | };
80 |
81 | virtual bool isVisible() const {
82 | return (::IsWindowVisible(_hSelf)?true:false);
83 | };
84 |
85 | HWND getHSelf() const {
86 | //assert(_hSelf);
87 | return _hSelf;
88 | };
89 |
90 | HWND getHParent() const {
91 | return _hParent;
92 | };
93 |
94 | void getFocus() const {
95 | ::SetFocus(_hSelf);
96 | };
97 |
98 | HINSTANCE getHinst() const {
99 | if (!_hInst)
100 | {
101 | ::MessageBox(NULL, TEXT("_hInst == NULL"), TEXT("class Window"), MB_OK);
102 | throw int(1999);
103 | }
104 | return _hInst;
105 | };
106 | protected:
107 | HINSTANCE _hInst;
108 | HWND _hParent;
109 | HWND _hSelf;
110 | };
111 |
112 | #endif //WINDOW_CONTROL_H
113 |
114 |
115 |
--------------------------------------------------------------------------------
/external/npp/dockingResource.h:
--------------------------------------------------------------------------------
1 | //this file is part of docking functionality for Notepad++
2 | //Copyright (C)2006 Jens Lorenz
3 | //
4 | //This program is free software; you can redistribute it and/or
5 | //modify it under the terms of the GNU General Public License
6 | //as published by the Free Software Foundation; either
7 | //version 2 of the License, or (at your option) any later version.
8 | //
9 | //This program is distributed in the hope that it will be useful,
10 | //but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | //GNU General Public License for more details.
13 | //
14 | //You should have received a copy of the GNU General Public License
15 | //along with this program; if not, write to the Free Software
16 | //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 |
18 | #ifndef DOCKING_RESOURCE_H
19 | #define DOCKING_RESOURCE_H
20 |
21 | #define IDD_PLUGIN_DLG 103
22 | #define IDC_EDIT1 1000
23 |
24 |
25 | #define IDB_CLOSE_DOWN 137
26 | #define IDB_CLOSE_UP 138
27 | #define IDD_CONTAINER_DLG 139
28 |
29 | #define IDC_TAB_CONT 1027
30 | #define IDC_CLIENT_TAB 1028
31 | #define IDC_BTN_CAPTION 1050
32 |
33 | #define DMM_MSG 0x5000
34 | #define DMM_CLOSE (DMM_MSG + 1)
35 | #define DMM_DOCK (DMM_MSG + 2)
36 | #define DMM_FLOAT (DMM_MSG + 3)
37 | #define DMM_DOCKALL (DMM_MSG + 4)
38 | #define DMM_FLOATALL (DMM_MSG + 5)
39 | #define DMM_MOVE (DMM_MSG + 6)
40 | #define DMM_UPDATEDISPINFO (DMM_MSG + 7)
41 | #define DMM_GETIMAGELIST (DMM_MSG + 8)
42 | #define DMM_GETICONPOS (DMM_MSG + 9)
43 | #define DMM_DROPDATA (DMM_MSG + 10)
44 | #define DMM_MOVE_SPLITTER (DMM_MSG + 11)
45 | #define DMM_CANCEL_MOVE (DMM_MSG + 12)
46 | #define DMM_LBUTTONUP (DMM_MSG + 13)
47 |
48 | #define DMN_FIRST 1050
49 | #define DMN_CLOSE (DMN_FIRST + 1)
50 | //nmhdr.code = DWORD(DMN_CLOSE, 0));
51 | //nmhdr.hwndFrom = hwndNpp;
52 | //nmhdr.idFrom = ctrlIdNpp;
53 |
54 | #define DMN_DOCK (DMN_FIRST + 2)
55 | #define DMN_FLOAT (DMN_FIRST + 3)
56 | //nmhdr.code = DWORD(DMN_XXX, int newContainer);
57 | //nmhdr.hwndFrom = hwndNpp;
58 | //nmhdr.idFrom = ctrlIdNpp;
59 |
60 |
61 |
62 | #endif //DOCKING_RESOURCE_H
63 |
64 |
--------------------------------------------------------------------------------
/src/NPPJSONViewer.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.3.32804.467
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NPPJSONViewer", "NppJsonViewer\NPPJSONViewer.vcxproj", "{1590D7CD-7D3A-4AB7-A355-EE02F7FB987D}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UtilityLib", "UtilityLib\UtilityLib.vcxproj", "{171CAFC6-E679-4B81-BF5B-049AC0FAB4F8}"
9 | EndProject
10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTest", "..\tests\UnitTest\UnitTest.vcxproj", "{5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|ARM64 = Debug|ARM64
15 | Debug|Win32 = Debug|Win32
16 | Debug|x64 = Debug|x64
17 | Release|ARM64 = Release|ARM64
18 | Release|Win32 = Release|Win32
19 | Release|x64 = Release|x64
20 | EndGlobalSection
21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 | {1590D7CD-7D3A-4AB7-A355-EE02F7FB987D}.Debug|ARM64.ActiveCfg = Debug|ARM64
23 | {1590D7CD-7D3A-4AB7-A355-EE02F7FB987D}.Debug|ARM64.Build.0 = Debug|ARM64
24 | {1590D7CD-7D3A-4AB7-A355-EE02F7FB987D}.Debug|Win32.ActiveCfg = Debug|Win32
25 | {1590D7CD-7D3A-4AB7-A355-EE02F7FB987D}.Debug|Win32.Build.0 = Debug|Win32
26 | {1590D7CD-7D3A-4AB7-A355-EE02F7FB987D}.Debug|x64.ActiveCfg = Debug|x64
27 | {1590D7CD-7D3A-4AB7-A355-EE02F7FB987D}.Debug|x64.Build.0 = Debug|x64
28 | {1590D7CD-7D3A-4AB7-A355-EE02F7FB987D}.Release|ARM64.ActiveCfg = Release|ARM64
29 | {1590D7CD-7D3A-4AB7-A355-EE02F7FB987D}.Release|ARM64.Build.0 = Release|ARM64
30 | {1590D7CD-7D3A-4AB7-A355-EE02F7FB987D}.Release|Win32.ActiveCfg = Release|Win32
31 | {1590D7CD-7D3A-4AB7-A355-EE02F7FB987D}.Release|Win32.Build.0 = Release|Win32
32 | {1590D7CD-7D3A-4AB7-A355-EE02F7FB987D}.Release|x64.ActiveCfg = Release|x64
33 | {1590D7CD-7D3A-4AB7-A355-EE02F7FB987D}.Release|x64.Build.0 = Release|x64
34 | {171CAFC6-E679-4B81-BF5B-049AC0FAB4F8}.Debug|ARM64.ActiveCfg = Debug|ARM64
35 | {171CAFC6-E679-4B81-BF5B-049AC0FAB4F8}.Debug|ARM64.Build.0 = Debug|ARM64
36 | {171CAFC6-E679-4B81-BF5B-049AC0FAB4F8}.Debug|Win32.ActiveCfg = Debug|Win32
37 | {171CAFC6-E679-4B81-BF5B-049AC0FAB4F8}.Debug|Win32.Build.0 = Debug|Win32
38 | {171CAFC6-E679-4B81-BF5B-049AC0FAB4F8}.Debug|x64.ActiveCfg = Debug|x64
39 | {171CAFC6-E679-4B81-BF5B-049AC0FAB4F8}.Debug|x64.Build.0 = Debug|x64
40 | {171CAFC6-E679-4B81-BF5B-049AC0FAB4F8}.Release|ARM64.ActiveCfg = Release|ARM64
41 | {171CAFC6-E679-4B81-BF5B-049AC0FAB4F8}.Release|ARM64.Build.0 = Release|ARM64
42 | {171CAFC6-E679-4B81-BF5B-049AC0FAB4F8}.Release|Win32.ActiveCfg = Release|Win32
43 | {171CAFC6-E679-4B81-BF5B-049AC0FAB4F8}.Release|Win32.Build.0 = Release|Win32
44 | {171CAFC6-E679-4B81-BF5B-049AC0FAB4F8}.Release|x64.ActiveCfg = Release|x64
45 | {171CAFC6-E679-4B81-BF5B-049AC0FAB4F8}.Release|x64.Build.0 = Release|x64
46 | {5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Debug|ARM64.ActiveCfg = Debug|ARM64
47 | {5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Debug|ARM64.Build.0 = Debug|ARM64
48 | {5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Debug|Win32.ActiveCfg = Debug|Win32
49 | {5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Debug|Win32.Build.0 = Debug|Win32
50 | {5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Debug|x64.ActiveCfg = Debug|x64
51 | {5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Debug|x64.Build.0 = Debug|x64
52 | {5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Release|ARM64.ActiveCfg = Release|ARM64
53 | {5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Release|ARM64.Build.0 = Release|ARM64
54 | {5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Release|Win32.ActiveCfg = Release|Win32
55 | {5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Release|Win32.Build.0 = Release|Win32
56 | {5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Release|x64.ActiveCfg = Release|x64
57 | {5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Release|x64.Build.0 = Release|x64
58 | EndGlobalSection
59 | GlobalSection(SolutionProperties) = preSolution
60 | HideSolutionNode = FALSE
61 | EndGlobalSection
62 | GlobalSection(ExtensibilityGlobals) = postSolution
63 | SolutionGuid = {66FFEF3A-7122-49C7-8CE4-4704DFB30594}
64 | EndGlobalSection
65 | EndGlobal
66 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/AboutDlg.cpp:
--------------------------------------------------------------------------------
1 | #include "AboutDlg.h"
2 | #include "resource.h"
3 | #include "Utility.h"
4 | #include "StringHelper.h"
5 | #include "Define.h"
6 | #include
7 | #include
8 |
9 |
10 | AboutDlg::AboutDlg(HINSTANCE hInstance, HWND hParent, int nCmdId)
11 | : m_nCmdId(nCmdId)
12 | , StaticDialog()
13 | {
14 | init(hInstance, hParent);
15 | }
16 |
17 |
18 | bool AboutDlg::ShowDlg(bool bShow)
19 | {
20 | bool bShouldShow = bShow && !isVisible();
21 | if (bShouldShow)
22 | {
23 | if (!isCreated())
24 | create(IDD_ABOUTDLG);
25 |
26 | // Adjust the position of AboutBox
27 | goToCenter();
28 | }
29 | else
30 | {
31 | SendMessage(_hSelf, WM_COMMAND, IDCANCEL, NULL);
32 | }
33 | return bShouldShow;
34 | }
35 |
36 |
37 | INT_PTR AboutDlg::run_dlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
38 | {
39 | AboutDlg* pSelf = nullptr;
40 | switch (uMsg)
41 | {
42 | case WM_INITDIALOG:
43 | {
44 | ::SetWindowLongPtr(_hSelf, DWLP_USER, lParam);
45 |
46 | pSelf = reinterpret_cast(static_cast(::GetWindowLongPtr(_hSelf, DWLP_USER)));
47 | if (pSelf)
48 | {
49 | pSelf->SetVersion(_hSelf);
50 | }
51 | SetFocus(GetDlgItem(_hSelf, IDOK));
52 |
53 | // Set links
54 | std::wstring urlIssue(TEXT("__URL__"));
55 | std::wstring urlRepo = urlIssue;
56 |
57 | urlIssue = StringHelper::ReplaceAll(urlIssue, TEXT("__URL__"), URL_REPORT_ISSUE);
58 | urlRepo = StringHelper::ReplaceAll(urlRepo, TEXT("__URL__"), URL_SOURCE_CODE);
59 |
60 | SetWindowText(::GetDlgItem(_hSelf, IDC_WEB_ISSUE), urlIssue.c_str());
61 | SetWindowText(::GetDlgItem(_hSelf, IDC_WEB_SOURCE), urlRepo.c_str());
62 |
63 | return TRUE;
64 | }
65 |
66 | case WM_NOTIFY:
67 | {
68 | switch (reinterpret_cast(lParam)->code)
69 | {
70 | case NM_CLICK:
71 | case NM_RETURN:
72 | {
73 | auto nmLink = reinterpret_cast(lParam);
74 | LITEM item = nmLink->item;
75 |
76 | ShellExecute(nullptr, L"open", item.szUrl, nullptr, nullptr, SW_SHOW);
77 | return TRUE;
78 | }
79 | }
80 | return FALSE;
81 | }
82 |
83 | case WM_COMMAND:
84 | {
85 | pSelf = reinterpret_cast(static_cast(::GetWindowLongPtr(_hSelf, DWLP_USER)));
86 | switch (LOWORD(wParam))
87 | {
88 | case IDCANCEL: // Close this dialog when clicking to close button
89 | case IDOK:
90 | if (pSelf)
91 | ::SendMessage(pSelf->_hParent, NPPM_SETMENUITEMCHECK, static_cast(pSelf->m_nCmdId), false);
92 | EndDialog(_hSelf, wParam);
93 | _hSelf = nullptr;
94 | return TRUE;
95 | }
96 | }
97 | }
98 | return FALSE;
99 | }
100 |
101 | void AboutDlg::SetVersion(HWND hWnd)
102 | {
103 | std::wstring version;
104 |
105 | // Get module path
106 | wchar_t moduleFileName[MAX_PATH + 1] = {};
107 | ::GetModuleFileName(static_cast(getHinst()), moduleFileName, _MAX_PATH);
108 |
109 | version = CUtility::GetVersion(moduleFileName);
110 | if (!version.empty())
111 | {
112 | std::wstring text(PLUGIN_NAME);
113 | text += TEXT(" (");
114 | text += STR_VERSION;
115 | text += version;
116 | text += TEXT(") ");
117 | ::SetWindowText(::GetDlgItem(hWnd, IDC_GB_TITLE), text.c_str());
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/AboutDlg.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "StaticDialog.h"
3 |
4 | class AboutDlg : public StaticDialog
5 | {
6 | public:
7 | AboutDlg(HINSTANCE hInstance, HWND hParent, int nCmdId);
8 | ~AboutDlg() = default;
9 |
10 | bool ShowDlg(bool bShow);
11 |
12 | protected:
13 | virtual INT_PTR CALLBACK run_dlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam) override;
14 |
15 | void SetVersion(HWND hWnd);
16 |
17 | private:
18 | int m_nCmdId = -1;
19 | };
20 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/Define.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "PluginInterface.h"
3 |
4 | // Define the number of plugin commands here
5 | enum class CallBackID : int
6 | {
7 | SHOW_DOC_PANEL = 0,
8 | FORMAT,
9 | COMPRESS,
10 | SORT_BY_KEY,
11 | SEP_1,
12 | SETTING,
13 | ABOUT
14 | };
15 | constexpr const int nTotalCommandCount = static_cast(CallBackID::ABOUT) + 1;
16 |
17 | // Define plugin name here
18 | const TCHAR PLUGIN_NAME[] = TEXT("JSON Viewer");
19 | const TCHAR PLUGIN_CONFIG[] = TEXT("JSONViewer.ini");
20 |
21 | // Text which can be considered for localization
22 | const TCHAR TITLE_JSON_PANEL[] = TEXT("JSON Viewer");
23 | const TCHAR MENU_SHOW_JSON_PANEL[] = TEXT("Show &JSON Viewer");
24 | const TCHAR MENU_FORMAT_JSON[] = TEXT("&Format JSON");
25 | const TCHAR MENU_COMPRESS_JSON[] = TEXT("&Compress JSON");
26 | const TCHAR MENU_SORT_BY_KEY[] = TEXT("Sort by &key (ascending)");
27 | const TCHAR MENU_SETTING[] = TEXT("&Settings");
28 | const TCHAR MENU_ABOUT[] = TEXT("&About");
29 | const TCHAR MENU_SEPERATOR[] = TEXT("-SEPARATOR-");
30 |
31 | const TCHAR TOOLTIP_REFRESH[] = TEXT("Refresh JSON tree");
32 | const TCHAR TOOLTIP_VALIDATE[] = TEXT("Validate JSON to detect any errors");
33 | const TCHAR TOOLTIP_FORMAT[] = TEXT("Format JSON to beautify it");
34 | const TCHAR TOOLTIP_SEARCH[] = TEXT("Search in JSON");
35 |
36 | const TCHAR URL_SOURCE_CODE[] = TEXT("https://github.com/NPP-JSONViewer/JSON-Viewer");
37 | const TCHAR URL_REPORT_ISSUE[] = TEXT("https://github.com/NPP-JSONViewer/JSON-Viewer/issues/new");
38 |
39 | const TCHAR JSON_ROOT[] = TEXT("JSON");
40 |
41 | const TCHAR JSON_ERROR_TITLE[] = TEXT("JSON Viewer: Error");
42 | const TCHAR JSON_WARNING_TITLE[] = TEXT("JSON Viewer: Warning");
43 | const TCHAR JSON_INFO_TITLE[] = TEXT("JSON Viewer: Information");
44 |
45 | const TCHAR JSON_ERR_PARSE[] = TEXT("Unable to parse JSON. Please ensure a valid JSON string is selected.");
46 | const TCHAR JSON_ERR_VALIDATE[] = TEXT("An error occurred while parsing the JSON. Check the current selection for the potential issue.");
47 | const TCHAR JSON_ERR_VALIDATE_SUCCESS[] = TEXT("The JSON appears valid. No errors were found during validation.");
48 | const TCHAR JSON_ERR_SAVE_SETTING[] = TEXT("Could not save the settings. Please try again.");
49 | const TCHAR JSON_ERR_MULTI_SELECTION[] = TEXT("JSON-Viewer does not currently support multiple selections.");
50 |
51 | const TCHAR STR_VERSION[] = TEXT("Version: ");
52 | const TCHAR STR_COPY[] = TEXT("Copy");
53 | const TCHAR STR_COPYNAME[] = TEXT("Copy name");
54 | const TCHAR STR_COPYVALUE[] = TEXT("Copy value");
55 | const TCHAR STR_COPYPATH[] = TEXT("Copy path");
56 | const TCHAR STR_EXPANDALL[] = TEXT("Expand all");
57 | const TCHAR STR_COLLAPSEALL[] = TEXT("Collapse all");
58 |
59 | const TCHAR STR_INI_FORMATTING_SEC[] = TEXT("Formatting");
60 | const TCHAR STR_INI_FORMATTING_EOL[] = TEXT("EOL");
61 | const TCHAR STR_INI_FORMATTING_LINE[] = TEXT("LINE_FORMATTING");
62 | const TCHAR STR_INI_FORMATTING_INDENT[] = TEXT("INDENTATION");
63 | const TCHAR STR_INI_FORMATTING_INDENTCOUNT[] = TEXT("INDENTATION_COUNT");
64 |
65 | const TCHAR STR_INI_OTHER_SEC[] = TEXT("Others");
66 | const TCHAR STR_INI_OTHER_FOLLOW_TAB[] = TEXT("FOLLOW_TAB");
67 | const TCHAR STR_INI_OTHER_AUTO_FORMAT[] = TEXT("AUTO_FORMAT");
68 | const TCHAR STR_INI_OTHER_USE_HIGHLIGHT[] = TEXT("USE_JSON_HIGHLIGHT");
69 | const TCHAR STR_INI_OTHER_IGNORE_COMMENT[] = TEXT("IGNORE_COMMENT");
70 | const TCHAR STR_INI_OTHER_IGNORE_COMMA[] = TEXT("IGNORE_TRAILLING_COMMA");
71 | const TCHAR STR_INI_OTHER_REPLACE_UNDEFINED[] = TEXT("REPLACE_VALUE_UNDEFINED");
72 |
73 | const TCHAR STR_SRCH_SEARCHING[] = TEXT("Searching for: ");
74 | const TCHAR STR_SRCH_NOTFOUND[] = TEXT("Not found: ");
75 | const TCHAR STR_SRCH_NOMOREFOUND[] = TEXT("No more found: ");
76 |
77 | enum class LineEnding
78 | {
79 | AUTO,
80 | WINDOWS,
81 | UNIX,
82 | MAC
83 | };
84 |
85 | enum class LineFormat
86 | {
87 | DEFAULT,
88 | SINGLELINE
89 | };
90 |
91 | enum class IndentStyle
92 | {
93 | AUTO,
94 | TAB,
95 | SPACE
96 | };
97 |
98 | struct Indent
99 | {
100 | unsigned len = 4;
101 | IndentStyle style = IndentStyle::AUTO;
102 | };
103 |
104 | struct ParseOptions
105 | {
106 | bool bIgnoreComment = true;
107 | bool bIgnoreTrailingComma = true;
108 | bool bReplaceUndefined = false;
109 | };
110 |
111 | struct Setting
112 | {
113 | LineEnding lineEnding = LineEnding::AUTO;
114 | LineFormat lineFormat = LineFormat::DEFAULT;
115 | Indent indent {};
116 | bool bFollowCurrentTab = false;
117 | bool bAutoFormat = false;
118 | bool bUseJsonHighlight = true;
119 | ParseOptions parseOptions {};
120 | };
121 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/JsonHandler.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "JsonHandler.h"
5 |
6 | namespace rj = rapidjson;
7 |
8 |
9 | JsonHandler::JsonHandler(const ParseOptions& options)
10 | : m_parseOptions(options)
11 | {
12 | }
13 |
14 | auto JsonHandler::GetCompressedJson(const std::string& jsonText) -> const Result
15 | {
16 | rj::StringBuffer sb;
17 | rj::Writer, rj::UTF8<>, rj::CrtAllocator, rj::kWriteNanAndInfFlag> handler(sb);
18 |
19 | return ParseJson(jsonText, sb, handler);
20 | }
21 |
22 | auto JsonHandler::FormatJson(const std::string& jsonText, LE le, LF lf, char indentChar, unsigned indentLen) -> const Result
23 | {
24 | rj::StringBuffer sb;
25 | rj::PrettyWriter, rj::UTF8<>, rj::CrtAllocator, rj::kWriteNanAndInfFlag> handler(sb);
26 | handler.SetLineEnding(le);
27 | handler.SetFormatOptions(lf);
28 | handler.SetIndent(indentChar, indentLen);
29 |
30 | return ParseJson(jsonText, sb, handler);
31 | }
32 |
33 | auto JsonHandler::SortJsonByKey(const std::string& jsonText, LE le, LF lf, char indentChar, unsigned indentLen) -> const Result
34 | {
35 | auto res = ValidateJson(jsonText);
36 | if (res.success)
37 | {
38 | // Sort the JSON string
39 | auto sorted = SortJsonText(jsonText);
40 | res = FormatJson(sorted, le, lf, indentChar, indentLen);
41 | }
42 | return res;
43 | }
44 |
45 | auto JsonHandler::ValidateJson(const std::string& jsonText) -> const Result
46 | {
47 | rj::StringBuffer sb;
48 | rj::Writer, rj::UTF8<>, rj::CrtAllocator, rj::kWriteNanAndInfFlag> handler(sb);
49 |
50 | return ParseJson(jsonText, sb, handler);
51 | }
52 |
53 | void JsonHandler::SortJsonObject(rj::Value& jsonObject, rj::Document::AllocatorType& allocator) const
54 | {
55 | if (!jsonObject.IsObject())
56 | {
57 | return;
58 | }
59 |
60 | std::vector keys;
61 |
62 | // Collect keys
63 | for (rj::Value::ConstMemberIterator itr = jsonObject.MemberBegin(); itr != jsonObject.MemberEnd(); ++itr)
64 | {
65 | keys.push_back(itr->name.GetString());
66 | }
67 |
68 | // Sort keys alphabetically
69 | std::sort(keys.begin(), keys.end());
70 |
71 | // Create a new sorted object
72 | rj::Value sortedObject(rj::kObjectType);
73 |
74 | // Add members to the sorted object in sorted order
75 | for (const auto& key : keys)
76 | {
77 | rj::Value name(key.c_str(), allocator); // Create key as a RapidJSON value
78 | rj::Value& value = jsonObject[key.c_str()]; // Get corresponding value
79 | sortedObject.AddMember(name, value, allocator); // Add key-value pair to sorted object
80 | }
81 |
82 | // Replace the original object with the sorted one
83 | jsonObject = std::move(sortedObject);
84 | }
85 |
86 | void JsonHandler::SortJsonRecursively(rj::Value& jsonValue, rj::Document::AllocatorType& allocator) const
87 | {
88 | if (jsonValue.IsObject())
89 | {
90 | SortJsonObject(jsonValue, allocator);
91 |
92 | // Recursively sort any nested objects
93 | for (rj::Value::MemberIterator itr = jsonValue.MemberBegin(); itr != jsonValue.MemberEnd(); ++itr)
94 | {
95 | SortJsonRecursively(itr->value, allocator);
96 | }
97 | }
98 | else if (jsonValue.IsArray())
99 | {
100 | // If it's an array, sort each element (in case of nested objects)
101 | for (rj::SizeType i = 0; i < jsonValue.Size(); i++)
102 | {
103 | SortJsonRecursively(jsonValue[i], allocator);
104 | }
105 | }
106 | }
107 |
108 | auto JsonHandler::SortJsonText(const std::string& jsonString) const -> std::string
109 | {
110 | rj::Document document;
111 |
112 | // TODO: Find some better way
113 | constexpr auto flgBase_comment = flgBaseReader | rj::kParseCommentsFlag;
114 | constexpr auto flgBase_comma = flgBaseReader | rj::kParseTrailingCommasFlag;
115 | constexpr auto flgBase_Both = flgBase_comma | flgBase_comment;
116 |
117 | if (m_parseOptions.bIgnoreComment && m_parseOptions.bIgnoreTrailingComma)
118 | {
119 | if (document.Parse(jsonString.c_str()).HasParseError())
120 | {
121 | return "";
122 | }
123 | }
124 |
125 | else if (!m_parseOptions.bIgnoreComment && m_parseOptions.bIgnoreTrailingComma)
126 | {
127 | if (document.Parse(jsonString.c_str()).HasParseError())
128 | {
129 | return "";
130 | }
131 | }
132 |
133 | else if (m_parseOptions.bIgnoreComment && !m_parseOptions.bIgnoreTrailingComma)
134 | {
135 | if (document.Parse(jsonString.c_str()).HasParseError())
136 | {
137 | return "";
138 | }
139 | }
140 |
141 | else if (!m_parseOptions.bIgnoreComment && !m_parseOptions.bIgnoreTrailingComma)
142 | {
143 | if (document.Parse(jsonString.c_str()).HasParseError())
144 | {
145 | return "";
146 | }
147 | }
148 |
149 | SortJsonRecursively(document, document.GetAllocator());
150 |
151 | rj::StringBuffer buffer;
152 | rj::Writer writer(buffer);
153 | document.Accept(writer);
154 |
155 | return buffer.GetString();
156 | }
157 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/JsonHandler.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #include "Define.h"
13 | #include "TrackingStream.h"
14 |
15 | namespace rj = rapidjson;
16 |
17 | struct Result
18 | {
19 | bool success = false;
20 | int error_pos = -1;
21 | int error_code = -1;
22 | std::string error_str;
23 | std::string response;
24 | };
25 |
26 | using LE = rj::LineEndingOption;
27 | using LF = rj::PrettyFormatOptions;
28 |
29 | constexpr auto flgBaseReader = rj::kParseEscapedApostropheFlag | rj::kParseNanAndInfFlag | rj::kParseNumbersAsStringsFlag;
30 | constexpr auto flgBaseWriter = rj::kParseEscapedApostropheFlag | rj::kParseNanAndInfFlag | rj::kParseFullPrecisionFlag;
31 |
32 | class JsonHandler
33 | {
34 | ParseOptions m_parseOptions {};
35 |
36 | public:
37 | explicit JsonHandler(const ParseOptions& options);
38 | ~JsonHandler() = default;
39 |
40 | auto GetCompressedJson(const std::string& jsonText) -> const Result;
41 | auto FormatJson(const std::string& jsonText, LE le, LF lf, char indentChar, unsigned indentLen) -> const Result;
42 | auto SortJsonByKey(const std::string& jsonText, LE le, LF lf, char indentChar, unsigned indentLen) -> const Result;
43 | auto ValidateJson(const std::string& jsonText) -> const Result;
44 |
45 | template
46 | auto ParseJson(const std::string& jsonText, rj::StringBuffer& sb, Handler& handler, TrackingStreamSharedPtr pTS = nullptr) -> const Result;
47 |
48 | private:
49 | void SortJsonObject(rj::Value& jsonObject, rj::Document::AllocatorType& allocator) const;
50 | void SortJsonRecursively(rj::Value& jsonValue, rj::Document::AllocatorType& allocator) const;
51 | auto SortJsonText(const std::string& jsonString) const -> std::string;
52 | };
53 |
54 | template
55 | inline auto JsonHandler::ParseJson(const std::string& jsonText, rj::StringBuffer& sb, Handler& handler, TrackingStreamSharedPtr pTS) -> const Result
56 | {
57 | Result retVal {};
58 |
59 | bool success = false;
60 | rj::Reader reader;
61 |
62 | std::shared_ptr pSS = nullptr;
63 | if (!pTS)
64 | {
65 | pSS = std::make_shared(jsonText.c_str());
66 | }
67 |
68 | // TODO: Find some better way
69 | constexpr auto flgBase_comment = flgBase | rj::kParseCommentsFlag;
70 | constexpr auto flgBase_comma = flgBase | rj::kParseTrailingCommasFlag;
71 | constexpr auto flgBase_Both = flgBase_comma | flgBase_comment;
72 |
73 | if (m_parseOptions.bIgnoreComment && m_parseOptions.bIgnoreTrailingComma)
74 | {
75 | success = pTS ? reader.Parse(*pTS, handler) && sb.GetString() : reader.Parse(*pSS, handler) && sb.GetString();
76 | }
77 |
78 | else if (!m_parseOptions.bIgnoreComment && m_parseOptions.bIgnoreTrailingComma)
79 | {
80 | success = pTS ? reader.Parse(*pTS, handler) && sb.GetString() : reader.Parse(*pSS, handler) && sb.GetString();
81 | }
82 |
83 | else if (m_parseOptions.bIgnoreComment && !m_parseOptions.bIgnoreTrailingComma)
84 | {
85 | success = pTS ? reader.Parse(*pTS, handler) && sb.GetString() : reader.Parse(*pSS, handler) && sb.GetString();
86 | }
87 |
88 | else if (!m_parseOptions.bIgnoreComment && !m_parseOptions.bIgnoreTrailingComma)
89 | {
90 | success = pTS ? reader.Parse(*pTS, handler) && sb.GetString() : reader.Parse(*pSS, handler) && sb.GetString();
91 | }
92 |
93 | if (success)
94 | {
95 | retVal.success = true;
96 | retVal.response = sb.GetString();
97 | retVal.error_code = retVal.error_pos = -1;
98 | retVal.error_str.clear();
99 | }
100 | else
101 | {
102 | retVal.success = false;
103 | retVal.error_str = rj::GetParseError_En(reader.GetParseErrorCode());
104 | retVal.error_pos = static_cast(reader.GetErrorOffset());
105 | retVal.error_code = reader.GetParseErrorCode();
106 | retVal.response.clear();
107 | }
108 |
109 | return retVal;
110 | }
111 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/JsonNode.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | enum class JsonNodeType : short
5 | {
6 | UNKNOWN,
7 | STRING,
8 | NUMBER,
9 | BOOL,
10 | ARRAY,
11 | OBJECT,
12 | };
13 |
14 | struct Position
15 | {
16 | size_t nLine {};
17 | size_t nColumn {};
18 | size_t nKeyLength {};
19 |
20 | void clear()
21 | {
22 | nLine = nColumn = nKeyLength = 0;
23 | }
24 | };
25 |
26 | struct JsonKey
27 | {
28 | Position pos {};
29 | std::string strKey;
30 |
31 | void clear()
32 | {
33 | pos.clear();
34 | strKey.clear();
35 | }
36 | };
37 |
38 | struct JsonNode
39 | {
40 | JsonKey key;
41 | std::string value;
42 | JsonNodeType type = JsonNodeType::UNKNOWN;
43 | };
44 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/JsonViewDlg.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include "DockingDlgInterface.h"
9 | #include "PluginInterface.h"
10 | #include "resource.h"
11 | #include "TreeViewCtrl.h"
12 | #include "SliderCtrl.h"
13 | #include "ScintillaEditor.h"
14 | #include "JsonHandler.h"
15 | #include "JsonNode.h"
16 | #include "TreeHandler.h"
17 |
18 |
19 | class JsonViewDlg
20 | : public DockingDlgInterface
21 | , public TreeHandler
22 | {
23 | enum class eButton
24 | {
25 | eRefresh,
26 | eValidate,
27 | eFormat,
28 | eSearch
29 | };
30 |
31 | enum class eMethod
32 | {
33 | FormatJson,
34 | GetCompressedJson,
35 | ParseJson,
36 | ValidateJson,
37 | SortJsonByKey
38 | };
39 |
40 | public:
41 | JsonViewDlg(HINSTANCE hInstance, const NppData& nppData, const bool& isReady, int nCmdId, std::shared_ptr& pSetting);
42 | virtual ~JsonViewDlg();
43 |
44 | void ShowDlg(bool bShow);
45 | void FormatJson();
46 | void CompressJson();
47 | void SortJsonByKey();
48 | void HandleTabActivated();
49 | void UpdateTitle();
50 |
51 | HTREEITEM InsertToTree(HTREEITEM parent, const std::string& text) override;
52 | HTREEITEM InsertToTree(HTREEITEM parent, const std::string& text, const Position& pos) override;
53 | void AppendNodeCount(HTREEITEM node, unsigned elementCount, bool bArray) override;
54 |
55 | private:
56 | void DrawJsonTree();
57 | void ReDrawJsonTree(bool bForce = false);
58 | void HighlightAsJson(bool bForcefully = false) const;
59 | auto PopulateTreeUsingSax(HTREEITEM tree_root, const std::string& jsonText) -> std::optional;
60 |
61 | void ValidateJson();
62 |
63 | void UpdateNodePath(HTREEITEM htiNode) const;
64 | void GoToLine(size_t nLineToGo) const;
65 | void GoToPosition(size_t nLineToGo, size_t nPos, size_t nLen) const;
66 |
67 | void SearchInTree();
68 |
69 | auto GetTitleFileName() const -> std::wstring;
70 | void PrepareButtons();
71 | void SetIconAndTooltip(eButton ctrlType, const std::wstring& toolTip);
72 |
73 | void AdjustDocPanelSize(int nWidth, int nHeight);
74 |
75 | // Context menu related functions
76 | void ShowContextMenu(int x, int y);
77 | void ShowContextMenu(HTREEITEM htiNode, LPPOINT lppScreen);
78 | void ContextMenuExpand(bool bExpand);
79 |
80 | auto CopyName() const -> std::wstring;
81 | auto CopyKey() const -> std::wstring;
82 | auto CopyValue() const -> std::wstring;
83 | auto CopyPath() const -> std::wstring;
84 |
85 | int ShowMessage(const std::wstring& title, const std::wstring& msg, int flag, bool bDonotShow = false);
86 | void ReportError(const Result& result);
87 |
88 | void ToggleMenuItemState(bool bVisible);
89 |
90 | void ShowControls(const std::vector& ids, bool show);
91 | void EnableControls(const std::vector& ids, bool enable);
92 |
93 | auto GetZoomLevel() const -> int;
94 | void SetZoomLevel(int pos) const;
95 | void SetTreeViewZoom(double dwZoomFactor) const;
96 | void UpdateUIOnZoom(int zoomPercentage) const;
97 | void HandleZoomOnScroll(WPARAM wParam) const;
98 |
99 | void HandleTreeEvents(LPARAM lParam) const;
100 |
101 | auto GetFormatSetting() const -> std::tuple;
102 |
103 | bool CheckForTokenUndefined(eMethod method, std::string selectedText, Result& res, HTREEITEM tree_root);
104 |
105 | bool IsMultiSelection(const ScintillaData& scintillaData) const;
106 | auto IsSelectionValidJson(const ScintillaData& scintillaData) const -> std::optional;
107 | void ProcessScintillaData(const ScintillaData& scintillaData, std::string& text, ScintillaCode& code) const;
108 |
109 | protected:
110 | virtual INT_PTR CALLBACK run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) override;
111 |
112 | private:
113 | int m_nDlgId = -1;
114 | NppData m_NppData = {};
115 | HICON m_hBtnIcon[4] = {};
116 | const bool& m_IsNppReady;
117 |
118 | // To handle doc panel resizing
119 | LONG m_lfDeltaWidth = 0;
120 | LONG m_lfDeltaHeight = 0;
121 | LONG m_lfInitialClientWidth = 0;
122 | LONG m_lfInitialClientHeight = 0;
123 | RECT m_rcInitialWindowRect = {};
124 |
125 | std::unique_ptr m_pCurrFileName;
126 | std::unique_ptr m_pEditor = nullptr;
127 | std::unique_ptr m_pTreeView = nullptr;
128 | std::unique_ptr m_pTreeViewZoom = nullptr;
129 | std::shared_ptr m_pSetting = nullptr;
130 | };
131 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/NPPJSONViewer.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx
15 |
16 |
17 | {3a31aa3c-9f15-4a33-bf5c-b9153d1e757a}
18 |
19 |
20 | {5b794f9e-baf6-4faf-98a6-741b4918d410}
21 |
22 |
23 |
24 |
25 | Source Files
26 |
27 |
28 | Source Files
29 |
30 |
31 | Source Files
32 |
33 |
34 | Source Files
35 |
36 |
37 | Source Files
38 |
39 |
40 | Source Files
41 |
42 |
43 | Source Files
44 |
45 |
46 | Source Files
47 |
48 |
49 | Source Files
50 |
51 |
52 | Source Files
53 |
54 |
55 | Source Files
56 |
57 |
58 | ThirdParty\npp
59 |
60 |
61 | Header Files
62 |
63 |
64 | Source Files
65 |
66 |
67 |
68 |
69 | Header Files
70 |
71 |
72 | Header Files
73 |
74 |
75 | Header Files
76 |
77 |
78 | Header Files
79 |
80 |
81 | Header Files
82 |
83 |
84 | Header Files
85 |
86 |
87 | Header Files
88 |
89 |
90 | Header Files
91 |
92 |
93 | Header Files
94 |
95 |
96 | Header Files
97 |
98 |
99 | Header Files
100 |
101 |
102 | Header Files
103 |
104 |
105 | Header Files
106 |
107 |
108 | Header Files
109 |
110 |
111 | ThirdParty\npp
112 |
113 |
114 | ThirdParty\npp
115 |
116 |
117 | ThirdParty\npp
118 |
119 |
120 | ThirdParty\npp
121 |
122 |
123 | ThirdParty\npp
124 |
125 |
126 | ThirdParty\npp
127 |
128 |
129 | ThirdParty\npp
130 |
131 |
132 | ThirdParty\npp
133 |
134 |
135 | ThirdParty\npp
136 |
137 |
138 | Header Files
139 |
140 |
141 | Header Files
142 |
143 |
144 |
145 |
146 | Resource Files
147 |
148 |
149 |
150 |
151 | Resource Files
152 |
153 |
154 | Resource Files
155 |
156 |
157 | Resource Files
158 |
159 |
160 | Resource Files
161 |
162 |
163 | Resource Files
164 |
165 |
166 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/NppJsonPlugin.cpp:
--------------------------------------------------------------------------------
1 | #include "NppJsonPlugin.h"
2 | #include "resource.h"
3 | #include "Profile.h"
4 | #include
5 |
6 | NppJsonPlugin* NppJsonPlugin::Callback::m_pNppJsonPlugin = nullptr;
7 |
8 | NppJsonPlugin::NppJsonPlugin()
9 | : m_shortcutCommands(nTotalCommandCount)
10 | {
11 | NppJsonPlugin::Callback::m_pNppJsonPlugin = this;
12 | }
13 |
14 | void NppJsonPlugin::PluginInit(HMODULE hModule)
15 | {
16 | m_hModule = hModule;
17 | }
18 |
19 | void NppJsonPlugin::PluginCleanup() {}
20 |
21 | void NppJsonPlugin::SetInfo(const NppData& nppData)
22 | {
23 | m_NppData = nppData;
24 | InitCommandMenu();
25 | InitToolbarIcon();
26 | InitConfigPath();
27 | }
28 |
29 | const TCHAR* NppJsonPlugin::GetPluginName() const
30 | {
31 | return PLUGIN_NAME;
32 | }
33 |
34 | FuncItem* NppJsonPlugin::GetFuncsArray(int* nbF)
35 | {
36 | *nbF = nTotalCommandCount;
37 | return m_shortcutCommands.GetFuncItem();
38 | }
39 |
40 | void NppJsonPlugin::ProcessNotification(const SCNotification* notifyCode)
41 | {
42 | switch (notifyCode->nmhdr.code)
43 | {
44 | case NPPN_TBMODIFICATION:
45 | {
46 | SetMenuIcon();
47 | break;
48 | }
49 |
50 | case NPPN_SHUTDOWN:
51 | {
52 | PluginCleanup();
53 | break;
54 | }
55 |
56 | case NPPN_BUFFERACTIVATED:
57 | {
58 | if (m_pJsonViewDlg && m_bNppReady && !m_bAboutToClose)
59 | {
60 | m_pJsonViewDlg->HandleTabActivated();
61 | }
62 | break;
63 | }
64 |
65 | case NPPN_BEFORESHUTDOWN:
66 | {
67 | m_bAboutToClose = true;
68 | break;
69 | }
70 |
71 | case NPPN_READY:
72 | {
73 | // This is workaround where dialog does not show tree on launch
74 | if (m_pJsonViewDlg && m_pJsonViewDlg->isVisible() && !m_bAboutToClose)
75 | {
76 | ::SendMessage(m_pJsonViewDlg->getHSelf(), WM_COMMAND, IDC_BTN_REFRESH, 0);
77 | m_pJsonViewDlg->UpdateTitle();
78 | }
79 | m_bNppReady = true;
80 | break;
81 | }
82 |
83 | default:
84 | return;
85 | }
86 | }
87 |
88 | LRESULT NppJsonPlugin::MessageProc(UINT /*msg*/, WPARAM /*wParam*/, LPARAM /*lParam*/)
89 | {
90 | return TRUE;
91 | }
92 |
93 | BOOL NppJsonPlugin::IsUnicode()
94 | {
95 | #ifdef _UNICODE
96 | return TRUE;
97 | #else
98 | return FALSE;
99 | #endif // _UNICODE
100 | }
101 |
102 | void NppJsonPlugin::SetMenuIcon()
103 | {
104 | if (m_hMenuIcon.hToolbarIcon || m_hMenuIcon.hToolbarBmp)
105 | {
106 | toolbarIcons tbIcon {};
107 | tbIcon.hToolbarBmp = m_hMenuIcon.hToolbarBmp;
108 | tbIcon.hToolbarIcon = m_hMenuIcon.hToolbarIcon;
109 | auto nCommandId = m_shortcutCommands.GetCommandID(CallBackID::SHOW_DOC_PANEL);
110 | ::SendMessage(m_NppData._nppHandle, NPPM_ADDTOOLBARICON, reinterpret_cast(nCommandId), reinterpret_cast(&tbIcon));
111 | }
112 | }
113 |
114 | void NppJsonPlugin::InitCommandMenu()
115 | {
116 | m_shortcutCommands.SetShortCut(CallBackID::SHOW_DOC_PANEL, {true, true, true, 'J'});
117 | m_shortcutCommands.SetCommand(CallBackID::SHOW_DOC_PANEL, MENU_SHOW_JSON_PANEL, Callback::ShowJsonDlg, false);
118 |
119 | m_shortcutCommands.SetShortCut(CallBackID::FORMAT, {true, true, true, 'M'});
120 | m_shortcutCommands.SetCommand(CallBackID::FORMAT, MENU_FORMAT_JSON, Callback::FormatJson, false);
121 |
122 | m_shortcutCommands.SetShortCut(CallBackID::COMPRESS, {true, true, true, 'C'});
123 | m_shortcutCommands.SetCommand(CallBackID::COMPRESS, MENU_COMPRESS_JSON, Callback::CompressJson, false);
124 |
125 | m_shortcutCommands.SetShortCut(CallBackID::SORT_BY_KEY, {true, true, true, 'K'});
126 | m_shortcutCommands.SetCommand(CallBackID::SORT_BY_KEY, MENU_SORT_BY_KEY, Callback::SortJsonByKey, false);
127 |
128 | m_shortcutCommands.SetCommand(CallBackID::SEP_1, MENU_SEPERATOR, NULL, true);
129 |
130 | m_shortcutCommands.SetCommand(CallBackID::SETTING, MENU_SETTING, Callback::OpenSettingDlg, false);
131 | m_shortcutCommands.SetCommand(CallBackID::ABOUT, MENU_ABOUT, Callback::ShowAboutDlg, false);
132 | }
133 |
134 | void NppJsonPlugin::InitToolbarIcon()
135 | {
136 | auto dpi = GetDeviceCaps(GetWindowDC(m_NppData._nppHandle), LOGPIXELSX);
137 | int size = 16 * dpi / 96;
138 | m_hMenuIcon.hToolbarIcon = reinterpret_cast(::LoadImage(static_cast(m_hModule), MAKEINTRESOURCE(IDI_ICON_TOOLBAR), IMAGE_ICON, size, size, 0));
139 | ICONINFO iconInfo;
140 | GetIconInfo(m_hMenuIcon.hToolbarIcon, &iconInfo);
141 | m_hMenuIcon.hToolbarBmp = iconInfo.hbmColor;
142 | }
143 |
144 | void NppJsonPlugin::InitConfigPath()
145 | {
146 | // Get config dir path
147 | WCHAR szPath[_MAX_PATH] {};
148 | SendMessage(m_NppData._nppHandle, NPPM_GETPLUGINSCONFIGDIR, MAX_PATH, reinterpret_cast(&szPath));
149 | m_configPath = std::wstring(szPath) + TEXT("\\") + PLUGIN_CONFIG;
150 | }
151 |
152 | void NppJsonPlugin::ToggleMenuItemState(int nCmdId, bool bVisible)
153 | {
154 | ::SendMessage(m_NppData._nppHandle, NPPM_SETMENUITEMCHECK, static_cast(nCmdId), bVisible);
155 | }
156 |
157 | void NppJsonPlugin::ConstructJsonDlg()
158 | {
159 | if (!m_pJsonViewDlg)
160 | {
161 | ConstructSetting();
162 | auto nCmdId = m_shortcutCommands.GetCommandID(CallBackID::SHOW_DOC_PANEL);
163 | m_pJsonViewDlg = std::make_unique(reinterpret_cast(m_hModule), m_NppData, m_bNppReady, nCmdId, m_pSetting);
164 | }
165 | }
166 |
167 | void NppJsonPlugin::ConstructSetting()
168 | {
169 | if (!m_pSetting)
170 | {
171 | m_pSetting = std::make_shared();
172 | ProfileSetting(m_configPath).GetSettings(*m_pSetting);
173 | }
174 | }
175 |
176 | void NppJsonPlugin::ShowJsonDlg()
177 | {
178 | ConstructJsonDlg();
179 |
180 | if (m_pJsonViewDlg) // Hope it is constructed by now.
181 | {
182 | bool bVisible = !m_pJsonViewDlg->isVisible();
183 | m_pJsonViewDlg->ShowDlg(bVisible);
184 | }
185 | }
186 |
187 | void NppJsonPlugin::FormatJson()
188 | {
189 | ConstructJsonDlg();
190 |
191 | if (m_pJsonViewDlg) // Hope it is constructed by now.
192 | {
193 | m_pJsonViewDlg->FormatJson();
194 | }
195 | }
196 |
197 | void NppJsonPlugin::CompressJson()
198 | {
199 | ConstructJsonDlg();
200 |
201 | if (m_pJsonViewDlg) // Hope it is constructed by now.
202 | {
203 | m_pJsonViewDlg->CompressJson();
204 | }
205 | }
206 |
207 | void NppJsonPlugin::SortJsonByKey()
208 | {
209 | ConstructJsonDlg();
210 |
211 | if (m_pJsonViewDlg) // Hope it is constructed by now.
212 | {
213 | m_pJsonViewDlg->SortJsonByKey();
214 | }
215 | }
216 |
217 | void NppJsonPlugin::OpenSettingDlg()
218 | {
219 | ConstructSetting();
220 | auto nCmdId = m_shortcutCommands.GetCommandID(CallBackID::SETTING);
221 |
222 | if (!m_pSettingsDlg)
223 | m_pSettingsDlg = std::make_unique(reinterpret_cast(m_hModule), m_NppData._nppHandle, nCmdId, m_configPath, m_pSetting);
224 | bool isShown = m_pSettingsDlg->ShowDlg(true);
225 |
226 | ToggleMenuItemState(nCmdId, isShown);
227 | }
228 |
229 | void NppJsonPlugin::ShowAboutDlg()
230 | {
231 | auto nCmdId = m_shortcutCommands.GetCommandID(CallBackID::ABOUT);
232 |
233 | if (!m_pAboutDlg)
234 | m_pAboutDlg = std::make_unique(reinterpret_cast(m_hModule), m_NppData._nppHandle, nCmdId);
235 | bool isShown = m_pAboutDlg->ShowDlg(true);
236 |
237 | ToggleMenuItemState(nCmdId, isShown);
238 | }
239 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/NppJsonPlugin.h:
--------------------------------------------------------------------------------
1 | #pragma
2 |
3 | #include
4 | #include
5 | #include "Define.h"
6 | #include "Notepad_plus_msgs.h"
7 | #include "ShortcutCommand.h"
8 | #include "AboutDlg.h"
9 | #include "JsonViewDlg.h"
10 | #include "SettingsDlg.h"
11 |
12 |
13 | class NppJsonPlugin
14 | {
15 | public:
16 | NppJsonPlugin();
17 | ~NppJsonPlugin() = default;
18 |
19 | void PluginInit(HMODULE hModule);
20 | void PluginCleanup();
21 |
22 | // Notepad++ APIs to be implemented
23 | void SetInfo(const NppData& nppData);
24 |
25 | const TCHAR* GetPluginName() const;
26 |
27 | FuncItem* GetFuncsArray(int* nbF);
28 |
29 | void ProcessNotification(const SCNotification* notifyCode);
30 |
31 | LRESULT MessageProc(UINT msg, WPARAM wParam, LPARAM lParam);
32 |
33 | BOOL IsUnicode();
34 |
35 | private:
36 | class Callback
37 | {
38 | friend class NppJsonPlugin;
39 | static NppJsonPlugin* m_pNppJsonPlugin;
40 |
41 | public:
42 | Callback() = default;
43 | ~Callback() = default;
44 |
45 | static void ShowJsonDlg()
46 | {
47 | m_pNppJsonPlugin->ShowJsonDlg();
48 | }
49 | static void FormatJson()
50 | {
51 | m_pNppJsonPlugin->FormatJson();
52 | }
53 | static void CompressJson()
54 | {
55 | m_pNppJsonPlugin->CompressJson();
56 | }
57 | static void SortJsonByKey()
58 | {
59 | m_pNppJsonPlugin->SortJsonByKey();
60 | }
61 | static void OpenSettingDlg()
62 | {
63 | m_pNppJsonPlugin->OpenSettingDlg();
64 | }
65 | static void ShowAboutDlg()
66 | {
67 | m_pNppJsonPlugin->ShowAboutDlg();
68 | }
69 | };
70 |
71 | void SetMenuIcon();
72 | void InitCommandMenu();
73 | void InitToolbarIcon();
74 | void InitConfigPath();
75 |
76 | void ToggleMenuItemState(int nCmdId, bool bVisible);
77 |
78 | void ConstructJsonDlg();
79 | void ConstructSetting();
80 |
81 | void ShowJsonDlg();
82 | void FormatJson();
83 | void CompressJson();
84 | void SortJsonByKey();
85 | void OpenSettingDlg();
86 | void ShowAboutDlg();
87 |
88 | private:
89 | HMODULE m_hModule = nullptr;
90 | toolbarIcons m_hMenuIcon = {};
91 | ShortcutCommand m_shortcutCommands;
92 | NppData m_NppData = {};
93 | std::wstring m_configPath;
94 | bool m_bAboutToClose = false;
95 | bool m_bNppReady = false;
96 | std::unique_ptr m_pAboutDlg = nullptr;
97 | std::unique_ptr m_pJsonViewDlg = nullptr;
98 | std::unique_ptr m_pSettingsDlg = nullptr;
99 | std::shared_ptr m_pSetting = nullptr;
100 | };
101 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/Profile.cpp:
--------------------------------------------------------------------------------
1 | #include "Profile.h"
2 | #include "Utility.h"
3 | #include "Define.h"
4 | #include "StringHelper.h"
5 | #include
6 | #include
7 |
8 | Profile::Profile(const std::wstring& path)
9 | : m_ProfileFilePath(path)
10 | {
11 | if (path.empty())
12 | Init();
13 | }
14 |
15 | bool Profile::ReadValue(const std::wstring& section, const std::wstring& key, int& retVal, int defaultVal) const
16 | {
17 | retVal = GetPrivateProfileInt(section.c_str(), key.c_str(), defaultVal, m_ProfileFilePath.c_str());
18 |
19 | return true;
20 | }
21 |
22 | bool Profile::ReadValue(const std::wstring& section, const std::wstring& key, std::wstring& retVal, const std::wstring& defaultVal) const
23 | {
24 | bool bRetVal = false;
25 |
26 | // Try with MAX_PATH
27 | constexpr DWORD nBufSize = MAX_PATH * 2;
28 | auto pData = std::make_unique(nBufSize);
29 | GetPrivateProfileString(section.c_str(), key.c_str(), defaultVal.c_str(), pData.get(), nBufSize, m_ProfileFilePath.c_str());
30 |
31 | if (pData)
32 | {
33 | bRetVal = true;
34 | retVal = pData.get();
35 | }
36 |
37 | return bRetVal;
38 | }
39 |
40 | bool Profile::WriteValue(const std::wstring& section, const std::wstring& key, int value) const
41 | {
42 | return WriteValue(section, key, std::to_wstring(value));
43 | }
44 |
45 | bool Profile::WriteValue(const std::wstring& section, const std::wstring& key, const std::wstring& value) const
46 | {
47 | return WritePrivateProfileString(section.c_str(), key.c_str(), value.c_str(), m_ProfileFilePath.c_str()) ? true : false;
48 | }
49 |
50 | void Profile::Init()
51 | {
52 | auto appDataPath = CUtility::GetSpecialFolderLocation(CSIDL_APPDATA);
53 | if (appDataPath.empty())
54 | {
55 | ::MessageBox(NULL, L"Failed to get %appdata% path. Please contact developer. Inconvenience regretted.", JSON_ERROR_TITLE, MB_OK | MB_ICONERROR);
56 | return;
57 | }
58 |
59 | appDataPath += L"\\config";
60 | if (!CUtility::DirExist(appDataPath) && !CUtility::CreateDir(appDataPath))
61 | {
62 | std::wstring msg = L"Failed to get below directory. Please contact developer. Inconvenience regretted.";
63 | msg += L"\n\n" + appDataPath;
64 |
65 | ::MessageBox(NULL, msg.c_str(), JSON_ERROR_TITLE, MB_OK | MB_ICONERROR);
66 | return;
67 | }
68 |
69 | m_ProfileFilePath = appDataPath + L"\\" + PLUGIN_CONFIG;
70 | }
71 |
72 | bool ProfileSetting::GetSettings(Setting& info) const
73 | {
74 | bool bRetVal = true;
75 |
76 | int nVal = 0;
77 | bRetVal = bRetVal && ReadValue(STR_INI_FORMATTING_SEC, STR_INI_FORMATTING_EOL, nVal, static_cast(info.lineEnding));
78 | if (bRetVal)
79 | info.lineEnding = static_cast(nVal);
80 |
81 | bRetVal = bRetVal && ReadValue(STR_INI_FORMATTING_SEC, STR_INI_FORMATTING_LINE, nVal, static_cast(info.lineFormat));
82 | if (bRetVal)
83 | info.lineFormat = static_cast(nVal);
84 |
85 | bRetVal = bRetVal && ReadValue(STR_INI_FORMATTING_SEC, STR_INI_FORMATTING_INDENT, nVal, static_cast(info.indent.style));
86 | if (bRetVal)
87 | info.indent.style = static_cast(nVal);
88 |
89 | bRetVal = bRetVal && ReadValue(STR_INI_FORMATTING_SEC, STR_INI_FORMATTING_INDENTCOUNT, nVal, info.indent.len);
90 | if (bRetVal)
91 | info.indent.len = nVal;
92 |
93 | bRetVal = bRetVal && ReadValue(STR_INI_OTHER_SEC, STR_INI_OTHER_FOLLOW_TAB, nVal, info.bFollowCurrentTab);
94 | if (bRetVal)
95 | info.bFollowCurrentTab = static_cast(nVal);
96 |
97 | bRetVal = bRetVal && ReadValue(STR_INI_OTHER_SEC, STR_INI_OTHER_AUTO_FORMAT, nVal, info.bAutoFormat);
98 | if (bRetVal)
99 | info.bAutoFormat = static_cast(nVal);
100 |
101 | bRetVal = bRetVal && ReadValue(STR_INI_OTHER_SEC, STR_INI_OTHER_USE_HIGHLIGHT, nVal, info.bUseJsonHighlight);
102 | if (bRetVal)
103 | info.bUseJsonHighlight = static_cast(nVal);
104 |
105 | bRetVal = bRetVal && ReadValue(STR_INI_OTHER_SEC, STR_INI_OTHER_IGNORE_COMMENT, nVal, info.parseOptions.bIgnoreComment);
106 | if (bRetVal)
107 | info.parseOptions.bIgnoreComment = static_cast(nVal);
108 |
109 | bRetVal = bRetVal && ReadValue(STR_INI_OTHER_SEC, STR_INI_OTHER_IGNORE_COMMA, nVal, info.parseOptions.bIgnoreTrailingComma);
110 | if (bRetVal)
111 | info.parseOptions.bIgnoreTrailingComma = static_cast(nVal);
112 |
113 | bRetVal = bRetVal && ReadValue(STR_INI_OTHER_SEC, STR_INI_OTHER_REPLACE_UNDEFINED, nVal, info.parseOptions.bReplaceUndefined);
114 | if (bRetVal)
115 | info.parseOptions.bReplaceUndefined = static_cast(nVal);
116 |
117 | return bRetVal;
118 | }
119 |
120 | bool ProfileSetting::SetSettings(const Setting& info) const
121 | {
122 | bool bRetVal = true;
123 |
124 | bRetVal = bRetVal && WriteValue(STR_INI_FORMATTING_SEC, STR_INI_FORMATTING_EOL, static_cast(info.lineEnding));
125 | bRetVal = bRetVal && WriteValue(STR_INI_FORMATTING_SEC, STR_INI_FORMATTING_LINE, static_cast(info.lineFormat));
126 | bRetVal = bRetVal && WriteValue(STR_INI_FORMATTING_SEC, STR_INI_FORMATTING_INDENT, static_cast(info.indent.style));
127 | bRetVal = bRetVal && WriteValue(STR_INI_FORMATTING_SEC, STR_INI_FORMATTING_INDENTCOUNT, info.indent.len);
128 |
129 | bRetVal = bRetVal && WriteValue(STR_INI_OTHER_SEC, STR_INI_OTHER_FOLLOW_TAB, info.bFollowCurrentTab);
130 | bRetVal = bRetVal && WriteValue(STR_INI_OTHER_SEC, STR_INI_OTHER_AUTO_FORMAT, info.bAutoFormat);
131 | bRetVal = bRetVal && WriteValue(STR_INI_OTHER_SEC, STR_INI_OTHER_USE_HIGHLIGHT, info.bUseJsonHighlight);
132 | bRetVal = bRetVal && WriteValue(STR_INI_OTHER_SEC, STR_INI_OTHER_IGNORE_COMMENT, info.parseOptions.bIgnoreComment);
133 | bRetVal = bRetVal && WriteValue(STR_INI_OTHER_SEC, STR_INI_OTHER_IGNORE_COMMA, info.parseOptions.bIgnoreTrailingComma);
134 | bRetVal = bRetVal && WriteValue(STR_INI_OTHER_SEC, STR_INI_OTHER_REPLACE_UNDEFINED, info.parseOptions.bReplaceUndefined);
135 |
136 | return bRetVal;
137 | }
138 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/Profile.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include "Define.h"
4 |
5 | class Profile
6 | {
7 | protected:
8 | std::wstring m_ProfileFilePath;
9 |
10 | public:
11 | explicit Profile(const std::wstring& path);
12 | virtual ~Profile() = default;
13 |
14 | protected:
15 | bool ReadValue(const std::wstring& section, const std::wstring& key, int& retVal, int defaultVal = 0) const;
16 | bool ReadValue(const std::wstring& section, const std::wstring& key, std::wstring& retVal, const std::wstring& defaultVal = {}) const;
17 |
18 | bool WriteValue(const std::wstring& section, const std::wstring& key, int value) const;
19 | bool WriteValue(const std::wstring& section, const std::wstring& key, const std::wstring& value) const;
20 |
21 | private:
22 | void Init();
23 | };
24 |
25 |
26 | class ProfileSetting : public Profile
27 | {
28 | public:
29 | explicit ProfileSetting(const std::wstring& path)
30 | : Profile(path)
31 | {
32 | }
33 | ~ProfileSetting() = default;
34 |
35 | bool GetSettings(Setting& info) const;
36 | bool SetSettings(const Setting& info) const;
37 | };
38 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/RapidJsonHandler.cpp:
--------------------------------------------------------------------------------
1 | #include "RapidJsonHandler.h"
2 | #include "TreeHandler.h"
3 |
4 | const char* const STR_NULL = "null";
5 | const char* const STR_TRUE = "true";
6 | const char* const STR_FALSE = "false";
7 |
8 |
9 | bool RapidJsonHandler::Null()
10 | {
11 | if (!m_NodeStack.size())
12 | return false;
13 |
14 | TreeNode* parent = m_NodeStack.top();
15 | InsertToTree(parent, STR_NULL, false);
16 | return true;
17 | }
18 |
19 | bool RapidJsonHandler::Bool(bool b)
20 | {
21 | if (!m_NodeStack.size())
22 | return false;
23 |
24 | TreeNode* parent = m_NodeStack.top();
25 | InsertToTree(parent, b ? STR_TRUE : STR_FALSE, false);
26 | return true;
27 | }
28 |
29 | bool RapidJsonHandler::Int(int /*i*/)
30 | {
31 | return true;
32 | }
33 |
34 | bool RapidJsonHandler::Uint(unsigned /*i*/)
35 | {
36 | return true;
37 | }
38 |
39 | bool RapidJsonHandler::Int64(int64_t /*i*/)
40 | {
41 | return true;
42 | }
43 |
44 | bool RapidJsonHandler::Uint64(uint64_t /*i*/)
45 | {
46 | return true;
47 | }
48 |
49 | bool RapidJsonHandler::Double(double /*d*/)
50 | {
51 | return true;
52 | }
53 |
54 | bool RapidJsonHandler::RawNumber(const Ch* str, unsigned /*length*/, bool /*copy*/)
55 | {
56 | if (!m_NodeStack.size())
57 | return false;
58 |
59 | TreeNode* parent = m_NodeStack.top();
60 | InsertToTree(parent, str, false);
61 | return true;
62 | }
63 |
64 | bool RapidJsonHandler::String(const Ch* str, unsigned /*length*/, bool /*copy*/)
65 | {
66 | if (!str)
67 | return false;
68 |
69 | // handle case, when there is only a value in input
70 | if (m_NodeStack.empty())
71 | {
72 | m_pTreeHandler->InsertToTree(m_treeRoot, str);
73 | return true;
74 | }
75 |
76 | TreeNode* parent = m_NodeStack.top();
77 | InsertToTree(parent, str, true);
78 |
79 | return true;
80 | }
81 |
82 | bool RapidJsonHandler::Key(const Ch* str, unsigned length, bool /*copy*/)
83 | {
84 | m_jsonLastKey.strKey = str;
85 | m_jsonLastKey.pos.nLine = m_pTS->getLine();
86 | m_jsonLastKey.pos.nColumn = m_pTS->getColumn() - length - 1;
87 | m_jsonLastKey.pos.nKeyLength = length;
88 | return true;
89 | }
90 |
91 | bool RapidJsonHandler::StartObject()
92 | {
93 | TreeNode* parent = nullptr;
94 | if (m_NodeStack.empty())
95 | {
96 | parent = new TreeNode;
97 | parent->node.type = JsonNodeType::OBJECT;
98 | parent->subRoot = m_treeRoot;
99 | parent->counter = 0;
100 | m_NodeStack.push(parent);
101 | }
102 | else
103 | {
104 | parent = m_NodeStack.top();
105 | }
106 |
107 | if (!m_jsonLastKey.strKey.empty() || parent->node.type == JsonNodeType::ARRAY)
108 | {
109 | HTREEITEM newNode = nullptr;
110 | if (parent->node.type != JsonNodeType::ARRAY)
111 | {
112 | newNode = m_pTreeHandler->InsertToTree(parent->subRoot, m_jsonLastKey.strKey, m_jsonLastKey.pos);
113 | m_jsonLastKey.clear();
114 | }
115 | else
116 | {
117 | // It is an array
118 | std::string arr = "[" + std::to_string(parent->counter) + "]";
119 | newNode = m_pTreeHandler->InsertToTree(parent->subRoot, arr);
120 | }
121 |
122 | parent->counter++;
123 | TreeNode* newTreeNode = new TreeNode;
124 | newTreeNode->node.type = JsonNodeType::OBJECT;
125 | newTreeNode->subRoot = newNode;
126 | newTreeNode->counter = 0;
127 | m_NodeStack.push(newTreeNode);
128 | }
129 |
130 | return true;
131 | }
132 |
133 | bool RapidJsonHandler::EndObject(unsigned memberCount)
134 | {
135 | AppendNodeCount(memberCount, false);
136 | return true;
137 | }
138 |
139 | bool RapidJsonHandler::StartArray()
140 | {
141 | TreeNode* parent = nullptr;
142 | if (m_NodeStack.empty())
143 | {
144 | parent = new TreeNode;
145 | parent->node.type = JsonNodeType::ARRAY;
146 | parent->subRoot = m_treeRoot;
147 | parent->counter = 0;
148 | m_NodeStack.push(parent);
149 | return true;
150 | }
151 | else
152 | {
153 | parent = m_NodeStack.top();
154 | }
155 |
156 | if (!m_jsonLastKey.strKey.empty() || parent->node.type == JsonNodeType::ARRAY)
157 | {
158 | HTREEITEM newNode;
159 | if (parent->node.type != JsonNodeType::ARRAY)
160 | {
161 | newNode = m_pTreeHandler->InsertToTree(parent->subRoot, m_jsonLastKey.strKey, m_jsonLastKey.pos);
162 | m_jsonLastKey.clear();
163 | }
164 | else
165 | {
166 | // It is an array
167 | std::string arr = "[" + std::to_string(parent->counter) + "]";
168 | newNode = m_pTreeHandler->InsertToTree(parent->subRoot, arr);
169 | }
170 |
171 | parent->counter++;
172 | TreeNode* newTreeNode = new TreeNode;
173 | newTreeNode->node.type = JsonNodeType::ARRAY;
174 | newTreeNode->subRoot = newNode;
175 | newTreeNode->counter = 0;
176 | m_NodeStack.push(newTreeNode);
177 | }
178 | return true;
179 | }
180 |
181 | bool RapidJsonHandler::EndArray(unsigned elementCount)
182 | {
183 | AppendNodeCount(elementCount, true);
184 | return true;
185 | }
186 |
187 | void RapidJsonHandler::InsertToTree(TreeNode* node, const char* const str, bool bQuote)
188 | {
189 | if (!node || !str)
190 | return;
191 |
192 | if (node->node.type != JsonNodeType::ARRAY)
193 | {
194 | node->node.key = m_jsonLastKey;
195 | node->node.value = str;
196 | m_jsonLastKey.clear();
197 | }
198 | else
199 | {
200 | node->node.key.strKey = "[" + std::to_string(node->counter) + "]";
201 | node->node.value = str;
202 |
203 | size_t valueLen = node->node.value.size();
204 | node->node.key.pos.nLine = m_pTS->getLine();
205 | node->node.key.pos.nColumn = m_pTS->getColumn() - valueLen - (bQuote ? 1 : 0); // -1 to deal with double quote in string
206 | node->node.key.pos.nKeyLength = valueLen;
207 |
208 | node->counter++;
209 | }
210 |
211 | // Insert item to tree
212 | if (bQuote)
213 | m_pTreeHandler->InsertToTree(node->subRoot, node->node.key.strKey + " : \"" + node->node.value + "\"", node->node.key.pos);
214 | else
215 | m_pTreeHandler->InsertToTree(node->subRoot, node->node.key.strKey + " : " + node->node.value, node->node.key.pos);
216 | }
217 |
218 | void RapidJsonHandler::AppendNodeCount(unsigned elementCount, bool bArray)
219 | {
220 | if (!m_NodeStack.empty())
221 | {
222 | TreeNode* node = m_NodeStack.top();
223 | m_NodeStack.pop();
224 |
225 | if (node->subRoot && node->subRoot != m_treeRoot)
226 | m_pTreeHandler->AppendNodeCount(node->subRoot, elementCount, bArray);
227 |
228 | delete node;
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/RapidJsonHandler.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 |
10 | #include "JsonNode.h"
11 | #include "TrackingStream.h"
12 |
13 | class TreeHandler;
14 |
15 | struct TreeNode
16 | {
17 | HTREEITEM subRoot {};
18 | JsonNode node {};
19 | int counter {};
20 | };
21 |
22 |
23 | class RapidJsonHandler : public rapidjson::BaseReaderHandler, RapidJsonHandler>
24 | {
25 | JsonKey m_jsonLastKey {};
26 | std::stack m_NodeStack;
27 |
28 | TrackingStreamSharedPtr m_pTS;
29 | TreeHandler* m_pTreeHandler = nullptr;
30 | HTREEITEM m_treeRoot = nullptr;
31 |
32 | public:
33 | RapidJsonHandler(TreeHandler* handler, HTREEITEM treeRoot, TrackingStreamSharedPtr pTS = nullptr)
34 | : m_pTS(pTS ? pTS->GetShared() : nullptr)
35 | , m_pTreeHandler(handler)
36 | , m_treeRoot(treeRoot)
37 | {
38 | }
39 | virtual ~RapidJsonHandler() = default;
40 |
41 | bool Null();
42 | bool Bool(bool b);
43 | bool Int(int i);
44 | bool Uint(unsigned i);
45 | bool Int64(int64_t i);
46 | bool Uint64(uint64_t i);
47 | bool Double(double d);
48 | bool RawNumber(const Ch* str, unsigned length, bool copy);
49 | bool String(const Ch* str, unsigned length, bool copy);
50 | bool Key(const Ch* str, unsigned length, bool copy);
51 | bool StartObject();
52 | bool EndObject(unsigned memberCount);
53 | bool StartArray();
54 | bool EndArray(unsigned elementCount);
55 |
56 | private:
57 | void InsertToTree(TreeNode* node, const char* const str, bool bQuote);
58 | void AppendNodeCount(unsigned elementCount, bool bArray);
59 | };
60 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/ScintillaEditor.cpp:
--------------------------------------------------------------------------------
1 | #include "ScintillaEditor.h"
2 | #include
3 | #include
4 |
5 | ScintillaEditor::ScintillaEditor(const NppData& nppData)
6 | : m_NppData(nppData)
7 | {
8 | RefreshViewHandle();
9 | }
10 |
11 | void ScintillaEditor::RefreshViewHandle()
12 | {
13 | int which = -1;
14 | ::SendMessage(m_NppData._nppHandle, NPPM_GETCURRENTSCINTILLA, 0, reinterpret_cast(&which));
15 | assert(which != -1);
16 | if (which != -1)
17 | m_hScintilla = (which == 0) ? m_NppData._scintillaMainHandle : m_NppData._scintillaSecondHandle;
18 | }
19 |
20 | auto ScintillaEditor::GetJsonText() -> ScintillaData
21 | {
22 | if (!m_hScintilla)
23 | return ScintillaCode::NotInitialized;
24 |
25 | // Multi selection is not supported
26 | size_t nSelections = ::SendMessage(m_hScintilla, SCI_GETSELECTIONS, 0, 0);
27 | if (nSelections > 1)
28 | return ScintillaCode::MultiLineSelection;
29 |
30 | // Adjust the selection position
31 | RefreshSelectionPos();
32 |
33 | // Get only selected text if any else select all text
34 | size_t asciiTextLen = m_nEndPos - m_nStartPos;
35 | if (asciiTextLen == 0)
36 | {
37 | asciiTextLen = ::SendMessage(m_hScintilla, SCI_GETLENGTH, 0, 0);
38 | ::SendMessage(m_hScintilla, SCI_SETSELECTIONSTART, 0, 0);
39 | ::SendMessage(m_hScintilla, SCI_SETSELECTIONEND, asciiTextLen, 0);
40 | }
41 | std::unique_ptr chSelectedText = std::make_unique(asciiTextLen + 1);
42 | ::SendMessage(m_hScintilla, SCI_GETSELTEXT, 0, reinterpret_cast(chSelectedText.get()));
43 |
44 | // Update selection position
45 | RefreshSelectionPos();
46 |
47 | return chSelectedText.get();
48 | }
49 |
50 | void ScintillaEditor::SetLangAsJson() const
51 | {
52 | ::SendMessage(m_NppData._nppHandle, NPPM_SETCURRENTLANGTYPE, 0, LangType::L_JSON);
53 | }
54 |
55 | bool ScintillaEditor::IsJsonFile() const
56 | {
57 | unsigned languageType = 0;
58 | ::SendMessage(m_NppData._nppHandle, NPPM_GETCURRENTLANGTYPE, 0, reinterpret_cast(&languageType));
59 | return languageType == LangType::L_JSON;
60 | }
61 |
62 | auto ScintillaEditor::GetCurrentFileName() const -> std::wstring
63 | {
64 | wchar_t fileName[MAX_PATH] {};
65 | ::SendMessage(m_NppData._nppHandle, NPPM_GETFILENAME, 0, reinterpret_cast(&fileName));
66 | return fileName;
67 | }
68 |
69 | void ScintillaEditor::ReplaceSelection(const std::string& text) const
70 | {
71 | ::SendMessage(m_hScintilla, SCI_REPLACESEL, 0, reinterpret_cast(text.c_str()));
72 |
73 | // Restore the selection
74 | MakeSelection(m_nStartPos, m_nStartPos + text.length());
75 | }
76 |
77 | void ScintillaEditor::MakeSelection(size_t start, size_t end) const
78 | {
79 | ::SendMessage(m_hScintilla, SCI_SETSEL, start, end);
80 | }
81 |
82 | auto ScintillaEditor::GetEOL() const -> unsigned
83 | {
84 | LRESULT eolMode = ::SendMessage(m_hScintilla, SCI_GETEOLMODE, 0, 0);
85 | return static_cast(eolMode);
86 | }
87 |
88 | auto ScintillaEditor::GetIndent() const -> std::tuple
89 | {
90 | bool useTabs = ::SendMessage(m_hScintilla, SCI_GETUSETABS, 0, 0);
91 | char indentChar = useTabs ? '\t' : ' ';
92 | unsigned indentLen = useTabs ? 1 : static_cast(::SendMessage(m_hScintilla, SCI_GETTABWIDTH, 0, 0));
93 | return std::tuple(indentChar, indentLen);
94 | }
95 |
96 | void ScintillaEditor::RefreshSelectionPos()
97 | {
98 | m_nStartPos = ::SendMessage(m_hScintilla, SCI_GETSELECTIONSTART, 0, 0);
99 | m_nEndPos = ::SendMessage(m_hScintilla, SCI_GETSELECTIONEND, 0, 0);
100 |
101 | if (m_nEndPos < m_nStartPos)
102 | std::swap(m_nStartPos, m_nEndPos);
103 |
104 | m_nStartLine = ::SendMessage(m_hScintilla, SCI_LINEFROMPOSITION, m_nStartPos, 0);
105 | }
106 |
107 | void ScintillaEditor::GoToLine(size_t nLineToGo) const
108 | {
109 | ::SendMessage(m_hScintilla, SCI_GOTOLINE, m_nStartLine + nLineToGo, 0);
110 | }
111 |
112 | void ScintillaEditor::GoToPosition(size_t nLineToGo, size_t nColumnIndex, size_t nWordLen, bool selectWord /*= true*/) const
113 | {
114 | size_t lineStartPos = SendMessage(m_hScintilla, SCI_POSITIONFROMLINE, m_nStartLine + nLineToGo, 0);
115 | size_t targetPos = lineStartPos + nColumnIndex;
116 | ::SendMessage(m_hScintilla, SCI_GOTOPOS, targetPos, 0);
117 | if (selectWord)
118 | {
119 | MakeSelection(targetPos, targetPos + nWordLen);
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/ScintillaEditor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "Define.h"
3 | #include
4 | #include
5 | #include
6 |
7 | enum class ScintillaCode : short
8 | {
9 | Unknown,
10 | Success,
11 | NotInitialized,
12 | NoSelection,
13 | MultiLineSelection
14 | };
15 |
16 | using ScintillaData = std::variant;
17 |
18 | class ScintillaEditor
19 | {
20 | public:
21 | explicit ScintillaEditor(const NppData& nppData);
22 | ~ScintillaEditor() = default;
23 |
24 | void RefreshViewHandle();
25 | auto GetJsonText() -> ScintillaData;
26 | void SetLangAsJson() const;
27 | bool IsJsonFile() const;
28 | auto GetCurrentFileName() const -> std::wstring;
29 |
30 | void ReplaceSelection(const std::string& text) const;
31 |
32 | void MakeSelection(size_t start, size_t end) const;
33 | inline auto GetSelectionStart() const -> size_t
34 | {
35 | return m_nStartPos;
36 | }
37 | inline auto GetSelectionEnd() const -> size_t
38 | {
39 | return m_nEndPos;
40 | }
41 | inline auto GetSelectionStartLine() const -> size_t
42 | {
43 | return m_nStartLine;
44 | }
45 |
46 | auto GetEOL() const -> unsigned;
47 | auto GetIndent() const -> std::tuple;
48 |
49 | void RefreshSelectionPos();
50 |
51 | void GoToLine(size_t nLineToGo) const;
52 | void GoToPosition(size_t nLineToGo, size_t nColumnIndex, size_t nWordLen, bool selectWord = true) const;
53 |
54 | private:
55 | NppData m_NppData = {};
56 | HWND m_hScintilla = nullptr;
57 |
58 | size_t m_nStartLine = 0;
59 | size_t m_nStartPos = 0;
60 | size_t m_nEndPos = 0;
61 | };
62 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/SettingsDlg.cpp:
--------------------------------------------------------------------------------
1 | #include "SettingsDlg.h"
2 | #include "resource.h"
3 | #include "Utility.h"
4 | #include "Profile.h"
5 | #include
6 | #include
7 |
8 |
9 | SettingsDlg::SettingsDlg(HINSTANCE hInstance, HWND hParent, int nCmdId, const std::wstring& configPath, std::shared_ptr& pSetting)
10 | : m_nCmdId(nCmdId)
11 | , m_configPath(configPath)
12 | , StaticDialog()
13 | , m_pSetting(pSetting)
14 | {
15 | init(hInstance, hParent);
16 | }
17 |
18 |
19 | bool SettingsDlg::ShowDlg(bool bShow)
20 | {
21 | bool bShouldShow = bShow && !isVisible();
22 | if (bShouldShow)
23 | {
24 | if (!isCreated())
25 | create(IDD_SETTING);
26 |
27 | // Adjust the position of Setting dialog
28 | goToCenter();
29 | }
30 | else
31 | {
32 | SendMessage(_hSelf, WM_COMMAND, IDCANCEL, NULL);
33 | }
34 | return bShouldShow;
35 | }
36 |
37 | INT_PTR SettingsDlg::run_dlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
38 | {
39 | switch (uMsg)
40 | {
41 | case WM_INITDIALOG:
42 | {
43 | ::SetWindowLongPtr(_hSelf, DWLP_USER, lParam);
44 |
45 | auto enable_dlg_theme = reinterpret_cast(::SendMessage(_hParent, NPPM_GETENABLETHEMETEXTUREFUNC, 0, 0));
46 | if (enable_dlg_theme != nullptr)
47 | enable_dlg_theme(_hSelf, ETDT_ENABLETAB);
48 |
49 | InitDlg();
50 |
51 | SetFocus(GetDlgItem(_hSelf, IDOK));
52 |
53 | return TRUE;
54 | }
55 |
56 | case WM_COMMAND:
57 | {
58 | switch (LOWORD(wParam))
59 | {
60 | case IDOK:
61 | if (Apply())
62 | {
63 | ::SendMessage(_hParent, NPPM_SETMENUITEMCHECK, static_cast(m_nCmdId), false);
64 | EndDialog(_hSelf, wParam);
65 | }
66 | else
67 | {
68 | ::MessageBox(_hSelf, JSON_ERR_SAVE_SETTING, JSON_ERROR_TITLE, MB_OK | MB_ICONERROR);
69 | }
70 | return TRUE;
71 |
72 | case IDCANCEL: // Close this dialog when clicking to close button
73 | ::SendMessage(_hParent, NPPM_SETMENUITEMCHECK, static_cast(m_nCmdId), false);
74 | EndDialog(_hSelf, wParam);
75 | return TRUE;
76 |
77 | case IDC_RADIO_INDENT_AUTO:
78 | case IDC_RADIO_INDENT_TAB:
79 | ShowSpaceCountCtrls(false);
80 | return TRUE;
81 |
82 | case IDC_RADIO_INDENT_SPACE:
83 | ShowSpaceCountCtrls(true);
84 | return TRUE;
85 | }
86 | }
87 | }
88 | return FALSE;
89 | }
90 |
91 | bool SettingsDlg::Apply()
92 | {
93 | // Get all the data from the UI
94 |
95 | // Line Ending setting
96 | if (IsDlgButtonChecked(_hSelf, IDC_RADIO_LINE_AUTO))
97 | m_pSetting->lineEnding = LineEnding::AUTO;
98 | else if (IsDlgButtonChecked(_hSelf, IDC_RADIO_LINE_WINDOW))
99 | m_pSetting->lineEnding = LineEnding::WINDOWS;
100 | else if (IsDlgButtonChecked(_hSelf, IDC_RADIO_LINE_UNIX))
101 | m_pSetting->lineEnding = LineEnding::UNIX;
102 | else if (IsDlgButtonChecked(_hSelf, IDC_RADIO_LINE_MAC))
103 | m_pSetting->lineEnding = LineEnding::MAC;
104 |
105 | // Indentation setting
106 | if (IsDlgButtonChecked(_hSelf, IDC_RADIO_INDENT_AUTO))
107 | m_pSetting->indent.style = IndentStyle::AUTO;
108 | else if (IsDlgButtonChecked(_hSelf, IDC_RADIO_INDENT_TAB))
109 | m_pSetting->indent.style = IndentStyle::TAB;
110 | else if (IsDlgButtonChecked(_hSelf, IDC_RADIO_INDENT_SPACE))
111 | m_pSetting->indent.style = IndentStyle::SPACE;
112 |
113 | auto indent_len = CUtility::GetNumber(CUtility::GetEditCtrlText(::GetDlgItem(_hSelf, IDC_EDT_INDENT_SPACECOUNT)));
114 | if (indent_len.has_value())
115 | {
116 | m_pSetting->indent.len = indent_len.value();
117 | }
118 |
119 | // Line Ending setting
120 | if (IsDlgButtonChecked(_hSelf, IDC_RADIO_LINEFORMAT_DEFAULT))
121 | m_pSetting->lineFormat = LineFormat::DEFAULT;
122 | else if (IsDlgButtonChecked(_hSelf, IDC_RADIO_LINEFORMAT_SINGLE))
123 | m_pSetting->lineFormat = LineFormat::SINGLELINE;
124 |
125 | m_pSetting->bFollowCurrentTab = CUtility::GetCheckboxStatus(::GetDlgItem(_hSelf, IDC_CHK_FOLLOW_CURRENT_DOC));
126 | m_pSetting->bAutoFormat = CUtility::GetCheckboxStatus(::GetDlgItem(_hSelf, IDC_CHK_FORMAT_ON_OPEN));
127 | m_pSetting->bUseJsonHighlight = CUtility::GetCheckboxStatus(::GetDlgItem(_hSelf, IDC_CHK_JSON_HIGHLIGHT));
128 | m_pSetting->parseOptions.bIgnoreTrailingComma = CUtility::GetCheckboxStatus(::GetDlgItem(_hSelf, IDC_CHK_IGNORE_COMMA));
129 | m_pSetting->parseOptions.bIgnoreComment = CUtility::GetCheckboxStatus(::GetDlgItem(_hSelf, IDC_CHK_IGNORE_COMMENT));
130 | m_pSetting->parseOptions.bReplaceUndefined = CUtility::GetCheckboxStatus(::GetDlgItem(_hSelf, IDC_CHK_REPLACE_UNDEFINED));
131 |
132 | return WriteINI();
133 | }
134 |
135 | void SettingsDlg::destroy() {}
136 |
137 | bool SettingsDlg::ReadINI()
138 | {
139 | return ProfileSetting(m_configPath).GetSettings(*m_pSetting);
140 | }
141 |
142 | bool SettingsDlg::WriteINI()
143 | {
144 | return ProfileSetting(m_configPath).SetSettings(*m_pSetting);
145 | }
146 |
147 | void SettingsDlg::InitDlg()
148 | {
149 | ReadINI();
150 |
151 | // Set UI control state here
152 |
153 | int nCtrlID = IDC_RADIO_LINE_AUTO;
154 | switch (m_pSetting->lineEnding)
155 | {
156 | case LineEnding::WINDOWS:
157 | nCtrlID = IDC_RADIO_LINE_WINDOW;
158 | break;
159 | case LineEnding::UNIX:
160 | nCtrlID = IDC_RADIO_LINE_UNIX;
161 | break;
162 | case LineEnding::MAC:
163 | nCtrlID = IDC_RADIO_LINE_MAC;
164 | break;
165 | case LineEnding::AUTO:
166 | nCtrlID = IDC_RADIO_LINE_AUTO;
167 | break;
168 | default:
169 | break;
170 | }
171 | CheckRadioButton(_hSelf, IDC_RADIO_LINE_AUTO, IDC_RADIO_LINE_MAC, nCtrlID);
172 |
173 |
174 | nCtrlID = IDC_RADIO_LINEFORMAT_DEFAULT;
175 | switch (m_pSetting->lineFormat)
176 | {
177 | case LineFormat::SINGLELINE:
178 | nCtrlID = IDC_RADIO_LINEFORMAT_SINGLE;
179 | break;
180 | case LineFormat::DEFAULT:
181 | nCtrlID = IDC_RADIO_LINEFORMAT_DEFAULT;
182 | break;
183 | default:
184 | break;
185 | }
186 | CheckRadioButton(_hSelf, IDC_RADIO_LINEFORMAT_DEFAULT, IDC_RADIO_LINEFORMAT_SINGLE, nCtrlID);
187 |
188 |
189 | switch (m_pSetting->indent.style)
190 | {
191 | case IndentStyle::AUTO:
192 | nCtrlID = IDC_RADIO_INDENT_AUTO;
193 | break;
194 | case IndentStyle::TAB:
195 | nCtrlID = IDC_RADIO_INDENT_TAB;
196 | break;
197 | case IndentStyle::SPACE:
198 | nCtrlID = IDC_RADIO_INDENT_SPACE;
199 | break;
200 | default:
201 | break;
202 | }
203 | CheckRadioButton(_hSelf, IDC_RADIO_INDENT_AUTO, IDC_RADIO_INDENT_SPACE, nCtrlID);
204 | CUtility::SetEditCtrlText(::GetDlgItem(_hSelf, IDC_EDT_INDENT_SPACECOUNT), std::to_wstring(m_pSetting->indent.len));
205 | ShowSpaceCountCtrls(m_pSetting->indent.style == IndentStyle::SPACE);
206 |
207 | CUtility::SetCheckboxStatus(::GetDlgItem(_hSelf, IDC_CHK_FOLLOW_CURRENT_DOC), m_pSetting->bFollowCurrentTab);
208 | CUtility::SetCheckboxStatus(::GetDlgItem(_hSelf, IDC_CHK_FORMAT_ON_OPEN), m_pSetting->bAutoFormat);
209 | CUtility::SetCheckboxStatus(::GetDlgItem(_hSelf, IDC_CHK_JSON_HIGHLIGHT), m_pSetting->bUseJsonHighlight);
210 | CUtility::SetCheckboxStatus(::GetDlgItem(_hSelf, IDC_CHK_IGNORE_COMMA), m_pSetting->parseOptions.bIgnoreTrailingComma);
211 | CUtility::SetCheckboxStatus(::GetDlgItem(_hSelf, IDC_CHK_IGNORE_COMMENT), m_pSetting->parseOptions.bIgnoreComment);
212 | CUtility::SetCheckboxStatus(::GetDlgItem(_hSelf, IDC_CHK_REPLACE_UNDEFINED), m_pSetting->parseOptions.bReplaceUndefined);
213 | }
214 |
215 | void SettingsDlg::ShowSpaceCountCtrls(bool bShow)
216 | {
217 | auto show = bShow ? SW_SHOW : SW_HIDE;
218 | ShowWindow(::GetDlgItem(_hSelf, IDC_EDT_INDENT_SPACECOUNT), show);
219 | ShowWindow(::GetDlgItem(_hSelf, IDC_STATIC_SPACECOUNT), show);
220 | }
221 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/SettingsDlg.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "StaticDialog.h"
3 | #include "Define.h"
4 | #include
5 | #include
6 |
7 | class SettingsDlg : public StaticDialog
8 | {
9 | public:
10 | SettingsDlg(HINSTANCE hInstance, HWND hParent, int nCmdId, const std::wstring& configPath, std::shared_ptr& pSetting);
11 | ~SettingsDlg() = default;
12 |
13 | bool ShowDlg(bool bShow);
14 |
15 | protected:
16 | virtual INT_PTR CALLBACK run_dlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam) override;
17 |
18 | private:
19 | bool Apply();
20 | void destroy() override;
21 | bool ReadINI();
22 | bool WriteINI();
23 | void InitDlg();
24 | void ShowSpaceCountCtrls(bool bShow);
25 |
26 | private:
27 | int m_nCmdId = -1;
28 | std::wstring m_configPath;
29 | std::shared_ptr m_pSetting = nullptr;
30 | };
31 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/ShortcutCommand.cpp:
--------------------------------------------------------------------------------
1 | #include "ShortcutCommand.h"
2 | #include
3 |
4 | ShortcutCommand::ShortcutCommand(int nCommandCount)
5 | : m_nCmdCount(nCommandCount)
6 | , m_pFuncItem(std::make_unique(nCommandCount))
7 | , m_pShortcutKeys(std::make_unique(nCommandCount))
8 | {
9 | }
10 |
11 | bool ShortcutCommand::SetCommand(CallBackID id, const TCHAR* cmdName, const PFUNCPLUGINCMD pFunc, bool checkOnInit)
12 | {
13 | int nIndex = static_cast(id);
14 |
15 | if (m_nCmdCount <= nIndex || !pFunc)
16 | return false;
17 |
18 | _tcscpy_s(m_pFuncItem[nIndex]._itemName, cmdName);
19 | m_pFuncItem[nIndex]._pFunc = pFunc;
20 | m_pFuncItem[nIndex]._init2Check = checkOnInit;
21 | m_pFuncItem[nIndex]._pShKey = &m_pShortcutKeys[nIndex];
22 |
23 | return true;
24 | }
25 |
26 | bool ShortcutCommand::SetShortCut(CallBackID id, const ShortcutKey& scKey)
27 | {
28 | int nIndex = static_cast(id);
29 |
30 | if (m_nCmdCount <= nIndex)
31 | return false;
32 |
33 | m_pShortcutKeys[At(id)] = scKey;
34 |
35 | return true;
36 | }
37 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/ShortcutCommand.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "Define.h"
3 | #include
4 |
5 | class ShortcutCommand
6 | {
7 | public:
8 | explicit ShortcutCommand(int nCommandCount);
9 | ~ShortcutCommand() = default;
10 |
11 | auto GetCommandID(CallBackID id) const -> int
12 | {
13 | return m_pFuncItem[At(id)]._cmdID;
14 | }
15 | auto GetFuncItem() const -> FuncItem*
16 | {
17 | return m_pFuncItem.get();
18 | }
19 |
20 | bool SetCommand(CallBackID id, const TCHAR* cmdName, const PFUNCPLUGINCMD pFunc, bool checkOnInit);
21 | bool SetShortCut(CallBackID id, const ShortcutKey& scKey);
22 |
23 | private:
24 | int At(CallBackID id) const
25 | {
26 | return static_cast(id);
27 | }
28 |
29 | private:
30 | std::unique_ptr m_pFuncItem = nullptr;
31 | std::unique_ptr m_pShortcutKeys = nullptr;
32 | int m_nCmdCount = 0;
33 | };
34 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/SliderCtrl.cpp:
--------------------------------------------------------------------------------
1 | #include "SliderCtrl.h"
2 |
3 | #include
4 |
5 | SliderCtrl::SliderCtrl(const SliderRange& sliderRange)
6 | : m_sliderRange(sliderRange)
7 | {
8 | }
9 |
10 | SliderCtrl::~SliderCtrl()
11 | {
12 | // Restore the original window procedure on cleanup
13 | SetWindowLongPtr(m_hSelf, GWLP_WNDPROC, reinterpret_cast(m_oldSliderProc));
14 | }
15 |
16 | void SliderCtrl::OnInit(HWND hParent, int sliderID, int sliderInfoID)
17 | {
18 | m_hParent = hParent;
19 | m_hSelf = GetDlgItem(m_hParent, sliderID);
20 | m_hSelfInfo = GetDlgItem(m_hParent, sliderInfoID);
21 |
22 | // Set slider range and initial position
23 | SendMessage(m_hSelf, TBM_SETRANGE, TRUE, MAKELPARAM(m_sliderRange.m_nMinZoom, m_sliderRange.m_nMaxZoom));
24 | SendMessage(m_hSelf, TBM_SETPOS, TRUE, m_sliderRange.m_nDefault);
25 | SendMessage(m_hSelf, TBM_SETPAGESIZE, 0, m_sliderRange.m_nSteps);
26 |
27 | UpdateInfo(m_sliderRange.m_nDefault);
28 |
29 | // Subclass the slider control to handle double-click events
30 | m_oldSliderProc = reinterpret_cast(SetWindowLongPtr(m_hSelfInfo, GWLP_WNDPROC, reinterpret_cast(runWinProc)));
31 |
32 | // Save this instance for access in the static window procedure
33 | SetWindowLongPtr(m_hSelfInfo, GWLP_USERDATA, reinterpret_cast(this));
34 | }
35 |
36 | auto SliderCtrl::GetPosition() const -> int
37 | {
38 | int pos = static_cast(SendMessage(m_hSelf, TBM_GETPOS, 0, 0));
39 | return pos;
40 | }
41 |
42 | void SliderCtrl::SetPosition(int pos) const
43 | {
44 | // Set slider position
45 | SendMessage(m_hSelf, TBM_SETPOS, TRUE, pos);
46 |
47 | // Set slider position in text value
48 | UpdateInfo(pos);
49 | }
50 |
51 | void SliderCtrl::UpdateInfo(int zoomPercentage) const
52 | {
53 | std::wstring sliderInfoText = std::to_wstring(zoomPercentage) + L"%";
54 | SetWindowText(m_hSelfInfo, sliderInfoText.c_str());
55 | }
56 |
57 | LRESULT SliderCtrl::runWinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
58 | {
59 | SliderCtrl* pThis = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA));
60 |
61 | if (pThis)
62 | {
63 | if (message == WM_LBUTTONDBLCLK)
64 | {
65 | // Reset slider to 100% on double-click
66 | // Also notify its parent to adjust tree view as well
67 | pThis->SetPosition(100);
68 | SendMessage(pThis->m_hParent, WM_HSCROLL, NULL, reinterpret_cast(pThis->m_hSelf));
69 | }
70 |
71 | // Call the original window procedure for other messages
72 | return CallWindowProc(pThis->m_oldSliderProc, hWnd, message, wParam, lParam);
73 | }
74 |
75 | return FALSE;
76 | }
77 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/SliderCtrl.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 |
4 | #include
5 | #include
6 |
7 | struct SliderRange
8 | {
9 | int m_nDefault = 100;
10 | int m_nMinZoom = 80;
11 | int m_nMaxZoom = 250;
12 | int m_nSteps = 10;
13 | }; // namespace SliderRange
14 |
15 | class SliderCtrl
16 | {
17 | HWND m_hParent = nullptr;
18 | HWND m_hSelf = nullptr;
19 | HWND m_hSelfInfo = nullptr;
20 | HWND m_hTreeView = nullptr;
21 | WNDPROC m_oldSliderProc = nullptr;
22 | const SliderRange m_sliderRange {};
23 |
24 | public:
25 | explicit SliderCtrl(const SliderRange& sliderRange = {});
26 |
27 | ~SliderCtrl();
28 |
29 | void OnInit(HWND hParent, int sliderID, int sliderInfoID);
30 |
31 | HWND GetSliderHandle() const
32 | {
33 | return m_hSelf;
34 | }
35 |
36 | HWND GetSliderInfoHandle() const
37 | {
38 | return m_hSelfInfo;
39 | }
40 |
41 | auto GetRange() const -> const SliderRange&
42 | {
43 | return m_sliderRange;
44 | }
45 |
46 | auto GetPosition() const -> int;
47 | void SetPosition(int pos) const;
48 | void UpdateInfo(int zoomPercentage) const;
49 |
50 | private:
51 | // Static window procedure for the slider
52 | static LRESULT CALLBACK runWinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
53 | };
54 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/StopWatch.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Stopwatch.h -- A simple stopwatch implementation, based on Windows
4 | // high-performance timers.
5 | // Can come in handy when measuring elapsed times of
6 | // portions of C++ code.
7 | //
8 | // Copyright (C) 2016 by Giovanni Dicanio
9 | //
10 | ////////////////////////////////////////////////////////////////////////////////
11 |
12 |
13 | #pragma once
14 |
15 | #include // For _ASSERTE
16 | #include // For high-performance timers
17 |
18 |
19 | namespace win32
20 | {
21 |
22 |
23 | //------------------------------------------------------------------------------
24 | // Class to measure time intervals, for benchmarking portions of code.
25 | // It's a convenient wrapper around the Win32 high-resolution timer APIs
26 | // QueryPerformanceCounter() and QueryPerformanceFrequency().
27 | //------------------------------------------------------------------------------
28 | class Stopwatch
29 | {
30 | public:
31 | // Initialize the stopwatch to a safe initial state
32 | Stopwatch() noexcept;
33 |
34 | // Clear the stopwatch state
35 | void Reset() noexcept;
36 |
37 | // Start measuring time.
38 | // When finished, call Stop().
39 | // Can call ElapsedTime() also before calling Stop(): in this case,
40 | // the elapsed time is measured since the Start() call.
41 | void Start() noexcept;
42 |
43 | // Stop measuring time.
44 | // Call ElapsedMilliseconds() to get the elapsed time from the Start() call.
45 | void Stop() noexcept;
46 |
47 | // Return elapsed time interval duration, in milliseconds.
48 | // Can be called both after Stop() and before it.
49 | // (Start() must have been called to initiate time interval measurements).
50 | double ElapsedMilliseconds() const noexcept;
51 |
52 |
53 | //
54 | // Ban copy
55 | //
56 | private:
57 | Stopwatch(const Stopwatch&) = delete;
58 | Stopwatch& operator=(const Stopwatch&) = delete;
59 |
60 |
61 | //
62 | // *** IMPLEMENTATION ***
63 | //
64 | private:
65 | bool m_running; // is the timer running?
66 | long long m_start; // start tick count
67 | long long m_finish; // end tick count
68 | const long long m_frequency; // cached frequency value
69 |
70 | //
71 | // According to MSDN documentation:
72 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms644905(v=vs.85).aspx
73 | //
74 | // The frequency of the performance counter is fixed at system boot and
75 | // is consistent across all processors.
76 | // Therefore, the frequency need only be queried upon application
77 | // initialization, and the result can be cached.
78 | //
79 |
80 | // Wrapper to Win32 API QueryPerformanceCounter()
81 | static long long Counter() noexcept;
82 |
83 | // Wrapper to Win32 API QueryPerformanceFrequency()
84 | static long long Frequency() noexcept;
85 |
86 | // Calculate elapsed time in milliseconds,
87 | // given a start tick and end tick counts.
88 | double ElapsedMilliseconds(long long start, long long finish) const noexcept;
89 | };
90 |
91 |
92 |
93 | //
94 | // Inline implementations
95 | //
96 |
97 |
98 | inline Stopwatch::Stopwatch() noexcept
99 | : m_running{ false }
100 | , m_start{ 0 }
101 | , m_finish{ 0 }
102 | , m_frequency{ Frequency() }
103 | {}
104 |
105 |
106 | inline void Stopwatch::Reset() noexcept
107 | {
108 | m_finish = m_start = 0;
109 | m_running = false;
110 | }
111 |
112 |
113 | inline void Stopwatch::Start() noexcept
114 | {
115 | m_running = true;
116 | m_finish = 0;
117 |
118 | m_start = Counter();
119 | }
120 |
121 |
122 | inline void Stopwatch::Stop() noexcept
123 | {
124 | m_finish = Counter();
125 | m_running = false;
126 | }
127 |
128 |
129 | inline double Stopwatch::ElapsedMilliseconds() const noexcept
130 | {
131 | if (m_running)
132 | {
133 | const long long current{ Counter() };
134 | return ElapsedMilliseconds(m_start, current);
135 | }
136 |
137 | return ElapsedMilliseconds(m_start, m_finish);
138 | }
139 |
140 |
141 | inline long long Stopwatch::Counter() noexcept
142 | {
143 | LARGE_INTEGER li;
144 | ::QueryPerformanceCounter(&li);
145 | return li.QuadPart;
146 | }
147 |
148 |
149 | inline long long Stopwatch::Frequency() noexcept
150 | {
151 | LARGE_INTEGER li;
152 | ::QueryPerformanceFrequency(&li);
153 | return li.QuadPart;
154 | }
155 |
156 |
157 | inline double Stopwatch::ElapsedMilliseconds(long long start, long long finish) const noexcept
158 | {
159 | _ASSERTE(start >= 0);
160 | _ASSERTE(finish >= 0);
161 | _ASSERTE(start <= finish);
162 |
163 | return ((finish - start) * 1000.0) / m_frequency;
164 | }
165 |
166 |
167 | } // namespace win32
168 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/TrackingStream.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | #include
7 |
8 |
9 | class TrackingStream : public std::enable_shared_from_this
10 | {
11 | private:
12 | char m_chPrevChar {}; // Store previous character for handling column postion
13 | size_t m_nLine {};
14 | size_t m_nColumn {};
15 | rapidjson::StringStream m_ss;
16 |
17 | public:
18 | using Ch = char; // Define Ch to conform to RapidJSON's expectations
19 |
20 | TrackingStream(const std::string& jsonText)
21 | : m_ss(jsonText.c_str())
22 | , m_nLine(0)
23 | , m_nColumn(0)
24 | , m_chPrevChar('\0')
25 | {
26 | }
27 |
28 | std::shared_ptr GetShared()
29 | {
30 | return shared_from_this();
31 | }
32 |
33 | inline size_t getLine() const
34 | {
35 | return m_nLine;
36 | }
37 |
38 | inline size_t getColumn() const
39 | {
40 | return m_nColumn;
41 | }
42 |
43 | // Read the next character and update line/column numbers
44 | Ch Take()
45 | {
46 | Ch ch = m_ss.Take();
47 | if (ch == '\n')
48 | {
49 | ++m_nLine;
50 | m_nColumn = 0;
51 | }
52 | else
53 | {
54 | ++m_nColumn;
55 | }
56 | m_chPrevChar = ch;
57 | return ch;
58 | }
59 |
60 | Ch Peek() const
61 | {
62 | return m_ss.Peek();
63 | }
64 |
65 | size_t Tell() const
66 | {
67 | return m_ss.Tell();
68 | }
69 |
70 | Ch* PutBegin()
71 | {
72 | return m_ss.PutBegin();
73 | }
74 |
75 | size_t PutEnd(Ch* pCh)
76 | {
77 | return m_ss.PutEnd(pCh);
78 | }
79 |
80 | void Put(Ch ch)
81 | {
82 | m_ss.Put(ch);
83 | }
84 | };
85 |
86 | using TrackingStreamSharedPtr = std::shared_ptr;
87 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/TreeHandler.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #include "JsonNode.h"
8 |
9 | class TreeHandler
10 | {
11 | public:
12 | virtual ~TreeHandler() = default;
13 |
14 | virtual HTREEITEM InsertToTree(HTREEITEM parent, const std::string& text) = 0;
15 | virtual HTREEITEM InsertToTree(HTREEITEM parent, const std::string& text, const Position& pos) = 0;
16 | virtual void AppendNodeCount(HTREEITEM node, unsigned elementCount, bool bArray) = 0;
17 | };
18 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/TreeViewCtrl.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include
6 | #include
7 |
8 | #include "JsonNode.h"
9 |
10 | class TreeViewCtrl
11 | {
12 | HWND m_hTree = nullptr;
13 | HWND m_hParent = nullptr;
14 | int m_nCtrlID = 0;
15 | size_t m_nMaxNodeTextLength = 0;
16 |
17 | public:
18 | TreeViewCtrl() = default;
19 | ~TreeViewCtrl() = default;
20 |
21 | void OnInit(HWND hParent, int ctrlID);
22 |
23 | HWND GetTreeViewHandle() const
24 | {
25 | return m_hTree;
26 | }
27 |
28 | auto InitTree() -> HTREEITEM;
29 | auto InsertNode(const std::wstring& text, LPARAM lparam, HTREEITEM parentNode) -> HTREEITEM;
30 | void UpdateNodeText(HTREEITEM node, const std::wstring& text);
31 | auto GetNodeCount() const -> unsigned int;
32 |
33 | bool IsExpanded(HTREEITEM node) const;
34 | bool IsThisOrAnyChildExpanded(HTREEITEM node) const;
35 | bool IsThisOrAnyChildCollapsed(HTREEITEM node) const;
36 |
37 | void Expand(HTREEITEM node) const;
38 | void Collapse(HTREEITEM node) const;
39 |
40 | BOOL ScreenToTreeView(LPPOINT lpPoint) const;
41 | auto HitTest(LPTVHITTESTINFO lpHTInfo) const -> HTREEITEM;
42 |
43 | auto GetRoot() const -> HTREEITEM;
44 | bool SelectItem(HTREEITEM hti, bool firstVisible = false) const;
45 | bool HasChild(HTREEITEM hti) const;
46 |
47 | HTREEITEM GetSelection() const;
48 | void SetSelection(HTREEITEM hItem) const;
49 |
50 | bool IsItemVisible(HTREEITEM hti) const;
51 |
52 | HTREEITEM NextItem(HTREEITEM htiCurrent) const
53 | {
54 | return NextItem(htiCurrent, nullptr);
55 | }
56 |
57 | HTREEITEM NextItem(HTREEITEM htiCurrent, HTREEITEM htiNextRoot) const;
58 |
59 | auto GetNodeName(HTREEITEM hti, bool removeTrailingCount) const -> std::wstring;
60 | auto GetNodePos(HTREEITEM hti) const -> LPARAM;
61 | auto GetNodeKey(HTREEITEM hti) const -> std::wstring;
62 | auto GetNodeValue(HTREEITEM hti) const -> std::wstring;
63 | auto GetNodePath(HTREEITEM hti) const -> std::wstring;
64 | auto GetNodePosition(HTREEITEM hti) const -> Position*;
65 |
66 | private:
67 | void ExpandOrCollapse(HTREEITEM node, UINT_PTR code) const;
68 |
69 | HTREEITEM GetParentItem(HTREEITEM hti) const;
70 |
71 | bool GetTVItem(HTREEITEM hti, TVITEM* tvi) const;
72 | bool SetTVItem(TVITEM* tvi) const;
73 |
74 | void FreeNodeData(HTREEITEM hItem);
75 | void DeleteAllNodes();
76 | };
77 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/dllmain.cpp:
--------------------------------------------------------------------------------
1 | // DllMain.cpp : Defines the entry point for the DLL application.
2 |
3 | #include "NppJsonPlugin.h"
4 |
5 | NppJsonPlugin g_NppJsonPlugin;
6 |
7 | BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID /*lpReserved*/)
8 | {
9 | switch (ul_reason_for_call)
10 | {
11 | case DLL_PROCESS_ATTACH:
12 | g_NppJsonPlugin.PluginInit(hModule);
13 | break;
14 |
15 | case DLL_PROCESS_DETACH:
16 | g_NppJsonPlugin.PluginCleanup();
17 | break;
18 |
19 | case DLL_THREAD_ATTACH:
20 | case DLL_THREAD_DETACH:
21 | break;
22 | }
23 | return TRUE;
24 | }
25 |
26 | // Below are the mandatory function to be implemented as Notepad++ requires them
27 |
28 | extern "C" __declspec(dllexport) void setInfo(NppData notepadPlusData)
29 | {
30 | g_NppJsonPlugin.SetInfo(notepadPlusData);
31 | }
32 |
33 | extern "C" __declspec(dllexport) const TCHAR* getName()
34 | {
35 | return g_NppJsonPlugin.GetPluginName();
36 | }
37 |
38 | extern "C" __declspec(dllexport) FuncItem* getFuncsArray(int* nbF)
39 | {
40 | return g_NppJsonPlugin.GetFuncsArray(nbF);
41 | }
42 |
43 | extern "C" __declspec(dllexport) void beNotified(SCNotification* notifyCode)
44 | {
45 | g_NppJsonPlugin.ProcessNotification(notifyCode);
46 | }
47 |
48 | // Here you can process the Npp Messages
49 | // I will make the messages accessible little by little, according to the need of plugin development.
50 | // Please let me know if you need to access to some messages :
51 | // http://sourceforge.net/forum/forum.php?forum_id=482781
52 | //
53 | extern "C" __declspec(dllexport) LRESULT messageProc(UINT msg, WPARAM wParam, LPARAM lParam)
54 | {
55 | return g_NppJsonPlugin.MessageProc(msg, wParam, lParam);
56 | }
57 |
58 | #ifdef UNICODE
59 | extern "C" __declspec(dllexport) BOOL isUnicode()
60 | {
61 | return g_NppJsonPlugin.IsUnicode();
62 | }
63 | #endif // UNICODE
64 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/res/Icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NPP-JSONViewer/JSON-Viewer/d0a79bc83df3d1c25ceb3d345bf1b74604dce8b1/src/NppJsonViewer/res/Icon.ico
--------------------------------------------------------------------------------
/src/NppJsonViewer/res/Refresh.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NPP-JSONViewer/JSON-Viewer/d0a79bc83df3d1c25ceb3d345bf1b74604dce8b1/src/NppJsonViewer/res/Refresh.ico
--------------------------------------------------------------------------------
/src/NppJsonViewer/res/format.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NPP-JSONViewer/JSON-Viewer/d0a79bc83df3d1c25ceb3d345bf1b74604dce8b1/src/NppJsonViewer/res/format.ico
--------------------------------------------------------------------------------
/src/NppJsonViewer/res/search.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NPP-JSONViewer/JSON-Viewer/d0a79bc83df3d1c25ceb3d345bf1b74604dce8b1/src/NppJsonViewer/res/search.ico
--------------------------------------------------------------------------------
/src/NppJsonViewer/res/validate.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NPP-JSONViewer/JSON-Viewer/d0a79bc83df3d1c25ceb3d345bf1b74604dce8b1/src/NppJsonViewer/res/validate.ico
--------------------------------------------------------------------------------
/src/NppJsonViewer/resource.h:
--------------------------------------------------------------------------------
1 | //{{NO_DEPENDENCIES}}
2 | // Microsoft Visual C++ generated include file.
3 | // Used by resource.rc
4 | //
5 | #define IDD_TREEDLG 101
6 | #define IDD_SETTING 102
7 | #define IDD_ABOUTDLG 103
8 | #define IDR_TREEITEM_MENU 104
9 | #define IDI_ICON_REFRESH 105
10 | #define IDI_ICON_SEARCH 106
11 | #define IDI_ICON_FORMAT 107
12 | #define IDI_ICON_VALIDATE 108
13 | #define IDI_ICON_TOOLBAR 109
14 | #define IDC_TREE 1001
15 | #define IDC_WEB_SOURCE 1002
16 | #define IDC_WEB_ISSUE 1003
17 | #define IDC_GB_TITLE 1004
18 | #define IDC_SYSLINK_EMAIL 1006
19 | #define IDC_BTN_REFRESH 1007
20 | #define IDC_BTN_FORMAT 1008
21 | #define IDC_EDT_NODEPATH 1009
22 | #define IDC_EDT_SEARCH 1010
23 | #define IDC_BTN_SEARCH 1011
24 | #define IDC_DIVIDER 1012
25 | #define IDC_BTN_VALIDATE 1013
26 | #define IDC_HOR_BAR_TOP 1014
27 | #define IDC_HOR_BAR_BOTTOM 1015
28 | #define IDC_RADIO_LINE_AUTO 1016
29 | #define IDC_RADIO_LINE_WINDOW 1017
30 | #define IDC_RADIO_LINE_UNIX 1018
31 | #define IDC_RADIO_LINE_MAC 1019
32 | #define IDC_RADIO_INDENT_AUTO 1020
33 | #define IDC_RADIO_INDENT_TAB 1021
34 | #define IDC_RADIO_INDENT_SPACE 1022
35 | #define IDC_EDT_INDENT_SPACECOUNT 1023
36 | #define IDC_STATIC_SPACECOUNT 1024
37 | #define IDC_RADIO_LINEFORMAT_DEFAULT 1025
38 | #define IDC_RADIO_LINEFORMAT_SINGLE 1026
39 | #define IDC_CHK_FOLLOW_CURRENT_DOC 1028
40 | #define IDC_CHK_FORMAT_ON_OPEN 1029
41 | #define IDC_CHK_IGNORE_COMMA 1030
42 | #define IDC_CHK_IGNORE_COMMENT 1031
43 | #define IDC_CHK_JSON_HIGHLIGHT 1032
44 | #define IDC_CHK_REPLACE_UNDEFINED 1033
45 | #define IDC_ZOOM_SLIDER 1034
46 | #define IDC_ZOOM_PERCENT 1035
47 | #define IDM_COPY_TREEITEM 40001
48 | #define IDM_COPY_NODENAME 40002
49 | #define IDM_COPY_NODEVALUE 40003
50 | #define IDM_COPY_NODEPATH 40004
51 | #define IDM_EXPANDALL 40005
52 | #define IDM_COLLAPSEALL 40006
53 |
54 | // Next default values for new objects
55 | //
56 | #ifdef APSTUDIO_INVOKED
57 | #ifndef APSTUDIO_READONLY_SYMBOLS
58 | #define _APS_NEXT_RESOURCE_VALUE 110
59 | #define _APS_NEXT_COMMAND_VALUE 40007
60 | #define _APS_NEXT_CONTROL_VALUE 1036
61 | #define _APS_NEXT_SYMED_VALUE 101
62 | #endif
63 | #endif
64 |
--------------------------------------------------------------------------------
/src/NppJsonViewer/resource.rc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NPP-JSONViewer/JSON-Viewer/d0a79bc83df3d1c25ceb3d345bf1b74604dce8b1/src/NppJsonViewer/resource.rc
--------------------------------------------------------------------------------
/src/NppJsonViewerCommon.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | $(SolutionDir)Build\Bin\$(Configuration)\$(Platform)\
7 | $(SolutionDir)Build\Intermediate\$(ProjectName)\$(Configuration)\$(Platform)\
8 | $(SolutionDir)..\external\npp;$(SolutionDir)..\external\rapidjson\include;$(ExternalIncludePath)
9 | $(SolutionDir)UtilityLib;$(IncludePath)
10 |
11 |
12 |
13 | Level4
14 | true
15 | true
16 | true
17 | stdcpp20
18 | true
19 | true
20 |
21 |
22 | true
23 |
24 |
25 |
26 |
27 | MultiThreaded
28 |
29 |
30 | true
31 | true
32 |
33 |
34 |
35 |
36 | MultiThreadedDebug
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/UtilityLib/Execute.cpp:
--------------------------------------------------------------------------------
1 | #include "Execute.h"
2 |
3 | Execute::Execute(const TCHAR* cmd, const TCHAR* args, const TCHAR* cDir, bool show)
4 | : m_Command(cmd)
5 | , m_Args(args)
6 | , m_CurDir(cDir)
7 | , m_bShow(show)
8 | {
9 | m_ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
10 | m_ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
11 | m_ShExecInfo.hwnd = NULL;
12 | m_ShExecInfo.lpFile = m_Command.c_str();
13 | m_ShExecInfo.lpParameters = m_Args.c_str();
14 | m_ShExecInfo.lpDirectory = m_CurDir.c_str();
15 | m_ShExecInfo.nShow = show ? SW_SHOWNORMAL : SW_HIDE;
16 | m_ShExecInfo.hInstApp = NULL;
17 | }
18 |
19 | bool Execute::Run(bool isElevationRequired)
20 | {
21 | m_ShExecInfo.lpVerb = isElevationRequired ? TEXT("runas") : TEXT("open");
22 |
23 | auto shellExecRes = ::ShellExecuteEx(&m_ShExecInfo);
24 | return shellExecRes ? false : true;
25 | }
26 |
27 | DWORD Execute::RunSync(bool isElevationRequired)
28 | {
29 | m_ShExecInfo.lpVerb = isElevationRequired ? TEXT("runas") : TEXT("open");
30 |
31 | ShellExecuteEx(&m_ShExecInfo);
32 | WaitForSingleObject(m_ShExecInfo.hProcess, INFINITE);
33 |
34 | DWORD exitCode = 0;
35 | if (::GetExitCodeProcess(m_ShExecInfo.hProcess, &exitCode) == FALSE)
36 | {
37 | exitCode = GetLastError();
38 | }
39 |
40 | return exitCode;
41 | }
42 |
--------------------------------------------------------------------------------
/src/UtilityLib/Execute.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | class Execute
8 | {
9 | public:
10 | Execute(const TCHAR* cmd, const TCHAR* args, const TCHAR* cDir, bool show = false);
11 |
12 | bool Run(bool isElevationRequired = false);
13 | DWORD RunSync(bool isElevationRequired = false);
14 |
15 | private:
16 | std::wstring m_Command;
17 | std::wstring m_Args;
18 | std::wstring m_CurDir;
19 | bool m_bShow = false;
20 | SHELLEXECUTEINFO m_ShExecInfo = {};
21 | };
22 |
--------------------------------------------------------------------------------
/src/UtilityLib/StringHelper.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "StringHelper.h"
4 |
5 | std::string StringHelper::ReplaceAll(const std::string& str, const std::string& search, const std::string& replace)
6 | {
7 | return std::regex_replace(str, std::regex(search), replace);
8 | }
9 |
10 | std::wstring StringHelper::ReplaceAll(const std::wstring& wstr, const std::wstring& search, const std::wstring& replace)
11 | {
12 | return std::regex_replace(wstr, std::wregex(search), replace);
13 | }
14 |
15 | std::wstring StringHelper::ToWstring(const std::string& str, UINT codePage)
16 | {
17 | std::wstring wstr;
18 |
19 | if (!str.empty())
20 | {
21 | auto required = ::MultiByteToWideChar(codePage, 0, str.data(), static_cast(str.size()), NULL, 0);
22 | if (0 != required)
23 | {
24 | wstr.resize(required);
25 |
26 | auto converted = ::MultiByteToWideChar(codePage, 0, str.data(), static_cast(str.size()), &wstr[0], static_cast(wstr.capacity()));
27 | if (0 == converted)
28 | {
29 | wstr.clear();
30 | }
31 | }
32 | }
33 |
34 | return wstr;
35 | }
36 |
37 | std::string StringHelper::ToString(const std::wstring& wstr, UINT codePage)
38 | {
39 | std::string str;
40 | if (!wstr.empty())
41 | {
42 | auto required = ::WideCharToMultiByte(codePage, 0, wstr.data(), static_cast(wstr.size()), NULL, 0, NULL, NULL);
43 | if (0 != required)
44 | {
45 | str.resize(required);
46 |
47 | auto converted = ::WideCharToMultiByte(codePage, 0, wstr.data(), static_cast(wstr.size()), &str[0], static_cast(str.capacity()), NULL, NULL);
48 | if (0 == converted)
49 | {
50 | str.clear();
51 | }
52 | }
53 | }
54 |
55 | return str;
56 | }
57 |
58 | std::vector StringHelper::Split(const std::string& input, const std::string& delim)
59 | {
60 | // Vector is created on stack and copied on return
61 | std::vector tokens;
62 |
63 | // Skip delimiters at beginning.
64 | auto lastPos = input.find_first_not_of(delim, 0);
65 | // Find first "non-delimiter".
66 | auto pos = input.find_first_of(delim, lastPos);
67 |
68 | while (pos != std::string::npos || lastPos != std::string::npos)
69 | {
70 | // Found a token, add it to the vector.
71 | tokens.push_back(input.substr(lastPos, pos - lastPos));
72 | // Skip delimiters. Note the "not_of"
73 | lastPos = input.find_first_not_of(delim, pos);
74 | // Find next "non-delimiter"
75 | pos = input.find_first_of(delim, lastPos);
76 | }
77 | return tokens;
78 | }
79 |
80 | std::vector StringHelper::Split(const std::wstring& input, const std::wstring& delim)
81 | {
82 | // Vector is created on stack and copied on return
83 | std::vector tokens;
84 |
85 | // Skip delimiters at beginning.
86 | auto lastPos = input.find_first_not_of(delim, 0);
87 | // Find first "non-delimiter".
88 | auto pos = input.find_first_of(delim, lastPos);
89 |
90 | while (pos != std::wstring::npos || lastPos != std::wstring::npos)
91 | {
92 | // Found a token, add it to the vector.
93 | tokens.push_back(input.substr(lastPos, pos - lastPos));
94 | // Skip delimiters. Note the "not_of"
95 | lastPos = input.find_first_not_of(delim, pos);
96 | // Find next "non-delimiter"
97 | pos = input.find_first_of(delim, lastPos);
98 | }
99 | return tokens;
100 | }
101 |
102 | bool StringHelper::Contains(const std::string& input, const std::string& search, bool ignoreCase)
103 | {
104 | return Contains(ToWstring(input), ToWstring(search), ignoreCase);
105 | }
106 |
107 | bool StringHelper::Contains(const std::wstring& input, const std::wstring& search, bool ignoreCase)
108 | {
109 | std::wstring lower_input = input;
110 | std::wstring lower_search = search;
111 | if (ignoreCase)
112 | {
113 | ToLower(lower_input);
114 | ToLower(lower_search);
115 | }
116 |
117 | return lower_input.find(lower_search) != std::wstring::npos;
118 | }
119 |
120 | void StringHelper::ToLower(std::string& input)
121 | {
122 | auto s = ToWstring(input);
123 | ToLower(s);
124 | input = ToString(s);
125 | }
126 |
127 | void StringHelper::ToLower(std::wstring& input)
128 | {
129 | std::transform(input.begin(), input.end(), input.begin(), ::towlower);
130 | }
131 |
--------------------------------------------------------------------------------
/src/UtilityLib/StringHelper.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 |
6 | class StringHelper
7 | {
8 | public:
9 | StringHelper() = default;
10 | ~StringHelper() = default;
11 |
12 | static std::string ReplaceAll(const std::string& str, const std::string& search, const std::string& replace);
13 | static std::wstring ReplaceAll(const std::wstring& wstr, const std::wstring& search, const std::wstring& replace);
14 |
15 | static std::wstring ToWstring(const std::string& str, UINT codePage = CP_THREAD_ACP);
16 | static std::string ToString(const std::wstring& wstr, UINT codePage = CP_THREAD_ACP);
17 |
18 | static std::vector Split(const std::string& input, const std::string& delim);
19 | static std::vector Split(const std::wstring& input, const std::wstring& delim);
20 |
21 | static bool Contains(const std::string& input, const std::string& search, bool ignorecase = true);
22 | static bool Contains(const std::wstring& input, const std::wstring& search, bool ignorecase = true);
23 |
24 | static void ToLower(std::string& input);
25 | static void ToLower(std::wstring& input);
26 | };
27 |
--------------------------------------------------------------------------------
/src/UtilityLib/Utility.cpp:
--------------------------------------------------------------------------------
1 | #include "Utility.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #pragma comment(lib, "Version.lib")
12 | #pragma comment(lib, "shlwapi.lib")
13 | #pragma comment(lib, "Comctl32.lib")
14 |
15 |
16 | std::wstring CUtility::GetVersion(const std::wstring& filePath)
17 | {
18 | std::wstring retVer;
19 |
20 | if (!filePath.empty() && ::PathFileExists(filePath.c_str()))
21 | {
22 | DWORD handle = 0;
23 | DWORD bufferSize = ::GetFileVersionInfoSize(filePath.c_str(), &handle);
24 |
25 | if (bufferSize > 0)
26 | {
27 | auto buffer = std::make_unique(bufferSize);
28 | ::GetFileVersionInfo(filePath.c_str(), 0, bufferSize, reinterpret_cast(buffer.get()));
29 |
30 | VS_FIXEDFILEINFO* lpFileInfo = nullptr;
31 | UINT cbFileInfo = 0;
32 | VerQueryValue(buffer.get(), TEXT("\\"), reinterpret_cast(&lpFileInfo), &cbFileInfo);
33 | if (cbFileInfo)
34 | {
35 | std::wostringstream os;
36 | os << ((lpFileInfo->dwFileVersionMS & 0xFFFF0000) >> 16);
37 | os << '.';
38 | os << (lpFileInfo->dwFileVersionMS & 0x0000FFFF);
39 | os << '.';
40 | os << ((lpFileInfo->dwFileVersionLS & 0xFFFF0000) >> 16);
41 | os << '.';
42 | os << (lpFileInfo->dwFileVersionLS & 0x0000FFFF);
43 |
44 | retVer = os.str();
45 | }
46 | }
47 | }
48 |
49 | return retVer;
50 | }
51 |
52 | HWND CUtility::CreateToolTip(HWND hWnd, int nCtrlID, const std::wstring& tooltipText, HINSTANCE hInst)
53 | {
54 | if (nCtrlID == 0 || hWnd == nullptr || tooltipText.empty())
55 | {
56 | return nullptr;
57 | }
58 |
59 | // Get the window of the tool.
60 | HWND hControl = GetDlgItem(hWnd, nCtrlID);
61 |
62 | // Create the tooltip. g_hInst is the global instance handle.
63 | HWND hToolTip
64 | = CreateWindowEx(NULL, TOOLTIPS_CLASS, nullptr, WS_POPUP | TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hWnd, nullptr, hInst, nullptr);
65 |
66 | if (hControl == nullptr || hToolTip == nullptr)
67 | {
68 | return nullptr;
69 | }
70 |
71 | // Associate the tooltip with the control.
72 | TOOLINFO toolInfo = {};
73 | toolInfo.cbSize = sizeof(toolInfo);
74 | toolInfo.hwnd = hWnd;
75 | toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
76 | toolInfo.uId = reinterpret_cast(hControl);
77 | toolInfo.lpszText = const_cast(tooltipText.c_str());
78 | SendMessage(hToolTip, TTM_ADDTOOL, 0, reinterpret_cast(&toolInfo));
79 |
80 | return hToolTip;
81 | }
82 |
83 | float CUtility::GetDesktopScale(HWND hWnd)
84 | {
85 | HDC hdc = GetDC(hWnd);
86 | float fScale = GetDeviceCaps(hdc, LOGPIXELSX) / 96.0f;
87 | ReleaseDC(hWnd, hdc);
88 | return fScale;
89 | }
90 |
91 | short CUtility::GetXFromLPARAM(LPARAM lp)
92 | {
93 | return static_cast(LOWORD(lp));
94 | }
95 |
96 | short CUtility::GetYFromLPARAM(LPARAM lp)
97 | {
98 | return static_cast(HIWORD(lp));
99 | }
100 |
101 | std::wstring CUtility::GetEditCtrlText(HWND hWnd)
102 | {
103 | auto length = Edit_GetTextLength(hWnd);
104 | std::vector buf(length + 1);
105 | Edit_GetText(hWnd, buf.data(), static_cast(buf.size()));
106 | return buf.data();
107 | }
108 |
109 | void CUtility::SetEditCtrlText(HWND hWnd, const std::wstring& txt)
110 | {
111 | Edit_SetText(hWnd, txt.data());
112 | }
113 |
114 | bool CUtility::GetCheckboxStatus(HWND hWnd)
115 | {
116 | return Button_GetCheck(hWnd);
117 | }
118 |
119 | void CUtility::SetCheckboxStatus(HWND hWnd, bool bCheck)
120 | {
121 | Button_SetCheck(hWnd, bCheck);
122 | }
123 |
124 | bool CUtility::DirExist(const std::wstring& dirPath)
125 | {
126 | return std::filesystem::exists(dirPath);
127 | }
128 |
129 | bool CUtility::FileExist(const std::wstring& filePath)
130 | {
131 | bool r = std::filesystem::exists(filePath);
132 | return r;
133 | }
134 |
135 | long CUtility::FileSize(const std::wstring& filePath)
136 | {
137 | auto r = std::filesystem::file_size(filePath);
138 | return static_cast(r);
139 | }
140 |
141 | bool CUtility::CreateDir(const std::wstring& dirPath)
142 | {
143 | bool r = std::filesystem::create_directories(dirPath);
144 | return r;
145 | }
146 |
147 | bool CUtility::Copy(const std::wstring& srcFile, const std::wstring& dstFile)
148 | {
149 | bool r = std::filesystem::copy_file(srcFile, dstFile);
150 | return r;
151 | }
152 |
153 | auto CUtility::GetFileName(const std::wstring& fullPath, bool withExtension) -> std::wstring
154 | {
155 | std::filesystem::path pathObj(fullPath);
156 |
157 | // Check if file name is required without extension
158 | if (withExtension == false)
159 | {
160 | // Check if file has stem i.e. filename without extension
161 | if (pathObj.has_stem())
162 | {
163 | // return the stem (file name without extension) from path object
164 | return pathObj.stem().wstring();
165 | }
166 | }
167 |
168 | // return the file name with extension from path object
169 | return pathObj.filename().wstring();
170 | }
171 |
172 | auto CUtility::GetFileExtension(const std::wstring& fileName) -> std::wstring
173 | {
174 | std::wstring retVal;
175 |
176 | std::filesystem::path pathObj(fileName);
177 |
178 | // Check if file has stem i.e. filename without extension
179 | if (pathObj.has_stem())
180 | {
181 | retVal = pathObj.filename().extension().wstring();
182 | }
183 | return retVal;
184 | }
185 |
186 | auto CUtility::GetTempFilePath() -> std::wstring
187 | {
188 | TCHAR tmpDir[1024] {};
189 | GetTempPath(1024, tmpDir);
190 | return tmpDir;
191 | }
192 |
193 | auto CUtility::GetSpecialFolderLocation(int folderKind) -> std::wstring
194 | {
195 | wchar_t path[MAX_PATH] = {};
196 | const HRESULT specialLocationResult = SHGetFolderPath(nullptr, folderKind, nullptr, SHGFP_TYPE_CURRENT, path);
197 |
198 | std::wstring result;
199 | if (SUCCEEDED(specialLocationResult))
200 | {
201 | result = path;
202 | }
203 | return result;
204 | }
205 |
206 | bool CUtility::OpenFileDlg(std::wstring& filePath, const std::wstring& dlgTitle, const std::vector& dlgFilter, DWORD flags)
207 | {
208 | bool bRetVal = false;
209 |
210 | OPENFILENAME ofn;
211 | ::memset(&ofn, 0, sizeof(ofn));
212 | wchar_t fileName[MAX_PATH] = {};
213 | ofn.lStructSize = sizeof(ofn);
214 | ofn.lpstrTitle = dlgTitle.c_str();
215 | ofn.lpstrFilter = dlgFilter.data();
216 | ofn.nFilterIndex = 1;
217 | ofn.lpstrFile = fileName;
218 | ofn.nMaxFile = MAX_PATH;
219 | ofn.Flags = flags ? flags : OFN_FILEMUSTEXIST;
220 |
221 | if (::GetOpenFileName(&ofn) != FALSE)
222 | {
223 | filePath = ofn.lpstrFile; // will have the full path and file name.
224 | bRetVal = true;
225 | }
226 |
227 | return bRetVal;
228 | }
229 |
230 | bool CUtility::CopyToClipboard(const std::wstring& str2cpy, HWND hWnd)
231 | {
232 | size_t len2Allocate = (str2cpy.size() + 1) * sizeof(TCHAR);
233 | HGLOBAL hglbCopy = ::GlobalAlloc(GMEM_MOVEABLE, len2Allocate);
234 | if (hglbCopy == NULL)
235 | {
236 | return false;
237 | }
238 |
239 | if (!::OpenClipboard(hWnd))
240 | {
241 | ::GlobalFree(hglbCopy);
242 | ::CloseClipboard();
243 | return false;
244 | }
245 |
246 | if (!::EmptyClipboard())
247 | {
248 | ::GlobalFree(hglbCopy);
249 | ::CloseClipboard();
250 | return false;
251 | }
252 |
253 | // Lock the handle and copy the text to the buffer.
254 | wchar_t* pStr = reinterpret_cast(::GlobalLock(hglbCopy));
255 | if (pStr == NULL)
256 | {
257 | ::GlobalUnlock(hglbCopy);
258 | ::GlobalFree(hglbCopy);
259 | ::CloseClipboard();
260 | return false;
261 | }
262 |
263 | wcscpy_s(pStr, len2Allocate / sizeof(wchar_t), str2cpy.c_str());
264 | ::GlobalUnlock(hglbCopy);
265 |
266 | // Place the handle on the clipboard.
267 | unsigned int clipBoardFormat = CF_UNICODETEXT;
268 | if (::SetClipboardData(clipBoardFormat, hglbCopy) == NULL)
269 | {
270 | ::GlobalFree(hglbCopy);
271 | ::CloseClipboard();
272 | return false;
273 | }
274 |
275 | if (!::CloseClipboard())
276 | {
277 | return false;
278 | }
279 |
280 | return true;
281 | }
282 |
283 | bool CUtility::IsNumber(const std::wstring& str)
284 | {
285 | return !str.empty()
286 | && std::find_if(
287 | str.begin(),
288 | str.end(),
289 | [](wchar_t c)
290 | {
291 | return !std::isdigit(c);
292 | })
293 | == str.end();
294 | }
295 |
296 | auto CUtility::GetNumber(const std::wstring& str) -> std::optional
297 | {
298 | std::optional retVal = std::nullopt;
299 | if (IsNumber(str))
300 | retVal = std::make_optional(std::stoi(str));
301 |
302 | return retVal;
303 | }
304 |
--------------------------------------------------------------------------------
/src/UtilityLib/Utility.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | class CUtility
9 | {
10 | public:
11 | CUtility() = default;
12 | ~CUtility() = default;
13 |
14 | static std::wstring GetVersion(const std::wstring& filePath);
15 |
16 | static HWND CreateToolTip(HWND hWnd, int nCtrlID, const std::wstring& tooltipText, HINSTANCE hInst = nullptr);
17 |
18 | static float GetDesktopScale(HWND hWnd);
19 |
20 | static short GetXFromLPARAM(LPARAM lp);
21 | static short GetYFromLPARAM(LPARAM lp);
22 |
23 | static auto GetEditCtrlText(HWND hWnd) -> std::wstring;
24 | static void SetEditCtrlText(HWND hWnd, const std::wstring& txt);
25 |
26 | static bool GetCheckboxStatus(HWND hWnd);
27 | static void SetCheckboxStatus(HWND hWnd, bool bCheck);
28 |
29 | static bool DirExist(const std::wstring& dirPath);
30 | static bool FileExist(const std::wstring& filePath);
31 |
32 | static long FileSize(const std::wstring& filePath);
33 |
34 | static bool CreateDir(const std::wstring& dirPath);
35 |
36 | static bool Copy(const std::wstring& srcFile, const std::wstring& dstFile);
37 |
38 | static auto GetFileName(const std::wstring& fullPath, bool withExtension = true) -> std::wstring;
39 | static auto GetFileExtension(const std::wstring& fileName) -> std::wstring;
40 |
41 | static auto GetTempFilePath() -> std::wstring;
42 | static auto GetSpecialFolderLocation(int folderKind) -> std::wstring;
43 |
44 | static bool OpenFileDlg(std::wstring& filePath, const std::wstring& dlgTitle, const std::vector& dlgFilter, DWORD flags = 0);
45 |
46 | static bool CopyToClipboard(const std::wstring& str2cpy, HWND hWnd);
47 |
48 | static bool IsNumber(const std::wstring& str);
49 | static auto GetNumber(const std::wstring& str) -> std::optional;
50 | };
51 |
--------------------------------------------------------------------------------
/src/UtilityLib/UtilityLib.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | ARM64
7 |
8 |
9 | Debug
10 | Win32
11 |
12 |
13 | Release
14 | ARM64
15 |
16 |
17 | Release
18 | Win32
19 |
20 |
21 | Debug
22 | x64
23 |
24 |
25 | Release
26 | x64
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | 16.0
41 | Win32Proj
42 | {171cafc6-e679-4b81-bf5b-049ac0fab4f8}
43 | UtilityLib
44 | 10.0
45 |
46 |
47 |
48 | StaticLibrary
49 | true
50 | v143
51 | Unicode
52 |
53 |
54 | StaticLibrary
55 | false
56 | v143
57 | true
58 | Unicode
59 |
60 |
61 | StaticLibrary
62 | true
63 | v143
64 | Unicode
65 |
66 |
67 | StaticLibrary
68 | true
69 | v143
70 | Unicode
71 |
72 |
73 | StaticLibrary
74 | false
75 | v143
76 | true
77 | Unicode
78 |
79 |
80 | StaticLibrary
81 | false
82 | v143
83 | true
84 | Unicode
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
119 |
120 |
121 |
122 |
123 | true
124 |
125 |
126 |
127 |
128 | true
129 | true
130 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
131 |
132 |
133 |
134 |
135 | true
136 | true
137 | true
138 |
139 |
140 |
141 |
142 | _DEBUG;_LIB;%(PreprocessorDefinitions)
143 |
144 |
145 |
146 |
147 | true
148 |
149 |
150 |
151 |
152 | _DEBUG;_LIB;%(PreprocessorDefinitions)
153 |
154 |
155 |
156 |
157 | true
158 |
159 |
160 |
161 |
162 | true
163 | true
164 | NDEBUG;_LIB;%(PreprocessorDefinitions)
165 |
166 |
167 |
168 |
169 | true
170 | true
171 | true
172 |
173 |
174 |
175 |
176 | true
177 | true
178 | NDEBUG;_LIB;%(PreprocessorDefinitions)
179 |
180 |
181 |
182 |
183 | true
184 | true
185 | true
186 |
187 |
188 |
189 |
190 |
191 |
--------------------------------------------------------------------------------
/src/UtilityLib/UtilityLib.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 | Source Files
23 |
24 |
25 | Source Files
26 |
27 |
28 |
29 |
30 | Header Files
31 |
32 |
33 | Header Files
34 |
35 |
36 | Header Files
37 |
38 |
39 |
--------------------------------------------------------------------------------
/tests/UnitTest/JsonCompressTest.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 |
6 | #include "JsonHandler.h"
7 |
8 | namespace JsonCompress
9 | {
10 | class JsonCompressTest : public ::testing::Test
11 | {
12 | protected:
13 | JsonHandler m_jsonHandler {{}};
14 |
15 | protected:
16 | void SetUp() override {}
17 | void TearDown() override {}
18 |
19 | void setParseOptions(const ParseOptions& opt)
20 | {
21 | m_jsonHandler = JsonHandler(opt);
22 | }
23 | };
24 |
25 | // Test 1: Test valid JSON with default formatting options
26 | TEST_F(JsonCompressTest, CompressJson_ValidJson)
27 | {
28 | const std::string inputJson = R"({"name": "John", "age": 30})";
29 |
30 | auto result = m_jsonHandler.GetCompressedJson(inputJson);
31 |
32 | EXPECT_TRUE(result.success);
33 | EXPECT_EQ(result.error_code, -1);
34 | EXPECT_EQ(result.error_pos, -1);
35 | EXPECT_EQ(result.error_str, "");
36 | EXPECT_EQ(result.response, R"({"name":"John","age":30})");
37 | }
38 |
39 | // Test 2: Test invalid JSON input
40 | TEST_F(JsonCompressTest, CompressJson_InvalidJson)
41 | {
42 | const std::string inputJson = R"({"name": "John", "age": })"; // Invalid JSON (missing age value)
43 |
44 | auto result = m_jsonHandler.GetCompressedJson(inputJson);
45 |
46 | EXPECT_FALSE(result.success);
47 | EXPECT_NE(result.error_code, -1);
48 | EXPECT_NE(result.error_pos, -1);
49 | EXPECT_FALSE(result.error_str.empty());
50 | EXPECT_EQ(result.response, "");
51 | }
52 |
53 | // Test 3: Test valid JSON with tab indentation
54 | TEST_F(JsonCompressTest, CompressJson_ValidJson_TabIndentation)
55 | {
56 | const std::string inputJson = "{\n\t\"name\": \"John\",\n\t\"age\": 30\n}";
57 |
58 | auto result = m_jsonHandler.GetCompressedJson(inputJson);
59 |
60 | EXPECT_TRUE(result.success);
61 | EXPECT_EQ(result.error_code, -1);
62 | EXPECT_EQ(result.error_pos, -1);
63 | EXPECT_EQ(result.error_str, "");
64 | EXPECT_EQ(result.response, R"({"name":"John","age":30})");
65 | }
66 |
67 | // Test 4: Test valid JSON with Windows line endings
68 | TEST_F(JsonCompressTest, CompressJson_ValidJson_WindowsLineEndings)
69 | {
70 | const std::string inputJson = "{\r\n \"name\": \"John\",\r\n \"age\": 30}";
71 |
72 | auto result = m_jsonHandler.GetCompressedJson(inputJson);
73 |
74 | EXPECT_TRUE(result.success);
75 | EXPECT_EQ(result.error_code, -1);
76 | EXPECT_EQ(result.error_pos, -1);
77 | EXPECT_EQ(result.error_str, "");
78 | EXPECT_EQ(result.response, R"({"name":"John","age":30})");
79 | }
80 |
81 | // Test 5: Test valid JSON with no indentation (compact format)
82 | TEST_F(JsonCompressTest, CompressJson_ValidJson_NoIndentation)
83 | {
84 | std::string inputJson = R"({"name":"John","age":30})";
85 | auto result = m_jsonHandler.GetCompressedJson(inputJson);
86 |
87 | EXPECT_TRUE(result.success);
88 | EXPECT_EQ(result.error_code, -1);
89 | EXPECT_EQ(result.error_pos, -1);
90 | EXPECT_EQ(result.error_str, "");
91 | EXPECT_EQ(result.response, R"({"name":"John","age":30})");
92 | }
93 |
94 | // Test 6: Test JSON with comments ignored
95 | TEST_F(JsonCompressTest, CompressJson_IgnoreComments)
96 | {
97 | const std::string inputJson = R"({
98 | // Comment here
99 | "name": "John",
100 | "age": 30
101 | })";
102 |
103 | // Set parse options to ignore comments
104 | ParseOptions parseOptions {.bIgnoreComment = true, .bIgnoreTrailingComma = false, .bReplaceUndefined = false};
105 | setParseOptions(parseOptions);
106 |
107 | auto result = m_jsonHandler.GetCompressedJson(inputJson);
108 |
109 | EXPECT_TRUE(result.success);
110 | EXPECT_EQ(result.error_code, -1);
111 | EXPECT_EQ(result.error_pos, -1);
112 | EXPECT_EQ(result.error_str, "");
113 | EXPECT_EQ(result.response, R"({"name":"John","age":30})");
114 | }
115 |
116 | // Test 7: Test JSON with trailing commas ignored
117 | TEST_F(JsonCompressTest, CompressJson_IgnoreTrailingCommas)
118 | {
119 | const std::string inputJson = R"({
120 | "name": "John",
121 | "age": 30,
122 | })"; // Trailing comma is invalid in standard JSON
123 |
124 | // Set parse options to ignore trailing commas
125 | ParseOptions parseOptions {.bIgnoreComment = false, .bIgnoreTrailingComma = true, .bReplaceUndefined = false};
126 | setParseOptions(parseOptions);
127 |
128 | auto result = m_jsonHandler.GetCompressedJson(inputJson);
129 |
130 | EXPECT_TRUE(result.success);
131 | EXPECT_EQ(result.error_code, -1);
132 | EXPECT_EQ(result.error_pos, -1);
133 | EXPECT_EQ(result.error_str, "");
134 | EXPECT_EQ(result.response, R"({"name":"John","age":30})");
135 | }
136 |
137 | // Test 8: Test with infinity NaN inf
138 | TEST_F(JsonCompressTest, CompressJson_Infinity_NaN_Null)
139 | {
140 | std::unordered_map testData {
141 | {"{\r\n \"NaN\": NaN\r\n}", R"({"NaN":NaN})"},
142 | {"{\r\n \"Mixed\": [\r\n null,\r\n null,\r\n \"power\"\r\n ]\r\n}", R"({"Mixed":[null,null,"power"]})"},
143 | {"{\n \"Inf\": [\n -Infinity,\n Infinity,\n -Inf,\n Inf\n ]\n}", R"({"Inf":[-Infinity,Infinity,-Infinity,Infinity]})"},
144 | };
145 |
146 | for (const auto& [input, output] : testData)
147 | {
148 | auto result = m_jsonHandler.GetCompressedJson(input);
149 |
150 | EXPECT_TRUE(result.success);
151 | EXPECT_EQ(result.error_code, -1);
152 | EXPECT_EQ(result.error_pos, -1);
153 | EXPECT_EQ(result.error_str, "");
154 | EXPECT_EQ(result.response, output);
155 | }
156 | }
157 |
158 | // Test 9: Test valid JSON with unicode sequence
159 | TEST_F(JsonCompressTest, CompressJson_UnicodeSequence)
160 | {
161 | const std::string inputJson = R"(
162 | {
163 | "FreeTextInput": "\u003Cscript\u003Ealert(\u0022links\u0022);\u003C/script\u003E"
164 | })";
165 | const std::string output = R"({"FreeTextInput":""})";
166 | auto result = m_jsonHandler.GetCompressedJson(inputJson);
167 |
168 | EXPECT_TRUE(result.success);
169 | EXPECT_EQ(result.error_code, -1);
170 | EXPECT_EQ(result.error_pos, -1);
171 | EXPECT_EQ(result.error_str, "");
172 | EXPECT_EQ(result.response, output);
173 | }
174 |
175 | // Test 10: Test with numbers (with and without precision)
176 | TEST_F(JsonCompressTest, CompressJson_numbers)
177 | {
178 | std::unordered_map