From 44b26e98882edb0ad3f00e8da6adde472e345c25 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Wed, 25 Mar 2015 06:34:06 +0100 Subject: [PATCH] Initial commit --- .gitignore | 29 + LICENSE | 676 ++++++++++++++++++ NOTICE | 12 + README.md | 52 ++ api/build.gradle | 1 + api/src/main/java/jd/gui/api/API.java | 48 ++ .../api/feature/ContainerEntryGettable.java | 12 + .../jd/gui/api/feature/ContentCopyable.java | 10 + .../jd/gui/api/feature/ContentIndexable.java | 13 + .../jd/gui/api/feature/ContentSavable.java | 16 + .../jd/gui/api/feature/ContentSearchable.java | 14 + .../jd/gui/api/feature/ContentSelectable.java | 10 + .../gui/api/feature/FocusedTypeGettable.java | 10 + .../api/feature/IndexesChangeListener.java | 14 + .../gui/api/feature/LineNumberNavigable.java | 14 + .../gui/api/feature/PageChangeListener.java | 12 + .../jd/gui/api/feature/PageChangeable.java | 10 + .../java/jd/gui/api/feature/PageClosable.java | 10 + .../java/jd/gui/api/feature/PageCreator.java | 14 + .../feature/PreferencesChangeListener.java | 12 + .../jd/gui/api/feature/SourcesSavable.java | 25 + .../gui/api/feature/TreeNodeExpandable.java | 12 + .../java/jd/gui/api/feature/UriGettable.java | 12 + .../java/jd/gui/api/feature/UriOpenable.java | 42 ++ .../main/java/jd/gui/api/model/Container.java | 37 + .../main/java/jd/gui/api/model/Indexes.java | 68 ++ .../java/jd/gui/api/model/TreeNodeData.java | 18 + api/src/main/java/jd/gui/api/model/Type.java | 66 ++ .../java/jd/gui/spi/ContainerFactory.java | 20 + api/src/main/java/jd/gui/spi/FileLoader.java | 20 + api/src/main/java/jd/gui/spi/Indexer.java | 20 + .../main/java/jd/gui/spi/PanelFactory.java | 18 + .../main/java/jd/gui/spi/PasteHandler.java | 14 + .../java/jd/gui/spi/PreferencesPanel.java | 29 + api/src/main/java/jd/gui/spi/SourceSaver.java | 32 + .../main/java/jd/gui/spi/TreeNodeFactory.java | 22 + api/src/main/java/jd/gui/spi/TypeFactory.java | 20 + api/src/main/java/jd/gui/spi/UriLoader.java | 18 + app/build.gradle | 9 + app/src/main/groovy/jd/gui/App.groovy | 40 ++ app/src/main/groovy/jd/gui/Constants.groovy | 21 + .../jd/gui/controller/GoToController.groovy | 25 + .../jd/gui/controller/MainController.groovy | 530 ++++++++++++++ .../gui/controller/OpenTypeController.groovy | 238 ++++++ .../OpenTypeHierarchyController.groovy | 84 +++ .../controller/PreferencesController.groovy | 26 + .../SaveAllSourcesController.groovy | 83 +++ .../SearchInConstantPoolsController.groovy | 408 +++++++++++ .../SelectLocationController.groovy | 164 +++++ .../model/configuration/Configuration.groovy | 31 + .../container/FilteredContainerWrapper.groovy | 72 ++ .../jd/gui/model/history/History.groovy | 73 ++ .../ConfigurationPersister.groovy | 14 + .../ConfigurationPersisterService.groovy | 15 + .../ConfigurationXmlPersisterProvider.groovy | 118 +++ .../container/ContainerFactoryService.groovy | 20 + .../fileloader/FileLoaderService.groovy | 31 + .../gui/service/indexer/IndexerService.groovy | 86 +++ .../ContainerPanelFactoryProvider.groovy | 110 +++ .../mainpanel/PanelFactoryService.groovy | 32 + .../pastehandler/PasteHandlerService.groovy | 22 + .../service/platform/PlatformService.groovy | 29 + .../PreferencesPanelService.groovy | 13 + .../sourcesaver/SourceSaverService.groovy | 86 +++ .../treenode/TreeNodeFactoryService.groovy | 87 +++ .../service/type/TypeFactoryService.groovy | 93 +++ .../service/uriloader/UriLoaderService.groovy | 28 + .../main/groovy/jd/gui/util/UriUtil.groovy | 45 ++ .../groovy/jd/gui/view/GoToDescription.groovy | 39 + .../main/groovy/jd/gui/view/GoToView.groovy | 121 ++++ .../groovy/jd/gui/view/MainDescription.groovy | 291 ++++++++ .../main/groovy/jd/gui/view/MainView.groovy | 321 +++++++++ .../jd/gui/view/OpenTypeDescription.groovy | 53 ++ .../view/OpenTypeHierarchyDescription.groovy | 40 ++ .../jd/gui/view/OpenTypeHierarchyView.groovy | 313 ++++++++ .../groovy/jd/gui/view/OpenTypeView.groovy | 200 ++++++ .../jd/gui/view/PreferencesDescription.groovy | 39 + .../groovy/jd/gui/view/PreferencesView.groovy | 138 ++++ .../gui/view/SaveAllSourcesDescription.groovy | 29 + .../jd/gui/view/SaveAllSourcesView.groovy | 76 ++ .../SearchInConstantPoolsDescription.groovy | 87 +++ .../gui/view/SearchInConstantPoolsView.groovy | 300 ++++++++ .../jd/gui/view/SelectLocationView.groovy | 224 ++++++ .../gui/view/bean/OpenTypeListCellBean.groovy | 18 + .../jd/gui/view/component/IconButton.groovy | 18 + .../groovy/jd/gui/view/component/List.groovy | 95 +++ .../groovy/jd/gui/view/component/Tree.groovy | 23 + .../component/panel/MainTabbedPanel.groovy | 144 ++++ .../view/component/panel/TabbedPanel.groovy | 183 +++++ .../component/panel/TreeTabbedPanel.groovy | 216 ++++++ .../renderer/OpenTypeListCellRenderer.groovy | 96 +++ .../gui/view/renderer/TreeNodeRenderer.groovy | 79 ++ .../META-INF/services/jd.gui.spi.PanelFactory | 1 + .../main/resources/images/Icon_java_128.png | Bin 0 -> 14178 bytes .../main/resources/images/Icon_java_64.png | Bin 0 -> 5673 bytes .../main/resources/images/backward_nav.png | Bin 0 -> 469 bytes app/src/main/resources/images/close.gif | Bin 0 -> 88 bytes .../main/resources/images/close_active.gif | Bin 0 -> 88 bytes app/src/main/resources/images/forward_nav.png | Bin 0 -> 470 bytes app/src/main/resources/images/next_nav.png | Bin 0 -> 536 bytes app/src/main/resources/images/open.png | Bin 0 -> 498 bytes app/src/main/resources/images/open_type.png | Bin 0 -> 729 bytes app/src/main/resources/images/prev_nav.png | Bin 0 -> 527 bytes app/src/main/resources/images/search_src.png | Bin 0 -> 508 bytes app/src/main/resources/images/splash.gif | Bin 0 -> 11680 bytes build.gradle | 60 ++ services/build.gradle | 11 + services/lib/jd-core-0.7.1.jar | Bin 0 -> 619215 bytes .../model/container/GenericContainer.groovy | 144 ++++ .../gui/model/container/JarContainer.groovy | 22 + .../GenericContainerFactoryProvider.groovy | 25 + .../JarContainerFactoryProvider.groovy | 47 ++ .../AbstractFileLoaderProvider.groovy | 51 ++ .../fileloader/ClassFileLoaderProvider.groovy | 68 ++ .../fileloader/JarFileLoaderProvider.groovy | 18 + .../fileloader/LogFileLoaderProvider.groovy | 24 + .../fileloader/ZipFileLoaderProvider.groovy | 42 ++ .../indexer/DirectoryIndexerProvider.groovy | 45 ++ .../MetainfServiceFileIndexerProvider.groovy | 31 + .../indexer/TextFileIndexerProvider.groovy | 25 + .../indexer/XmlFileIndexerProvider.groovy | 93 +++ .../indexer/ZipFileIndexerProvider.groovy | 31 + .../pastehandler/LogPasteHandler.groovy | 23 + .../ClassFileSaverPreferencesProvider.groovy | 76 ++ .../ClassFileViewerPreferencesProvider.groovy | 70 ++ ...DirectoryIndexerPreferencesProvider.groovy | 78 ++ .../DirectorySourceSaverProvider.groovy | 59 ++ .../FileSourceSaverProvider.groovy | 34 + .../PackageSourceSaverProvider.groovy | 21 + .../ZipFileSourceSaverProvider.groovy | 50 ++ .../ClassFileTreeNodeFactoryProvider.groovy | 424 +++++++++++ .../DirectoryTreeNodeFactoryProvider.groovy | 92 +++ .../DtdFileTreeNodeFactoryProvider.groovy | 41 ++ .../FileTreeNodeFactoryProvider.groovy | 42 ++ .../HtmlFileTreeNodeFactoryProvider.groovy | 41 ++ .../JarFileTreeNodeFactoryProvider.groovy | 38 + ...vascriptFileTreeNodeFactoryProvider.groovy | 41 ++ ...ManifestFileTreeNodeFactoryProvider.groovy | 37 + ...infDirectoryTreeNodeFactoryProvider.groovy | 16 + ...fServiceFileTreeNodeFactoryProvider.groovy | 16 + .../PackageTreeNodeFactoryProvider.groovy | 61 ++ ...opertiesFileTreeNodeFactoryProvider.groovy | 41 ++ .../TextFileTreeNodeFactoryProvider.groovy | 71 ++ .../XmlFileTreeNodeFactoryProvider.groovy | 41 ++ .../ZipFileTreeNodeFactoryProvider.groovy | 57 ++ .../uriloader/FileUriLoaderProvider.groovy | 21 + .../jd/gui/util/JarContainerEntryUtil.groovy | 93 +++ .../gui/view/component/ClassFilePage.groovy | 657 +++++++++++++++++ .../gui/view/component/HyperlinkPage.groovy | 112 +++ .../jd/gui/view/component/LogPage.groovy | 133 ++++ .../view/component/ManifestFilePage.groovy | 197 +++++ .../jd/gui/view/component/SourcePage.groovy | 294 ++++++++ .../jd/gui/view/component/TextPage.groovy | 276 +++++++ .../jd/gui/view/data/TreeNodeBean.groovy | 17 + .../indexer/ClassFileIndexerProvider.java | 328 +++++++++ .../ClassFileSourceSaverProvider.java | 136 ++++ .../type/ClassFileTypeFactoryProvider.java | 428 +++++++++++ .../decompiler/ClassFileSourcePrinter.java | 232 ++++++ .../gui/util/decompiler/ContainerLoader.java | 41 ++ .../gui/util/decompiler/GuiPreferences.java | 42 ++ .../gui/util/decompiler/PlainTextPrinter.java | 307 ++++++++ .../services/jd.gui.spi.ContainerFactory | 2 + .../META-INF/services/jd.gui.spi.FileLoader | 4 + .../META-INF/services/jd.gui.spi.Indexer | 5 + .../META-INF/services/jd.gui.spi.PasteHandler | 1 + .../services/jd.gui.spi.PreferencesPanel | 3 + .../META-INF/services/jd.gui.spi.SourceSaver | 5 + .../services/jd.gui.spi.TreeNodeFactory | 17 + .../META-INF/services/jd.gui.spi.TypeFactory | 1 + .../META-INF/services/jd.gui.spi.UriLoader | 1 + .../main/resources/images/abstract_ovr.png | Bin 0 -> 187 bytes .../main/resources/images/annotation_obj.png | Bin 0 -> 3021 bytes .../src/main/resources/images/ascii_obj.png | Bin 0 -> 713 bytes .../resources/images/class_default_obj.png | Bin 0 -> 3275 bytes .../src/main/resources/images/class_obj.png | Bin 0 -> 3147 bytes .../resources/images/class_private_obj.png | Bin 0 -> 3273 bytes .../resources/images/class_protected_obj.png | Bin 0 -> 3275 bytes .../src/main/resources/images/classf_obj.png | Bin 0 -> 522 bytes .../src/main/resources/images/constr_ovr.png | Bin 0 -> 180 bytes .../src/main/resources/images/dtd_obj.gif | Bin 0 -> 351 bytes .../src/main/resources/images/enum_obj.png | Bin 0 -> 3043 bytes .../resources/images/field_default_obj.png | Bin 0 -> 218 bytes .../resources/images/field_private_obj.png | Bin 0 -> 177 bytes .../resources/images/field_protected_obj.png | Bin 0 -> 222 bytes .../resources/images/field_public_obj.png | Bin 0 -> 221 bytes .../main/resources/images/file_plain_obj.png | Bin 0 -> 317 bytes .../src/main/resources/images/final_ovr.png | Bin 0 -> 122 bytes services/src/main/resources/images/folder.gif | Bin 0 -> 219 bytes .../src/main/resources/images/folder_open.png | Bin 0 -> 310 bytes .../main/resources/images/generate_class.png | Bin 0 -> 297 bytes .../main/resources/images/generate_int.png | Bin 0 -> 2918 bytes .../src/main/resources/images/html_obj.gif | Bin 0 -> 364 bytes .../main/resources/images/int_default_obj.png | Bin 0 -> 3272 bytes .../src/main/resources/images/int_obj.png | Bin 0 -> 3254 bytes .../main/resources/images/int_private_obj.png | Bin 0 -> 3271 bytes .../resources/images/int_protected_obj.png | Bin 0 -> 3275 bytes .../src/main/resources/images/jar_obj.png | Bin 0 -> 569 bytes .../src/main/resources/images/java_obj.png | Bin 0 -> 738 bytes services/src/main/resources/images/js_obj.png | Bin 0 -> 406 bytes .../main/resources/images/manifest_obj.png | Bin 0 -> 463 bytes .../src/main/resources/images/methdef_obj.png | Bin 0 -> 290 bytes .../src/main/resources/images/methpri_obj.png | Bin 0 -> 292 bytes .../src/main/resources/images/methpro_obj.png | Bin 0 -> 299 bytes .../src/main/resources/images/methpub_obj.png | Bin 0 -> 325 bytes services/src/main/resources/images/minus.png | Bin 0 -> 294 bytes .../src/main/resources/images/package_obj.png | Bin 0 -> 263 bytes services/src/main/resources/images/plus.png | Bin 0 -> 311 bytes .../src/main/resources/images/static_ovr.png | Bin 0 -> 129 bytes .../src/main/resources/images/war_obj.gif | Bin 0 -> 1014 bytes .../src/main/resources/images/xml_obj.gif | Bin 0 -> 357 bytes .../src/main/resources/images/zip_obj.png | Bin 0 -> 509 bytes .../RSyntaxTextArea_License.txt | 24 + .../rsyntaxtextarea/themes/eclipse.xml | 79 ++ settings.gradle | 3 + src/osx/dist/JD-GUI.app/Contents/Info.plist | 76 ++ .../MacOS/universalJavaApplicationStub.sh | 299 ++++++++ .../JD-GUI.app/Contents/Resources/jd-gui.icns | Bin 0 -> 46086 bytes 217 files changed, 13300 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 NOTICE create mode 100644 README.md create mode 100644 api/build.gradle create mode 100644 api/src/main/java/jd/gui/api/API.java create mode 100644 api/src/main/java/jd/gui/api/feature/ContainerEntryGettable.java create mode 100644 api/src/main/java/jd/gui/api/feature/ContentCopyable.java create mode 100644 api/src/main/java/jd/gui/api/feature/ContentIndexable.java create mode 100644 api/src/main/java/jd/gui/api/feature/ContentSavable.java create mode 100644 api/src/main/java/jd/gui/api/feature/ContentSearchable.java create mode 100644 api/src/main/java/jd/gui/api/feature/ContentSelectable.java create mode 100644 api/src/main/java/jd/gui/api/feature/FocusedTypeGettable.java create mode 100644 api/src/main/java/jd/gui/api/feature/IndexesChangeListener.java create mode 100644 api/src/main/java/jd/gui/api/feature/LineNumberNavigable.java create mode 100644 api/src/main/java/jd/gui/api/feature/PageChangeListener.java create mode 100644 api/src/main/java/jd/gui/api/feature/PageChangeable.java create mode 100644 api/src/main/java/jd/gui/api/feature/PageClosable.java create mode 100644 api/src/main/java/jd/gui/api/feature/PageCreator.java create mode 100644 api/src/main/java/jd/gui/api/feature/PreferencesChangeListener.java create mode 100644 api/src/main/java/jd/gui/api/feature/SourcesSavable.java create mode 100644 api/src/main/java/jd/gui/api/feature/TreeNodeExpandable.java create mode 100644 api/src/main/java/jd/gui/api/feature/UriGettable.java create mode 100644 api/src/main/java/jd/gui/api/feature/UriOpenable.java create mode 100644 api/src/main/java/jd/gui/api/model/Container.java create mode 100644 api/src/main/java/jd/gui/api/model/Indexes.java create mode 100644 api/src/main/java/jd/gui/api/model/TreeNodeData.java create mode 100644 api/src/main/java/jd/gui/api/model/Type.java create mode 100644 api/src/main/java/jd/gui/spi/ContainerFactory.java create mode 100644 api/src/main/java/jd/gui/spi/FileLoader.java create mode 100644 api/src/main/java/jd/gui/spi/Indexer.java create mode 100644 api/src/main/java/jd/gui/spi/PanelFactory.java create mode 100644 api/src/main/java/jd/gui/spi/PasteHandler.java create mode 100644 api/src/main/java/jd/gui/spi/PreferencesPanel.java create mode 100644 api/src/main/java/jd/gui/spi/SourceSaver.java create mode 100644 api/src/main/java/jd/gui/spi/TreeNodeFactory.java create mode 100644 api/src/main/java/jd/gui/spi/TypeFactory.java create mode 100644 api/src/main/java/jd/gui/spi/UriLoader.java create mode 100644 app/build.gradle create mode 100644 app/src/main/groovy/jd/gui/App.groovy create mode 100644 app/src/main/groovy/jd/gui/Constants.groovy create mode 100644 app/src/main/groovy/jd/gui/controller/GoToController.groovy create mode 100644 app/src/main/groovy/jd/gui/controller/MainController.groovy create mode 100644 app/src/main/groovy/jd/gui/controller/OpenTypeController.groovy create mode 100644 app/src/main/groovy/jd/gui/controller/OpenTypeHierarchyController.groovy create mode 100644 app/src/main/groovy/jd/gui/controller/PreferencesController.groovy create mode 100644 app/src/main/groovy/jd/gui/controller/SaveAllSourcesController.groovy create mode 100644 app/src/main/groovy/jd/gui/controller/SearchInConstantPoolsController.groovy create mode 100644 app/src/main/groovy/jd/gui/controller/SelectLocationController.groovy create mode 100644 app/src/main/groovy/jd/gui/model/configuration/Configuration.groovy create mode 100644 app/src/main/groovy/jd/gui/model/container/FilteredContainerWrapper.groovy create mode 100644 app/src/main/groovy/jd/gui/model/history/History.groovy create mode 100644 app/src/main/groovy/jd/gui/service/configuration/ConfigurationPersister.groovy create mode 100644 app/src/main/groovy/jd/gui/service/configuration/ConfigurationPersisterService.groovy create mode 100644 app/src/main/groovy/jd/gui/service/configuration/ConfigurationXmlPersisterProvider.groovy create mode 100644 app/src/main/groovy/jd/gui/service/container/ContainerFactoryService.groovy create mode 100644 app/src/main/groovy/jd/gui/service/fileloader/FileLoaderService.groovy create mode 100644 app/src/main/groovy/jd/gui/service/indexer/IndexerService.groovy create mode 100644 app/src/main/groovy/jd/gui/service/mainpanel/ContainerPanelFactoryProvider.groovy create mode 100644 app/src/main/groovy/jd/gui/service/mainpanel/PanelFactoryService.groovy create mode 100644 app/src/main/groovy/jd/gui/service/pastehandler/PasteHandlerService.groovy create mode 100644 app/src/main/groovy/jd/gui/service/platform/PlatformService.groovy create mode 100644 app/src/main/groovy/jd/gui/service/preferencespanel/PreferencesPanelService.groovy create mode 100644 app/src/main/groovy/jd/gui/service/sourcesaver/SourceSaverService.groovy create mode 100644 app/src/main/groovy/jd/gui/service/treenode/TreeNodeFactoryService.groovy create mode 100644 app/src/main/groovy/jd/gui/service/type/TypeFactoryService.groovy create mode 100644 app/src/main/groovy/jd/gui/service/uriloader/UriLoaderService.groovy create mode 100644 app/src/main/groovy/jd/gui/util/UriUtil.groovy create mode 100644 app/src/main/groovy/jd/gui/view/GoToDescription.groovy create mode 100644 app/src/main/groovy/jd/gui/view/GoToView.groovy create mode 100644 app/src/main/groovy/jd/gui/view/MainDescription.groovy create mode 100644 app/src/main/groovy/jd/gui/view/MainView.groovy create mode 100644 app/src/main/groovy/jd/gui/view/OpenTypeDescription.groovy create mode 100644 app/src/main/groovy/jd/gui/view/OpenTypeHierarchyDescription.groovy create mode 100644 app/src/main/groovy/jd/gui/view/OpenTypeHierarchyView.groovy create mode 100644 app/src/main/groovy/jd/gui/view/OpenTypeView.groovy create mode 100644 app/src/main/groovy/jd/gui/view/PreferencesDescription.groovy create mode 100644 app/src/main/groovy/jd/gui/view/PreferencesView.groovy create mode 100644 app/src/main/groovy/jd/gui/view/SaveAllSourcesDescription.groovy create mode 100644 app/src/main/groovy/jd/gui/view/SaveAllSourcesView.groovy create mode 100644 app/src/main/groovy/jd/gui/view/SearchInConstantPoolsDescription.groovy create mode 100644 app/src/main/groovy/jd/gui/view/SearchInConstantPoolsView.groovy create mode 100644 app/src/main/groovy/jd/gui/view/SelectLocationView.groovy create mode 100644 app/src/main/groovy/jd/gui/view/bean/OpenTypeListCellBean.groovy create mode 100644 app/src/main/groovy/jd/gui/view/component/IconButton.groovy create mode 100644 app/src/main/groovy/jd/gui/view/component/List.groovy create mode 100644 app/src/main/groovy/jd/gui/view/component/Tree.groovy create mode 100644 app/src/main/groovy/jd/gui/view/component/panel/MainTabbedPanel.groovy create mode 100644 app/src/main/groovy/jd/gui/view/component/panel/TabbedPanel.groovy create mode 100644 app/src/main/groovy/jd/gui/view/component/panel/TreeTabbedPanel.groovy create mode 100644 app/src/main/groovy/jd/gui/view/renderer/OpenTypeListCellRenderer.groovy create mode 100644 app/src/main/groovy/jd/gui/view/renderer/TreeNodeRenderer.groovy create mode 100644 app/src/main/resources/META-INF/services/jd.gui.spi.PanelFactory create mode 100644 app/src/main/resources/images/Icon_java_128.png create mode 100644 app/src/main/resources/images/Icon_java_64.png create mode 100644 app/src/main/resources/images/backward_nav.png create mode 100644 app/src/main/resources/images/close.gif create mode 100644 app/src/main/resources/images/close_active.gif create mode 100644 app/src/main/resources/images/forward_nav.png create mode 100644 app/src/main/resources/images/next_nav.png create mode 100644 app/src/main/resources/images/open.png create mode 100644 app/src/main/resources/images/open_type.png create mode 100644 app/src/main/resources/images/prev_nav.png create mode 100644 app/src/main/resources/images/search_src.png create mode 100644 app/src/main/resources/images/splash.gif create mode 100644 build.gradle create mode 100644 services/build.gradle create mode 100644 services/lib/jd-core-0.7.1.jar create mode 100644 services/src/main/groovy/jd/gui/model/container/GenericContainer.groovy create mode 100644 services/src/main/groovy/jd/gui/model/container/JarContainer.groovy create mode 100644 services/src/main/groovy/jd/gui/service/container/GenericContainerFactoryProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/container/JarContainerFactoryProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/fileloader/AbstractFileLoaderProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/fileloader/ClassFileLoaderProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/fileloader/JarFileLoaderProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/fileloader/LogFileLoaderProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/fileloader/ZipFileLoaderProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/indexer/DirectoryIndexerProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/indexer/MetainfServiceFileIndexerProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/indexer/TextFileIndexerProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/indexer/XmlFileIndexerProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/indexer/ZipFileIndexerProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/pastehandler/LogPasteHandler.groovy create mode 100644 services/src/main/groovy/jd/gui/service/preferencespanel/ClassFileSaverPreferencesProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/preferencespanel/ClassFileViewerPreferencesProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/preferencespanel/DirectoryIndexerPreferencesProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/sourcesaver/DirectorySourceSaverProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/sourcesaver/FileSourceSaverProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/sourcesaver/PackageSourceSaverProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/sourcesaver/ZipFileSourceSaverProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/treenode/ClassFileTreeNodeFactoryProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/treenode/DirectoryTreeNodeFactoryProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/treenode/DtdFileTreeNodeFactoryProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/treenode/FileTreeNodeFactoryProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/treenode/HtmlFileTreeNodeFactoryProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/treenode/JarFileTreeNodeFactoryProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/treenode/JavascriptFileTreeNodeFactoryProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/treenode/ManifestFileTreeNodeFactoryProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/treenode/MetainfDirectoryTreeNodeFactoryProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/treenode/MetainfServiceFileTreeNodeFactoryProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/treenode/PackageTreeNodeFactoryProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/treenode/PropertiesFileTreeNodeFactoryProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/treenode/TextFileTreeNodeFactoryProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/treenode/XmlFileTreeNodeFactoryProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/treenode/ZipFileTreeNodeFactoryProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/service/uriloader/FileUriLoaderProvider.groovy create mode 100644 services/src/main/groovy/jd/gui/util/JarContainerEntryUtil.groovy create mode 100644 services/src/main/groovy/jd/gui/view/component/ClassFilePage.groovy create mode 100644 services/src/main/groovy/jd/gui/view/component/HyperlinkPage.groovy create mode 100644 services/src/main/groovy/jd/gui/view/component/LogPage.groovy create mode 100644 services/src/main/groovy/jd/gui/view/component/ManifestFilePage.groovy create mode 100644 services/src/main/groovy/jd/gui/view/component/SourcePage.groovy create mode 100644 services/src/main/groovy/jd/gui/view/component/TextPage.groovy create mode 100644 services/src/main/groovy/jd/gui/view/data/TreeNodeBean.groovy create mode 100644 services/src/main/java/jd/gui/service/indexer/ClassFileIndexerProvider.java create mode 100644 services/src/main/java/jd/gui/service/sourcesaver/ClassFileSourceSaverProvider.java create mode 100644 services/src/main/java/jd/gui/service/type/ClassFileTypeFactoryProvider.java create mode 100644 services/src/main/java/jd/gui/util/decompiler/ClassFileSourcePrinter.java create mode 100644 services/src/main/java/jd/gui/util/decompiler/ContainerLoader.java create mode 100644 services/src/main/java/jd/gui/util/decompiler/GuiPreferences.java create mode 100644 services/src/main/java/jd/gui/util/decompiler/PlainTextPrinter.java create mode 100644 services/src/main/resources/META-INF/services/jd.gui.spi.ContainerFactory create mode 100644 services/src/main/resources/META-INF/services/jd.gui.spi.FileLoader create mode 100644 services/src/main/resources/META-INF/services/jd.gui.spi.Indexer create mode 100644 services/src/main/resources/META-INF/services/jd.gui.spi.PasteHandler create mode 100644 services/src/main/resources/META-INF/services/jd.gui.spi.PreferencesPanel create mode 100644 services/src/main/resources/META-INF/services/jd.gui.spi.SourceSaver create mode 100644 services/src/main/resources/META-INF/services/jd.gui.spi.TreeNodeFactory create mode 100644 services/src/main/resources/META-INF/services/jd.gui.spi.TypeFactory create mode 100644 services/src/main/resources/META-INF/services/jd.gui.spi.UriLoader create mode 100644 services/src/main/resources/images/abstract_ovr.png create mode 100644 services/src/main/resources/images/annotation_obj.png create mode 100644 services/src/main/resources/images/ascii_obj.png create mode 100644 services/src/main/resources/images/class_default_obj.png create mode 100644 services/src/main/resources/images/class_obj.png create mode 100644 services/src/main/resources/images/class_private_obj.png create mode 100644 services/src/main/resources/images/class_protected_obj.png create mode 100644 services/src/main/resources/images/classf_obj.png create mode 100644 services/src/main/resources/images/constr_ovr.png create mode 100644 services/src/main/resources/images/dtd_obj.gif create mode 100644 services/src/main/resources/images/enum_obj.png create mode 100644 services/src/main/resources/images/field_default_obj.png create mode 100644 services/src/main/resources/images/field_private_obj.png create mode 100644 services/src/main/resources/images/field_protected_obj.png create mode 100644 services/src/main/resources/images/field_public_obj.png create mode 100644 services/src/main/resources/images/file_plain_obj.png create mode 100644 services/src/main/resources/images/final_ovr.png create mode 100644 services/src/main/resources/images/folder.gif create mode 100644 services/src/main/resources/images/folder_open.png create mode 100644 services/src/main/resources/images/generate_class.png create mode 100644 services/src/main/resources/images/generate_int.png create mode 100644 services/src/main/resources/images/html_obj.gif create mode 100644 services/src/main/resources/images/int_default_obj.png create mode 100644 services/src/main/resources/images/int_obj.png create mode 100644 services/src/main/resources/images/int_private_obj.png create mode 100644 services/src/main/resources/images/int_protected_obj.png create mode 100644 services/src/main/resources/images/jar_obj.png create mode 100644 services/src/main/resources/images/java_obj.png create mode 100644 services/src/main/resources/images/js_obj.png create mode 100644 services/src/main/resources/images/manifest_obj.png create mode 100644 services/src/main/resources/images/methdef_obj.png create mode 100644 services/src/main/resources/images/methpri_obj.png create mode 100644 services/src/main/resources/images/methpro_obj.png create mode 100644 services/src/main/resources/images/methpub_obj.png create mode 100644 services/src/main/resources/images/minus.png create mode 100644 services/src/main/resources/images/package_obj.png create mode 100644 services/src/main/resources/images/plus.png create mode 100644 services/src/main/resources/images/static_ovr.png create mode 100644 services/src/main/resources/images/war_obj.gif create mode 100644 services/src/main/resources/images/xml_obj.gif create mode 100644 services/src/main/resources/images/zip_obj.png create mode 100644 services/src/main/resources/rsyntaxtextarea/RSyntaxTextArea_License.txt create mode 100644 services/src/main/resources/rsyntaxtextarea/themes/eclipse.xml create mode 100644 settings.gradle create mode 100644 src/osx/dist/JD-GUI.app/Contents/Info.plist create mode 100644 src/osx/dist/JD-GUI.app/Contents/MacOS/universalJavaApplicationStub.sh create mode 100644 src/osx/dist/JD-GUI.app/Contents/Resources/jd-gui.icns diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..7647533e --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +# Java +*.class + +# JD-GUI +jd-gui.cfg + +# Idea +.idea/ +out/ +*.ipr +*.iml +*.iws + +# Eclipse +.settings/ +classes/ +.classpath +.project + +# Mac +.DS_Store + +# Maven +log/ +target/ + +# Gradle +.gradle/ +build/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..93d21dd3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,676 @@ + GNU GENERAL PUBLIC LICENSE + + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + JD-GUI, a standalone graphical utility that displays Java sources from + CLASS files + Copyright (C) 2008-2015 Emmanuel Dupuy + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + JD-GUI Copyright (C) 2008-2015 Emmanuel Dupuy + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/NOTICE b/NOTICE new file mode 100644 index 00000000..da9446e0 --- /dev/null +++ b/NOTICE @@ -0,0 +1,12 @@ +JD-GUI license - GPLv3 + +Libraries used: + +Groovy - Apache License 2.0 +Gradle - Apache License 2.0 +JD-Core Java Release - GPLv3 +RSyntaxTextArea - Modified BSD license + +JD-GUI OSX distribution: + +universalJavaApplicationStub - MIT License diff --git a/README.md b/README.md new file mode 100644 index 00000000..c83de7bd --- /dev/null +++ b/README.md @@ -0,0 +1,52 @@ +#JD-GUI + +JD-GUI, a standalone graphical utility that displays Java sources from CLASS files. + +![](http://jd.benow.ca/img/screenshot17.png) + +- Java Decompiler projects home page: [http://jd.benow.ca](http://jd.benow.ca) +- Java Decompiler Wikipedia page: [http://en.wikipedia.org/wiki/Java_Decompiler](http://en.wikipedia.org/wiki/Java_Decompiler) +- JD-GUI source code: [https://github.com/java-decompiler/jd-gui](https://github.com/java-decompiler/jd-gui) + +##Description +JD-GUI is a standalone graphical utility that displays Java source codes of +".class" files. You can browse the reconstructed source code with the JD-GUI +for instant access to methods and fields. + +##How to build JD-GUI ? +``` +> gradle build +``` +generate _"build/libs/jd-gui-x.y.z.jar"_ +``` +> gradle build installOsxDist +``` +generate _"build/install/jd-gui-osx/JD-GUI.app"_ + +##How to launch JD-GUI ? +- Double-click on _"jd-gui-x.y.z.jar"_ +- Double-click on _"JD-GUI"_ application under OSX +- Execute _"java -jar jd-gui-x.y.z.jar"_ or _"java -classpath jd-gui-x.y.z.jar jd.gui.App"_ + +##How to use JD-GUI ? +- Open a file with menu "File > Open File..." +- Open recent files with menu "File > Recent Files" +- Drag and drop files from your file explorer + +##How to extend JD-GUI ? +``` +> gradle idea +``` +generate Idea Intellij project +``` +> gradle eclipse +``` +generate Eclipse project +``` +> java -classpath jd-gui-x.y.z.jar;myextension1.jar;myextension2.jar jd.gui.App +``` +launch JD-GUI with your extensions + +##Uninstallation +- Delete "jd-gui-x.y.z.jar" and "jd-gui.cfg". +- Drag and drop "JD-GUI" application into the trash. diff --git a/api/build.gradle b/api/build.gradle new file mode 100644 index 00000000..bbfeb03c --- /dev/null +++ b/api/build.gradle @@ -0,0 +1 @@ +apply plugin: 'java' diff --git a/api/src/main/java/jd/gui/api/API.java b/api/src/main/java/jd/gui/api/API.java new file mode 100644 index 00000000..8c9486c8 --- /dev/null +++ b/api/src/main/java/jd/gui/api/API.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api; + +import jd.gui.api.feature.UriGettable; +import jd.gui.api.model.Container; +import jd.gui.api.model.Indexes; +import jd.gui.spi.*; + +import javax.swing.*; +import java.io.File; +import java.net.URI; +import java.nio.file.FileSystem; +import java.util.Collection; +import java.util.Map; + +public interface API { + public boolean openURI(URI uri); + + public boolean openURI(int x, int y, Collection entries, String query, String fragment); + + public void addURI(URI uri); + + public void addPanel(String title, Icon icon, String tip, T component); + + public UriLoader getUriLoader(URI uri); + + public FileLoader getFileLoader(File file); + + public ContainerFactory getContainerFactory(FileSystem fileSystem); + + public PanelFactory getMainPanelFactory(Container container); + + public TreeNodeFactory getTreeNodeFactory(Container.Entry entry); + + public TypeFactory getTypeFactory(Container.Entry entry); + + public Indexer getIndexer(Container.Entry entry); + + public SourceSaver getSourceSaver(Container.Entry entry); + + public Map getPreferences(); + + public Collection getCollectionOfIndexes(); +} diff --git a/api/src/main/java/jd/gui/api/feature/ContainerEntryGettable.java b/api/src/main/java/jd/gui/api/feature/ContainerEntryGettable.java new file mode 100644 index 00000000..422dbca2 --- /dev/null +++ b/api/src/main/java/jd/gui/api/feature/ContainerEntryGettable.java @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.feature; + +import jd.gui.api.model.Container; + +public interface ContainerEntryGettable { + public Container.Entry getEntry(); +} diff --git a/api/src/main/java/jd/gui/api/feature/ContentCopyable.java b/api/src/main/java/jd/gui/api/feature/ContentCopyable.java new file mode 100644 index 00000000..5d23ddd7 --- /dev/null +++ b/api/src/main/java/jd/gui/api/feature/ContentCopyable.java @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.feature; + +public interface ContentCopyable { + public void copy(); +} diff --git a/api/src/main/java/jd/gui/api/feature/ContentIndexable.java b/api/src/main/java/jd/gui/api/feature/ContentIndexable.java new file mode 100644 index 00000000..73595bea --- /dev/null +++ b/api/src/main/java/jd/gui/api/feature/ContentIndexable.java @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.feature; + +import jd.gui.api.API; +import jd.gui.api.model.Indexes; + +public interface ContentIndexable { + public Indexes index(API api); +} diff --git a/api/src/main/java/jd/gui/api/feature/ContentSavable.java b/api/src/main/java/jd/gui/api/feature/ContentSavable.java new file mode 100644 index 00000000..7d9dd9a6 --- /dev/null +++ b/api/src/main/java/jd/gui/api/feature/ContentSavable.java @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.feature; + +import jd.gui.api.API; + +import java.io.OutputStream; + +public interface ContentSavable { + public String getFileName(); + + public void save(API api, OutputStream os); +} diff --git a/api/src/main/java/jd/gui/api/feature/ContentSearchable.java b/api/src/main/java/jd/gui/api/feature/ContentSearchable.java new file mode 100644 index 00000000..897032d6 --- /dev/null +++ b/api/src/main/java/jd/gui/api/feature/ContentSearchable.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.feature; + +public interface ContentSearchable { + public boolean highlightText(String text, boolean caseSensitive); + + public void findNext(String text, boolean caseSensitive); + + public void findPrevious(String text, boolean caseSensitive); +} diff --git a/api/src/main/java/jd/gui/api/feature/ContentSelectable.java b/api/src/main/java/jd/gui/api/feature/ContentSelectable.java new file mode 100644 index 00000000..ef28b00b --- /dev/null +++ b/api/src/main/java/jd/gui/api/feature/ContentSelectable.java @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.feature; + +public interface ContentSelectable { + public void selectAll(); +} diff --git a/api/src/main/java/jd/gui/api/feature/FocusedTypeGettable.java b/api/src/main/java/jd/gui/api/feature/FocusedTypeGettable.java new file mode 100644 index 00000000..360498cd --- /dev/null +++ b/api/src/main/java/jd/gui/api/feature/FocusedTypeGettable.java @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.feature; + +public interface FocusedTypeGettable extends ContainerEntryGettable { + public String getFocusedTypeName(); +} diff --git a/api/src/main/java/jd/gui/api/feature/IndexesChangeListener.java b/api/src/main/java/jd/gui/api/feature/IndexesChangeListener.java new file mode 100644 index 00000000..04ac36b0 --- /dev/null +++ b/api/src/main/java/jd/gui/api/feature/IndexesChangeListener.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.feature; + +import jd.gui.api.model.Indexes; + +import java.util.Collection; + +public interface IndexesChangeListener { + void indexesChanged(Collection collectionOfIndexes); +} diff --git a/api/src/main/java/jd/gui/api/feature/LineNumberNavigable.java b/api/src/main/java/jd/gui/api/feature/LineNumberNavigable.java new file mode 100644 index 00000000..56751457 --- /dev/null +++ b/api/src/main/java/jd/gui/api/feature/LineNumberNavigable.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.feature; + +public interface LineNumberNavigable { + public int getMaximumLineNumber(); + + public void goToLineNumber(int lineNumber); + + public boolean checkLineNumber(int lineNumber); +} diff --git a/api/src/main/java/jd/gui/api/feature/PageChangeListener.java b/api/src/main/java/jd/gui/api/feature/PageChangeListener.java new file mode 100644 index 00000000..8659b187 --- /dev/null +++ b/api/src/main/java/jd/gui/api/feature/PageChangeListener.java @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.feature; + +import javax.swing.*; + +public interface PageChangeListener { + public void pageChanged(T page); +} diff --git a/api/src/main/java/jd/gui/api/feature/PageChangeable.java b/api/src/main/java/jd/gui/api/feature/PageChangeable.java new file mode 100644 index 00000000..33b364e1 --- /dev/null +++ b/api/src/main/java/jd/gui/api/feature/PageChangeable.java @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.feature; + +public interface PageChangeable { + public void addPageChangeListener(PageChangeListener listener); +} diff --git a/api/src/main/java/jd/gui/api/feature/PageClosable.java b/api/src/main/java/jd/gui/api/feature/PageClosable.java new file mode 100644 index 00000000..6181056b --- /dev/null +++ b/api/src/main/java/jd/gui/api/feature/PageClosable.java @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.feature; + +public interface PageClosable { + public boolean closePage(); +} diff --git a/api/src/main/java/jd/gui/api/feature/PageCreator.java b/api/src/main/java/jd/gui/api/feature/PageCreator.java new file mode 100644 index 00000000..7a6d80d9 --- /dev/null +++ b/api/src/main/java/jd/gui/api/feature/PageCreator.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.feature; + +import jd.gui.api.API; + +import javax.swing.*; + +public interface PageCreator { + public T createPage(API api); +} diff --git a/api/src/main/java/jd/gui/api/feature/PreferencesChangeListener.java b/api/src/main/java/jd/gui/api/feature/PreferencesChangeListener.java new file mode 100644 index 00000000..73b82da7 --- /dev/null +++ b/api/src/main/java/jd/gui/api/feature/PreferencesChangeListener.java @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.feature; + +import java.util.Map; + +public interface PreferencesChangeListener { + public void preferencesChanged(Map preferences); +} diff --git a/api/src/main/java/jd/gui/api/feature/SourcesSavable.java b/api/src/main/java/jd/gui/api/feature/SourcesSavable.java new file mode 100644 index 00000000..37c0225c --- /dev/null +++ b/api/src/main/java/jd/gui/api/feature/SourcesSavable.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.feature; + +import jd.gui.api.API; +import java.nio.file.Path; + +public interface SourcesSavable { + public String getSourceFileName(); + + public int getFileCount(); + + public void save(API api, Controller controller, Listener listener, Path path); + + public interface Controller { + public boolean isCancelled(); + }; + + public interface Listener { + public void pathSaved(Path path); + }; +} diff --git a/api/src/main/java/jd/gui/api/feature/TreeNodeExpandable.java b/api/src/main/java/jd/gui/api/feature/TreeNodeExpandable.java new file mode 100644 index 00000000..6e5f4558 --- /dev/null +++ b/api/src/main/java/jd/gui/api/feature/TreeNodeExpandable.java @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.feature; + +import jd.gui.api.API; + +public interface TreeNodeExpandable { + public void populateTreeNode(API api); +} diff --git a/api/src/main/java/jd/gui/api/feature/UriGettable.java b/api/src/main/java/jd/gui/api/feature/UriGettable.java new file mode 100644 index 00000000..10881b03 --- /dev/null +++ b/api/src/main/java/jd/gui/api/feature/UriGettable.java @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.feature; + +import java.net.URI; + +public interface UriGettable { + public URI getUri(); +} diff --git a/api/src/main/java/jd/gui/api/feature/UriOpenable.java b/api/src/main/java/jd/gui/api/feature/UriOpenable.java new file mode 100644 index 00000000..a17ce4a8 --- /dev/null +++ b/api/src/main/java/jd/gui/api/feature/UriOpenable.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.feature; + +import java.net.URI; + +/** + * uri = [scheme:][//authority][path][?query][#fragment]
+ * scheme = generic | jar | war | ear | dex | ...
+ * authority = ''
+ * path = path/to/dir/ | path/to/file
+ * query = '' | highlight=text
+ * fragment = '' | type | innertype | lineNumber=... | highlightPattern=...&highlightFlags=[drtcmfs]&highlightScope=...
+ *
+ * Examples: + *
    + *
  • file://dir1/dir2/
  • + *
  • file://dir1/dir2/file
  • + *
  • jar://dir1/dir2/
  • + *
  • jar://dir1/dir2/file
  • + * + *
  • jar://dir1/dir2/javafile
  • + *
  • jar://dir1/dir2/javafile#type
  • + *
  • jar://dir1/dir2/javafile#type-fieldName-descriptor
  • + *
  • jar://dir1/dir2/javafile#type-methodName-descriptor
  • + *
  • jar://dir1/dir2/javafile#innertype
  • + *
  • jar://dir1/dir2/javafile#innertype-fieldName-?
  • + *
  • jar://dir1/dir2/javafile#innertype-methodName-(?)?
  • + *
  • jar://dir1/dir2/javafile#innertype-fieldName-descriptor
  • + *
  • jar://dir1/dir2/javafile#innertype-methodName-descriptor
  • + * + *
  • file://dir1/dir2/file?lineNumber=number
  • + *
  • file://dir1/dir2/file?position=numeric
  • + *
  • file://dir1/dir2/file?highlightPattern=hello&highlightFlags=drtcmfs&highlightScope=internalTypeName
  • + *
+ */ +public interface UriOpenable { + public boolean openUri(URI uri); +} diff --git a/api/src/main/java/jd/gui/api/model/Container.java b/api/src/main/java/jd/gui/api/model/Container.java new file mode 100644 index 00000000..478426b1 --- /dev/null +++ b/api/src/main/java/jd/gui/api/model/Container.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.model; + +import java.io.InputStream; +import java.net.URI; +import java.util.Collection; + +public interface Container { + public String getType(); + + public Entry getRoot(); + + /** + * File or directory + */ + public interface Entry { + public Container getContainer(); + + public Entry getParent(); + + public URI getUri(); + + public String getPath(); + + public boolean isDirectory(); + + public long length(); + + public InputStream getInputStream(); + + public Collection getChildren(); + } +} diff --git a/api/src/main/java/jd/gui/api/model/Indexes.java b/api/src/main/java/jd/gui/api/model/Indexes.java new file mode 100644 index 00000000..56ac9cc1 --- /dev/null +++ b/api/src/main/java/jd/gui/api/model/Indexes.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.model; + +import java.util.Collection; +import java.util.Map; + +/** + * Whatever the language/file format (Java|Groovy|Scala/Class|DEX, Java|Javascript/Source, C#/CIL, ...), type names, + * stored in the indexes, use the JVM internal format (package separator = '/', inner class separator = '$').
+ *
+ * List of default indexes: + *
    + *
  • + * Map "strings"
    + * key: a string
    + * value: a list of entries containing the string + *
  • + *
  • + * Map "typeDeclarations"
    + * key: a type name using internal JVM internal format
    + * value: a list of entries containing the type declaration + *
  • + *
  • + * Map "constructorDeclarations"
    + * key: a type name using internal JVM internal format
    + * value: a list of entries containing the constructor declaration + *
  • + *
  • + * Map "constructorReferences"
    + * key: a type name using internal JVM internal format
    + * value: a list of entries containing the constructor reference + *
  • + *
  • + * Map "methodDeclarations"
    + * key: a method name
    + * value: a list of entries containing the method declaration + *
  • + *
  • + * Map "methodReferences"
    + * key: a method name
    + * value: a list of entries containing the method reference + *
  • + *
  • + * Map "fieldDeclarations"
    + * key: a field name
    + * value: a list of entries containing the field declaration + *
  • + *
  • + * Map "fieldReferences"
    + * key: a field name
    + * value: a list of entries containing the field reference + *
  • + *
  • + * Map "subTypeNames"
    + * key: a super type name using internal JVM internal format
    + * value: a list of sub type names using internal JVM internal format + *
  • + *
+ */ +public interface Indexes { + public void waitIndexers(); + + public Map getIndex(String name); +} diff --git a/api/src/main/java/jd/gui/api/model/TreeNodeData.java b/api/src/main/java/jd/gui/api/model/TreeNodeData.java new file mode 100644 index 00000000..ee3bb81a --- /dev/null +++ b/api/src/main/java/jd/gui/api/model/TreeNodeData.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.model; + +import javax.swing.*; + +public interface TreeNodeData { + public String getLabel(); + + public String getTip(); + + public Icon getIcon(); + + public Icon getOpenIcon(); +} \ No newline at end of file diff --git a/api/src/main/java/jd/gui/api/model/Type.java b/api/src/main/java/jd/gui/api/model/Type.java new file mode 100644 index 00000000..91e570ea --- /dev/null +++ b/api/src/main/java/jd/gui/api/model/Type.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.api.model; + +import javax.swing.*; +import java.util.Collection; + +public interface Type { + public final static int FLAG_PUBLIC = 1; + public final static int FLAG_PRIVATE = 2; + public final static int FLAG_PROTECTED = 4; + public final static int FLAG_STATIC = 8; + public final static int FLAG_FINAL = 16; + public final static int FLAG_VARARGS = 128; + public final static int FLAG_INTERFACE = 512; + public final static int FLAG_ABSTRACT = 1024; + public final static int FLAG_ANNOTATION = 8192; + public final static int FLAG_ENUM = 16384; + + public int getFlags(); + + public String getName(); + + public String getShortName(); + + public String getSuperName(); + + public String getOuterName(); + + public String getDisplayTypeName(); + + public String getDisplayInnerTypeName(); + + public String getDisplayPackageName(); + + public Icon getIcon(); + + public Collection getInnerTypes(); + + public Collection getFields(); + + public Collection getMethods(); + + public interface Field { + public int getFlags(); + + public String getName(); + + public String getDescriptor(); + + public Icon getIcon(); + } + + public interface Method { + public int getFlags(); + + public String getName(); + + public String getDescriptor(); + + public Icon getIcon(); + } +} diff --git a/api/src/main/java/jd/gui/spi/ContainerFactory.java b/api/src/main/java/jd/gui/spi/ContainerFactory.java new file mode 100644 index 00000000..d23122e5 --- /dev/null +++ b/api/src/main/java/jd/gui/spi/ContainerFactory.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.spi; + +import jd.gui.api.API; +import jd.gui.api.model.Container; + +import java.nio.file.FileSystem; +import java.nio.file.Path; + +public interface ContainerFactory { + public String getType(); + + public boolean accept(API api, FileSystem fileSystem); + + public Container make(API api, Container.Entry parentEntry, Path rootPath); +} diff --git a/api/src/main/java/jd/gui/spi/FileLoader.java b/api/src/main/java/jd/gui/spi/FileLoader.java new file mode 100644 index 00000000..69403791 --- /dev/null +++ b/api/src/main/java/jd/gui/spi/FileLoader.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.spi; + +import jd.gui.api.API; + +import java.io.File; + +public interface FileLoader { + public String[] getExtensions(); + + public String getDescription(); + + public boolean accept(API api, File file); + + public boolean load(API api, File file); +} diff --git a/api/src/main/java/jd/gui/spi/Indexer.java b/api/src/main/java/jd/gui/spi/Indexer.java new file mode 100644 index 00000000..f5ac7de9 --- /dev/null +++ b/api/src/main/java/jd/gui/spi/Indexer.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.spi; + +import jd.gui.api.API; +import jd.gui.api.model.Container; +import jd.gui.api.model.Indexes; + +import java.util.regex.Pattern; + +public interface Indexer { + public String[] getTypes(); + + public Pattern getPathPattern(); + + public void index(API api, Container.Entry entry, Indexes indexes); +} diff --git a/api/src/main/java/jd/gui/spi/PanelFactory.java b/api/src/main/java/jd/gui/spi/PanelFactory.java new file mode 100644 index 00000000..21c6c08b --- /dev/null +++ b/api/src/main/java/jd/gui/spi/PanelFactory.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.spi; + +import jd.gui.api.API; +import jd.gui.api.feature.UriGettable; +import jd.gui.api.model.Container; + +import javax.swing.JComponent; + +public interface PanelFactory { + public String[] getTypes(); + + public T make(API api, Container container); +} diff --git a/api/src/main/java/jd/gui/spi/PasteHandler.java b/api/src/main/java/jd/gui/spi/PasteHandler.java new file mode 100644 index 00000000..dfafa567 --- /dev/null +++ b/api/src/main/java/jd/gui/spi/PasteHandler.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.spi; + +import jd.gui.api.API; + +public interface PasteHandler { + public boolean accept(Object obj); + + public void paste(API api, Object obj); +} diff --git a/api/src/main/java/jd/gui/spi/PreferencesPanel.java b/api/src/main/java/jd/gui/spi/PreferencesPanel.java new file mode 100644 index 00000000..b93d5d67 --- /dev/null +++ b/api/src/main/java/jd/gui/spi/PreferencesPanel.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.spi; + +import java.awt.*; +import java.util.Map; + +public interface PreferencesPanel { + public String getPreferencesGroupTitle(); + + public String getPreferencesPanelTitle(); + + public void init(Color errorBackgroundColor); + + public void loadPreferences(Map preferences); + + public void savePreferences(Map preferences); + + public boolean arePreferencesValid(); + + public void addPreferencesChangeListener(PreferencesPanelChangeListener listener); + + public interface PreferencesPanelChangeListener { + public void preferencesPanelChanged(PreferencesPanel source); + } +} diff --git a/api/src/main/java/jd/gui/spi/SourceSaver.java b/api/src/main/java/jd/gui/spi/SourceSaver.java new file mode 100644 index 00000000..794e5f4a --- /dev/null +++ b/api/src/main/java/jd/gui/spi/SourceSaver.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.spi; + +import jd.gui.api.API; +import jd.gui.api.model.Container; + +import java.nio.file.Path; +import java.util.regex.Pattern; + +public interface SourceSaver { + public String[] getTypes(); + + public Pattern getPathPattern(); + + public String getSourcePath(Container.Entry entry); + + public int getFileCount(API api, Container.Entry entry); + + public void save(API api, Controller controller, Listener listener, Path path, Container.Entry entry); + + public interface Controller { + public boolean isCancelled(); + }; + + public interface Listener { + public void pathSaved(Path path); + }; +} diff --git a/api/src/main/java/jd/gui/spi/TreeNodeFactory.java b/api/src/main/java/jd/gui/spi/TreeNodeFactory.java new file mode 100644 index 00000000..f76c4804 --- /dev/null +++ b/api/src/main/java/jd/gui/spi/TreeNodeFactory.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.spi; + +import javax.swing.tree.DefaultMutableTreeNode; + +import jd.gui.api.API; +import jd.gui.api.feature.UriGettable; +import jd.gui.api.model.Container; + +import java.util.regex.Pattern; + +public interface TreeNodeFactory { + public String[] getTypes(); + + public Pattern getPathPattern(); + + public T make(API api, Container.Entry entry); +} diff --git a/api/src/main/java/jd/gui/spi/TypeFactory.java b/api/src/main/java/jd/gui/spi/TypeFactory.java new file mode 100644 index 00000000..f4d0d540 --- /dev/null +++ b/api/src/main/java/jd/gui/spi/TypeFactory.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.spi; + +import jd.gui.api.API; +import jd.gui.api.model.Container; +import jd.gui.api.model.Type; + +import java.util.regex.Pattern; + +public interface TypeFactory { + public String[] getTypes(); + + public Pattern getPathPattern(); + + public Type make(API api, Container.Entry entry, String fragment); +} diff --git a/api/src/main/java/jd/gui/spi/UriLoader.java b/api/src/main/java/jd/gui/spi/UriLoader.java new file mode 100644 index 00000000..3bf680d4 --- /dev/null +++ b/api/src/main/java/jd/gui/spi/UriLoader.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.spi; + +import jd.gui.api.API; + +import java.net.URI; + +public interface UriLoader { + public String[] getSchemes(); + + public boolean accept(API api, URI uri); + + public boolean load(API api, URI uri); +} diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 00000000..1bdd46c0 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,9 @@ +apply plugin: 'groovy' + +dependencies { + compile 'org.codehaus.groovy:groovy:2.4.0' + compile 'org.codehaus.groovy:groovy-swing:2.4.0' + compile 'org.codehaus.groovy:groovy-xml:2.4.0' + compile project(':api') + runtime project(':services') +} diff --git a/app/src/main/groovy/jd/gui/App.groovy b/app/src/main/groovy/jd/gui/App.groovy new file mode 100644 index 00000000..b310300e --- /dev/null +++ b/app/src/main/groovy/jd/gui/App.groovy @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui + +import groovy.swing.SwingBuilder +import jd.gui.service.configuration.ConfigurationPersisterService + +import javax.swing.JOptionPane + +import jd.gui.controller.MainController + +class App { + + static void main(String[] args) { + if (args.contains("-h")) { + JOptionPane.showMessageDialog(null, """Usage: jd-gui [option] [input-file] ... + +Option: + -h\tshow this help message and exit""", Constants.APP_NAME) + } else { + // Load preferences + def persister = ConfigurationPersisterService.instance.get() + def configuration = persister.load() + addShutdownHook { persister.save(configuration) } + + // Create SwingBuilder, set look and feel + def swing = new SwingBuilder() + swing.lookAndFeel(configuration.lookAndFeel) + + // Create main controller ans show main frame + new MainController(swing, configuration).with { + show() + openFiles(args.collect { new File(it) }) + } + } + } +} diff --git a/app/src/main/groovy/jd/gui/Constants.groovy b/app/src/main/groovy/jd/gui/Constants.groovy new file mode 100644 index 00000000..680b5c08 --- /dev/null +++ b/app/src/main/groovy/jd/gui/Constants.groovy @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui + +class Constants { + final static String APP_NAME = "JD-GUI" + + final static int DEFAULT_WIDTH = 600 + final static int DEFAULT_HEIGHT = 400 + + final static int MINIMAL_WIDTH = 500 + final static int MINIMAL_HEIGHT = 160 + + final static String CONFIG_FILENAME = "jd-gui.cfg" + + final static int MAX_RECENT_FILES = 10 + final static int RECENT_FILE_MAX_LENGTH = 200 +} diff --git a/app/src/main/groovy/jd/gui/controller/GoToController.groovy b/app/src/main/groovy/jd/gui/controller/GoToController.groovy new file mode 100644 index 00000000..017f6d5a --- /dev/null +++ b/app/src/main/groovy/jd/gui/controller/GoToController.groovy @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.controller + +import groovy.swing.SwingBuilder +import jd.gui.api.feature.LineNumberNavigable +import jd.gui.model.configuration.Configuration +import jd.gui.view.GoToView + +class GoToController { + GoToView goToView + + GoToController(SwingBuilder swing, Configuration configuration) { + // Create UI + goToView = new GoToView(swing, configuration) + } + + void show(LineNumberNavigable navigator, Closure okClosure) { + // Show + goToView.show(navigator, okClosure) + } +} diff --git a/app/src/main/groovy/jd/gui/controller/MainController.groovy b/app/src/main/groovy/jd/gui/controller/MainController.groovy new file mode 100644 index 00000000..d5775e90 --- /dev/null +++ b/app/src/main/groovy/jd/gui/controller/MainController.groovy @@ -0,0 +1,530 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.controller + +import groovy.swing.SwingBuilder +import groovy.transform.CompileStatic +import jd.gui.api.API +import jd.gui.api.feature.ContentCopyable +import jd.gui.api.feature.ContentIndexable +import jd.gui.api.feature.ContentSavable +import jd.gui.api.feature.ContentSearchable +import jd.gui.api.feature.FocusedTypeGettable +import jd.gui.api.feature.IndexesChangeListener +import jd.gui.api.feature.LineNumberNavigable +import jd.gui.api.feature.ContentSelectable +import jd.gui.api.feature.PreferencesChangeListener +import jd.gui.api.feature.SourcesSavable +import jd.gui.api.feature.UriGettable +import jd.gui.api.model.Container +import jd.gui.api.model.Indexes +import jd.gui.model.history.History +import jd.gui.service.container.ContainerFactoryService +import jd.gui.service.fileloader.FileLoaderService +import jd.gui.service.indexer.IndexerService +import jd.gui.service.mainpanel.PanelFactoryService +import jd.gui.service.pastehandler.PasteHandlerService +import jd.gui.service.preferencespanel.PreferencesPanelService +import jd.gui.service.sourcesaver.SourceSaverService +import jd.gui.service.treenode.TreeNodeFactoryService +import jd.gui.service.type.TypeFactoryService +import jd.gui.service.uriloader.UriLoaderService +import jd.gui.spi.ContainerFactory +import jd.gui.spi.FileLoader +import jd.gui.spi.Indexer +import jd.gui.spi.PanelFactory +import jd.gui.spi.SourceSaver +import jd.gui.spi.TreeNodeFactory +import jd.gui.spi.TypeFactory +import jd.gui.spi.UriLoader +import jd.gui.util.UriUtil + +import javax.swing.Icon +import javax.swing.JComponent +import javax.swing.JFileChooser +import javax.swing.JLayer +import javax.swing.TransferHandler + +import jd.gui.model.configuration.Configuration +import jd.gui.view.MainView + +import javax.swing.filechooser.FileNameExtensionFilter +import javax.swing.filechooser.FileSystemView +import java.awt.Desktop +import java.awt.EventDispatchThread +import java.awt.Frame +import java.awt.Point +import java.awt.Toolkit +import java.awt.WaitDispatchSupport +import java.awt.datatransfer.DataFlavor +import java.awt.event.ComponentAdapter +import java.awt.event.ComponentEvent +import java.util.concurrent.Callable +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors + +import java.nio.file.FileSystem + +class MainController implements API { + SwingBuilder swing + Configuration configuration + MainView mainView + + GoToController goToController + OpenTypeController openTypeController + OpenTypeHierarchyController openTypeHierarchyController + PreferencesController preferencesController + SearchInConstantPoolsController searchInConstantPoolsController + SaveAllSourcesController saveAllSourcesController + SelectLocationController selectLocationController + + History history = new History() + JComponent currentPage = null + ExecutorService executor + Collection containerChangeListeners = [] + + MainController(SwingBuilder swing, Configuration configuration) { + this.swing = swing + this.configuration = configuration + // Create main frame + mainView = new MainView( + swing, + configuration, + history, + { panelClosed() }, // panelClosedClosure + { page -> onCurrentPageChanged(page) }, // currentPageChangedClosure + { file -> openFiles([file]) }, // openFilesClosure + { onFindCriteriaChanged() } // findCriteriaChangedClosure + ) + } + + // --- Show GUI --- // + void show() { + // Show main frame + mainView.show( + configuration.mainWindowLocation, + configuration.mainWindowSize, + configuration.mainWindowMaximize) + + mainView.updateRecentFilesMenu(configuration.recentFiles) + + swing.doLater { + // Setup closures + openAction.closure = { onOpen() } + closeAction.closure = { onClose() } + saveAction.closure = { onSaveSource() } + saveAllSourcesAction.closure = { onSaveAllSources() } + copyAction.closure = { onCopy() } + pasteAction.closure = { onPaste() } + selectAllAction.closure = { onSelectAll() } + findAction.closure = { onFind() } + findNextAction.closure = { onFindNext() } + findPreviousAction.closure = { onFindPrevious() } + findCaseSensitiveAction.closure = { onFindCriteriaChanged() } + openTypeAction.closure = { onOpenType() } + openTypeHierarchyAction.closure = { onOpenTypeHierarchy() } + goToAction.closure = { onGoTo() } + backwardAction.closure = { openURI(history.backward()) } + forwardAction.closure = { openURI(history.forward()) } + searchAction.closure = { onSearch() } + wikipediaAction.closure = { onWikipedia() } + preferencesAction.closure = { onPreferences() } + // Add listeners + mainFrame.addComponentListener(new MainFrameListener(configuration)) + // Set drop files transfer handler + mainFrame.setTransferHandler(new FilesTransferHandler()) + // Create executor + executor = Executors.newSingleThreadExecutor() + // Background initializations + executor.execute(new Runnable() { + void run() { + // Background controller creation + goToController = new GoToController(swing, configuration) + containerChangeListeners.add(openTypeController = new OpenTypeController(swing, configuration, MainController.this)) + containerChangeListeners.add(openTypeHierarchyController = new OpenTypeHierarchyController(swing, configuration, MainController.this)) + preferencesController = new PreferencesController(swing, configuration, MainController.this, PreferencesPanelService.instance.providers) + containerChangeListeners.add(searchInConstantPoolsController = new SearchInConstantPoolsController(swing, configuration, MainController.this)) + saveAllSourcesController = new SaveAllSourcesController(swing, configuration, MainController.this) + selectLocationController = new SelectLocationController(swing, configuration, MainController.this) + // Background service initialization + ContainerFactoryService.instance + FileLoaderService.instance + IndexerService.instance + PasteHandlerService.instance + PreferencesPanelService.instance + TreeNodeFactoryService.instance + TypeFactoryService.instance + UriLoaderService.instance + // Background class loading + new JFileChooser().addChoosableFileFilter(new FileNameExtensionFilter('', 'dummy')) + new WaitDispatchSupport(new EventDispatchThread(null, 'dummy', null), null) + FileSystemView.getFileSystemView().isFileSystemRoot(new File('dummy')) + new JLayer() + new JComponent.KeyboardState() + new JComponent.IntVector() + } + }) + } + } + + // --- Actions --- // + void onOpen() { + mainView.createOpenFileChooser().with { + addFileFilters(FileLoaderService.instance.mapProviders) + currentDirectory = configuration.configRecentLoadDirectory + show({ openFiles([ selectedFile ]) }) + configuration.configRecentLoadDirectory = currentDirectory + } + } + + void onClose() { + mainView.closeCurrentTab() + } + + void onSaveSource() { + if (currentPage instanceof ContentSavable) { + mainView.createSaveFileChooser().with { + selectedFile = new File(configuration.configRecentSaveDirectory, currentPage.fileName) + show({ file -> file.withOutputStream { os -> currentPage.save(this, os) } }) + configuration.configRecentSaveDirectory = currentDirectory + } + } + } + + void onSaveAllSources() { + if (! saveAllSourcesController.isActivated()) { + def currentPanel = mainView.selectedMainPanel + + if (currentPanel instanceof SourcesSavable) { + mainView.createSaveFileChooser().with { + selectedFile = new File(configuration.configRecentSaveDirectory, currentPanel.sourceFileName) + show({ file -> saveAllSourcesController.show(executor, currentPanel, file) }) + configuration.configRecentSaveDirectory = currentDirectory + } + } + } + } + + void onCopy() { + if (currentPage instanceof ContentCopyable) { + currentPage.copy() + } + } + + void onPaste() { + try { + def transferable = Toolkit.defaultToolkit.systemClipboard.getContents(null) + + if (transferable?.isDataFlavorSupported(DataFlavor.stringFlavor)) { + def obj = transferable.getTransferData(DataFlavor.stringFlavor) + PasteHandlerService.instance.get(obj)?.paste(this, obj) + } + } catch (Exception ignore) { + } + } + + void onSelectAll() { + if (currentPage instanceof ContentSelectable) { + currentPage.selectAll() + } + } + + void onFind() { + if (currentPage instanceof ContentSearchable) { + mainView.showFindPanel() + } + } + + void onFindCriteriaChanged() { + if (currentPage instanceof ContentSearchable) { + mainView.setFindBackgroundColor(currentPage.highlightText(mainView.findText, mainView.findCaseSensitive)) + } + } + + void onFindNext() { + if (currentPage instanceof ContentSearchable) { + currentPage.findNext(mainView.findText, mainView.findCaseSensitive) + } + } + + void onOpenType() { + openTypeController.show(collectionOfIndexes, { uri -> openURI(uri) }) + } + + void onOpenTypeHierarchy() { + if (currentPage instanceof FocusedTypeGettable) { + openTypeHierarchyController.show(collectionOfIndexes, currentPage.entry, currentPage.focusedTypeName, { uri -> openURI(uri) }) + } + } + + void onGoTo() { + if (currentPage instanceof LineNumberNavigable) { + goToController.show(currentPage, { int lineNumber -> currentPage.goToLineNumber(lineNumber) }) + } + } + + void onSearch() { + searchInConstantPoolsController.show(collectionOfIndexes, { uri -> openURI(uri) }) + } + + void onFindPrevious() { + if (currentPage instanceof ContentSearchable) { + currentPage.findPrevious(mainView.findText, mainView.findCaseSensitive) + } + } + + void onWikipedia() { + if (Desktop.isDesktopSupported()) { + def desktop = Desktop.desktop + if (desktop.isSupported(Desktop.Action.BROWSE)) { + desktop.browse(URI.create('http://en.wikipedia.org/wiki/Java_Decompiler')) + } + } + } + + void onPreferences() { + preferencesController.show({ checkPreferencesChange(currentPage) }) + } + + void onCurrentPageChanged(JComponent page) { + currentPage = page + checkIndexesChange(page) + checkPreferencesChange(page) + } + + void checkIndexesChange(JComponent page) { + if (page instanceof IndexesChangeListener) { + def collectionOfIndexes = getCollectionOfIndexes() + def currentHashcode = Integer.valueOf(collectionOfIndexes.hashCode()) + def lastHashcode = page.getClientProperty('collectionOfIndexes-stamp') + + if (!currentHashcode.equals(lastHashcode)) { + page.indexesChanged(collectionOfIndexes) + page.putClientProperty('collectionOfIndexes-stamp', currentHashcode) + } + } + } + + void checkPreferencesChange(JComponent page) { + if (page instanceof PreferencesChangeListener) { + def preferences = configuration.preferences + def currentHashcode = Integer.valueOf(preferences.hashCode()) + def lastHashcode = page.getClientProperty('preferences-stamp') + + if (!currentHashcode.equals(lastHashcode)) { + page.preferencesChanged(preferences) + page.putClientProperty('preferences-stamp', currentHashcode) + } + } + } + + // --- Operations --- // + void openFiles(List files) { + def errors = [] + + for (def file : files) { + // Check input file + if (file.exists()) { + FileLoader loader = getFileLoader(file) + if (! loader?.accept(this, file)) { + errors << "Invalid input fileloader: '$file.absolutePath'" + } + } else { + errors << "File not found: '$file.absolutePath'" + } + } + + if (errors) { + String messages = '' + + errors.eachWithIndex { message, index -> + if (index == 0) { + messages += message + } else if (index < 20) { + messages += "\n$message" + } else if (index == 20) { + messages += '\n...' + } + } + + mainView.showErrorDialog(messages) + } else { + for (def file : files) { + if (openURI(file.toURI())) { + configuration.addRecentFile(file) + mainView.updateRecentFilesMenu(configuration.recentFiles) + } + } + } + } + + // --- Drop files transfer handler --- // + class FilesTransferHandler extends TransferHandler { + boolean canImport(TransferHandler.TransferSupport info) { + return info.isDataFlavorSupported(DataFlavor.javaFileListFlavor) + } + + boolean importData(TransferHandler.TransferSupport info) { + if (info.isDrop() && info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { + try { + openFiles(info.transferable.getTransferData(DataFlavor.javaFileListFlavor)) + return true + } catch (Exception ignore) { + } + } + return false + } + } + + // --- ComponentListener --- // + class MainFrameListener extends ComponentAdapter { + Configuration configuration + + MainFrameListener(Configuration configuration) { + this.configuration = configuration + } + + void componentMoved(ComponentEvent e) { + def f = e.source + + if ((f.extendedState & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH) { + configuration.mainWindowMaximize = true + } else { + configuration.mainWindowLocation = f.location + configuration.mainWindowMaximize = false + } + } + + void componentResized(ComponentEvent e) { + def f = e.source + + if ((f.extendedState & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH) { + configuration.mainWindowMaximize = true + } else { + configuration.mainWindowSize = f.size + configuration.mainWindowMaximize = false + } + } + } + + protected void panelClosed() { + swing.doLater { + // Fire 'indexesChanged' event + def collectionOfIndexes = getCollectionOfIndexes() + for (def listener : containerChangeListeners) { + listener.indexesChanged(collectionOfIndexes) + } + if (currentPage instanceof IndexesChangeListener) { + currentPage.indexesChanged(collectionOfIndexes) + } + } + } + + // --- API --- // + boolean openURI(URI uri) { + if (uri) { + boolean success = mainView.openUri(uri) || getUriLoader(uri)?.load(this, uri) + if (success) { + swing.doLater { + addURI(uri) + closeAction.enabled = true + openTypeAction.enabled = true + } + } + return success + } + return false + } + + boolean openURI(int x, int y, Collection entries, String query, String fragment) { + if (entries) { + if (entries.size() == 1) { + // Open the single entry uri + def entry = entries.iterator().next() + return openURI(UriUtil.createURI(this, collectionOfIndexes, entry, query, fragment)) + } else { + // Multiple entries -> Open a "Select location" popup + def collectionOfIndexes = getCollectionOfIndexes() + selectLocationController.show( + new Point(x+(16+2) as int, y+2 as int), + entries, + { entry -> openURI(UriUtil.createURI(this, collectionOfIndexes, entry, query, fragment)) }, // entry selected closure + { }) // popup close closure + return true + } + } + + return false + } + + void addURI(URI uri) { + history.add(uri) + mainView.updateHistoryActions() + } + + public void addPanel(String title, Icon icon, String tip, T component) { + mainView.addMainPanel(title, icon, tip, component) + + if (component instanceof ContentIndexable) { + def futureIndexes = executor.submit(new Callable() { + Indexes call() throws Exception { + return component.index(MainController.this) + } + }) + def indexes = new Indexes() { + void waitIndexers() { futureIndexes.get() } + + Map getIndex(String name) { futureIndexes.get().getIndex(name) } + } + + component.putClientProperty('indexes', indexes) + + swing.doLater { + // Fire 'indexesChanged' event + def collectionOfIndexes = getCollectionOfIndexes() + for (def listener : containerChangeListeners) { + listener.indexesChanged(collectionOfIndexes) + } + if (currentPage instanceof IndexesChangeListener) { + currentPage.indexesChanged(collectionOfIndexes) + } + } + } + + checkIndexesChange(currentPage) + } + + @CompileStatic + FileLoader getFileLoader(File file) { FileLoaderService.instance.get(this, file) } + + @CompileStatic + UriLoader getUriLoader(URI uri) { UriLoaderService.instance.get(this, uri) } + + @CompileStatic + PanelFactory getMainPanelFactory(Container container) { PanelFactoryService.instance.get(container) } + + @CompileStatic + ContainerFactory getContainerFactory(FileSystem fileSystem) { ContainerFactoryService.instance.get(this, fileSystem) } + + @CompileStatic + TreeNodeFactory getTreeNodeFactory(Container.Entry entry) { TreeNodeFactoryService.instance.get(entry) } + + @CompileStatic + TypeFactory getTypeFactory(Container.Entry entry) { TypeFactoryService.instance.get(entry) } + + @CompileStatic + Indexer getIndexer(Container.Entry entry) { IndexerService.instance.get(entry) } + + @CompileStatic + SourceSaver getSourceSaver(Container.Entry entry) { SourceSaverService.instance.get(entry) } + + @CompileStatic + Map getPreferences() { configuration.preferences } + + Collection getCollectionOfIndexes() { + mainView.mainPanels.collect { it.getClientProperty('indexes') }.grep { it != null } + } +} diff --git a/app/src/main/groovy/jd/gui/controller/OpenTypeController.groovy b/app/src/main/groovy/jd/gui/controller/OpenTypeController.groovy new file mode 100644 index 00000000..bc2faefc --- /dev/null +++ b/app/src/main/groovy/jd/gui/controller/OpenTypeController.groovy @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.controller + +import groovy.swing.SwingBuilder +import groovy.transform.CompileStatic +import jd.gui.api.API +import jd.gui.api.feature.IndexesChangeListener +import jd.gui.api.model.Container +import jd.gui.api.model.Indexes +import jd.gui.model.configuration.Configuration +import jd.gui.util.UriUtil +import jd.gui.view.OpenTypeView + +import java.awt.Cursor +import java.awt.Point +import java.util.regex.Pattern + +class OpenTypeController implements IndexesChangeListener { + static final int CACHE_MAX_ENTRIES = 5*20 + + API api + OpenTypeView openTypeView + SelectLocationController selectLocationController + Collection collectionOfIndexes + Closure openClosure + long indexesHashCode = 0L + Map>> cache + + OpenTypeController(SwingBuilder swing, Configuration configuration, API api) { + this.api = api + // Create UI + openTypeView = new OpenTypeView( + swing, configuration, api, + { newPattern -> updateList(newPattern) }, // onPatternChangedClosure + { leftBottom, entries, tn -> onTypeSelected(leftBottom, entries, tn) }, // onTypeSelectedClosure + ) + selectLocationController = new SelectLocationController(swing, configuration, api) + // Create result cache + cache = new LinkedHashMap>(CACHE_MAX_ENTRIES*3/2, 0.7f, true) { + protected boolean removeEldestEntry(Map.Entry> eldest) { + return size() > CACHE_MAX_ENTRIES + } + } + } + + void show(Collection collectionOfIndexes, Closure openClosure) { + // Init attributes + this.collectionOfIndexes = collectionOfIndexes + this.openClosure = openClosure + // Refresh view + long hashCode = collectionOfIndexes.hashCode() + if (hashCode != indexesHashCode) { + // List of indexes has changed -> Refresh result list + updateList(openTypeView.pattern) + indexesHashCode = hashCode + } + // Show + openTypeView.show() + } + + protected void updateList(String pattern) { + int patternLength = pattern.length() + Map> result + + if (patternLength == 0) { + result = Collections.emptyMap() + } else { + def regExpPattern = createRegExpPattern(pattern) + + result = new HashMap>().withDefault { new HashSet() } + + for (def indexes : collectionOfIndexes) { + String key = String.valueOf(indexes.hashCode()) + '***' + pattern + def matchingEntries = cache.get(key) + + if (matchingEntries) { + // Merge 'result' and 'matchingEntries' + for (def mapEntry : matchingEntries.entrySet()) { + result.get(mapEntry.key).addAll(mapEntry.value) + } + } else { + // Waiting the end of indexation... + openTypeView.swing.openTypeDialog.rootPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)) + def index = indexes.getIndex('typeDeclarations') + openTypeView.swing.openTypeDialog.rootPane.setCursor(Cursor.getDefaultCursor()) + + if (index) { + matchingEntries = new HashMap>().withDefault { new HashSet() } + + // Filter + if (patternLength == 1) { + match(pattern.charAt(0), index, matchingEntries) + } else { + def lastKey = key.substring(0, patternLength-1) + def lastResult = cache.get(lastKey) + if (lastResult) { + match(regExpPattern, lastResult, matchingEntries) + } else { + match(regExpPattern, index, matchingEntries) + } + } + + // Store 'matchingEntries' + cache.put(key, matchingEntries) + // Merge 'result' and 'matchingEntries' + for (def mapEntry : matchingEntries.entrySet()) { + result.get(mapEntry.key).addAll(mapEntry.value) + } + } + } + } + } + + // Display + openTypeView.updateList(result) + } + + @CompileStatic + protected static void match(char c, Map> index, Map> result) { + // Filter + if (Character.isLowerCase(c)) { + char upperCase = Character.toUpperCase(c) + + for (def mapEntry : index.entrySet()) { + def typeName = mapEntry.key + def entries = mapEntry.value + // Search last package separator + int lastPackageSeparatorIndex = typeName.lastIndexOf('/') + 1 + int lastTypeNameSeparatorIndex = typeName.lastIndexOf('$') + 1 + int lastIndex = Math.max(lastPackageSeparatorIndex, lastTypeNameSeparatorIndex) + + if (lastIndex < typeName.length()) { + char first = typeName.charAt(lastIndex) + + if ((first == c) || (first == upperCase)) { + result[typeName].addAll(entries) + } + } + } + } else { + for (def mapEntry : index.entrySet()) { + def typeName = mapEntry.key + def entries = mapEntry.value + // Search last package separator + int lastPackageSeparatorIndex = typeName.lastIndexOf('/') + 1 + int lastTypeNameSeparatorIndex = typeName.lastIndexOf('$') + 1 + int lastIndex = Math.max(lastPackageSeparatorIndex, lastTypeNameSeparatorIndex) + + if ((lastIndex < typeName.length()) && (typeName.charAt(lastIndex) == c)) { + result[typeName].addAll(entries) + } + } + } + } + + /** + * Create a regular expression to match package, type and inner type name. + * + * Rules: + * '*' matches 0 ou N characters + * '?' matches 1 character + * lower case matches insensitive case + * upper case matches upper case + */ + @CompileStatic + protected static Pattern createRegExpPattern(String pattern) { + // Create regular expression + int patternLength = pattern.length() + def sbPattern = new StringBuffer(patternLength * 4) + + for (int i=0; i 1) { + sbPattern.append('.*') + } + sbPattern.append(c) + } else if (Character.isLowerCase(c)) { + sbPattern.append('[').append(c).append(Character.toUpperCase(c)).append(']') + } else if (c == '*') { + sbPattern.append('.*') + } else if (c == '?') { + sbPattern.append('.') + } else { + sbPattern.append(c) + } + } + + sbPattern.append('.*') + + return Pattern.compile(sbPattern.toString()) + } + + @CompileStatic + protected static void match(Pattern regExpPattern, Map> index, Map> result) { + for (def mapEntry : index.entrySet()) { + def typeName = mapEntry.key + def entries = mapEntry.value + // Search last package separator + int lastPackageSeparatorIndex = typeName.lastIndexOf('/') + 1 + int lastTypeNameSeparatorIndex = typeName.lastIndexOf('$') + 1 + int lastIndex = Math.max(lastPackageSeparatorIndex, lastTypeNameSeparatorIndex) + + if (regExpPattern.matcher(typeName.substring(lastIndex)).matches()) { + result[typeName].addAll(entries) + } + } + } + + protected void onTypeSelected(Point leftBottom, Collection entries, String typeName) { + if (entries.size() == 1) { + // Open the single entry uri + openClosure(UriUtil.createURI(api, collectionOfIndexes, entries.iterator().next(), null, typeName)) + } else { + // Multiple entries -> Open a "Select location" popup + selectLocationController.show( + new Point(leftBottom.x+(16+2) as int, leftBottom.y+2 as int), + entries, + { entry -> openClosure(UriUtil.createURI(api, collectionOfIndexes, entry, null, typeName)) }, // entry selected closure + { openTypeView.focus() }) // popup close closure + } + } + + // --- IndexesChangeListener --- // + void indexesChanged(Collection collectionOfIndexes) { + if (openTypeView.isVisible()) { + // Update the list of containers + this.collectionOfIndexes = collectionOfIndexes + // And refresh + updateList(openTypeView.pattern) + } + } +} diff --git a/app/src/main/groovy/jd/gui/controller/OpenTypeHierarchyController.groovy b/app/src/main/groovy/jd/gui/controller/OpenTypeHierarchyController.groovy new file mode 100644 index 00000000..ab1e20e6 --- /dev/null +++ b/app/src/main/groovy/jd/gui/controller/OpenTypeHierarchyController.groovy @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.controller + +import groovy.swing.SwingBuilder +import jd.gui.api.API +import jd.gui.api.feature.IndexesChangeListener +import jd.gui.api.model.Container +import jd.gui.api.model.Indexes +import jd.gui.model.configuration.Configuration +import jd.gui.util.UriUtil +import jd.gui.view.OpenTypeHierarchyView + +import java.awt.Cursor +import java.awt.Point + +class OpenTypeHierarchyController implements IndexesChangeListener { + API api + OpenTypeHierarchyView openTypeHierarchyView + SelectLocationController selectLocationController + Collection collectionOfIndexes + Closure openClosure + + OpenTypeHierarchyController(SwingBuilder swing, Configuration configuration, API api) { + this.api = api + // Create UI + openTypeHierarchyView = new OpenTypeHierarchyView( + swing, configuration, api, + { leftBottom, entries, tn -> onTypeSelected(leftBottom, entries, tn) }, // onTypeSelectedClosure + { parentTypeName -> getSubTypeNames(parentTypeName) }, // getSubTypeNamesClosure + { childTypeName -> getEntries(childTypeName) } // getEntriesClosure + ) + selectLocationController = new SelectLocationController(swing, configuration, api) + } + + void show(Collection collectionOfIndexes, Container.Entry entry, String typeName, Closure openClosure) { + // Init attributes + this.collectionOfIndexes = collectionOfIndexes + this.openClosure = openClosure + // Waiting the end of indexation... + openTypeHierarchyView.swing.mainFrame.rootPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)) + for (def indexes : collectionOfIndexes) { indexes.waitIndexers() } + openTypeHierarchyView.swing.mainFrame.rootPane.setCursor(Cursor.getDefaultCursor()) + + openTypeHierarchyView.updateTree(entry, typeName) + // Show + openTypeHierarchyView.show() + } + + protected List getSubTypeNames(String typeName) { + return collectionOfIndexes.collect{ it.getIndex('subTypeNames').get(typeName) }.grep{ it!=null }.flatten() + } + + protected List getEntries(String typeName) { + return collectionOfIndexes.collect{ it.getIndex('typeDeclarations').get(typeName) }.grep{ it!=null }.flatten() + } + + protected void onTypeSelected(Point leftBottom, Collection entries, String typeName) { + if (entries.size() == 1) { + // Open the single entry uri + openClosure(UriUtil.createURI(api, collectionOfIndexes, entries.iterator().next(), null, typeName)) + } else { + // Multiple entries -> Open a "Select location" popup + selectLocationController.show( + new Point(leftBottom.x+(16+2) as int, leftBottom.y+2 as int), + entries, + { entry -> openClosure(UriUtil.createURI(api, collectionOfIndexes, entry, null, typeName)) }, // entry selected + { openTypeHierarchyView.focus() }) // popup closeClosure + } + } + + // --- IndexesChangeListener --- // + void indexesChanged(Collection collectionOfIndexes) { + if (openTypeHierarchyView.isVisible()) { + // Update the list of containers + this.collectionOfIndexes = collectionOfIndexes + // And refresh + openTypeHierarchyView.updateTree(openTypeHierarchyView.entry, openTypeHierarchyView.typeName) + } + } +} diff --git a/app/src/main/groovy/jd/gui/controller/PreferencesController.groovy b/app/src/main/groovy/jd/gui/controller/PreferencesController.groovy new file mode 100644 index 00000000..a1ec2c6b --- /dev/null +++ b/app/src/main/groovy/jd/gui/controller/PreferencesController.groovy @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.controller + +import groovy.swing.SwingBuilder +import jd.gui.api.API +import jd.gui.model.configuration.Configuration +import jd.gui.spi.PreferencesPanel +import jd.gui.view.PreferencesView + +class PreferencesController { + PreferencesView preferencesView + + PreferencesController(SwingBuilder swing, Configuration configuration, API api, List panels) { + // Create UI + preferencesView = new PreferencesView(swing, configuration, panels) + } + + void show(Closure okClosure) { + // Show + preferencesView.show(okClosure) + } +} diff --git a/app/src/main/groovy/jd/gui/controller/SaveAllSourcesController.groovy b/app/src/main/groovy/jd/gui/controller/SaveAllSourcesController.groovy new file mode 100644 index 00000000..0a2242df --- /dev/null +++ b/app/src/main/groovy/jd/gui/controller/SaveAllSourcesController.groovy @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.controller + +import groovy.swing.SwingBuilder +import groovy.transform.CompileStatic +import jd.gui.api.API +import jd.gui.api.feature.SourcesSavable +import jd.gui.model.configuration.Configuration +import jd.gui.view.SaveAllSourcesView + +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths +import java.util.concurrent.Callable +import java.util.concurrent.ExecutorService + +class SaveAllSourcesController implements SourcesSavable.Controller, SourcesSavable.Listener { + API api + SaveAllSourcesView saveAllSourcesView + boolean cancel + int counter + int step + + SaveAllSourcesController(SwingBuilder swing, Configuration configuration, API api) { + this.api = api + // Create UI + this.saveAllSourcesView = new SaveAllSourcesView(swing, configuration, api, { onCanceled() }) + } + + @CompileStatic + void show(ExecutorService executor, SourcesSavable savable, File file) { + // Show + this.saveAllSourcesView.show(file) + // Execute background task + executor.submit(new Callable() { + Void call() throws Exception { + int fileCount = savable.fileCount + int quotient = (fileCount / 100) + + cancel = false + counter = 0 + step = 1 + + while (quotient > step) { + step <<= 1 + } + step = (step >> 1) - 1 + + saveAllSourcesView.updateProgressBar(counter) + saveAllSourcesView.setMaxValue(fileCount) + + def path = Paths.get(file.toURI()) + Files.deleteIfExists(path) + + savable.save(api, this as SourcesSavable.Controller, this as SourcesSavable.Listener, path) + + if (cancel) { + Files.delete(path) + } + + saveAllSourcesView.hide() + } + }) + } + + boolean isActivated() { saveAllSourcesView.isVisible() } + + protected void onCanceled() { cancel = true } + + // --- SourcesSavable.Controller --- // + boolean isCancelled() { cancel } + + // --- SourcesSavable.Listener --- // + void pathSaved(Path path) { + if (((counter++) & step) == 0) { + saveAllSourcesView.updateProgressBar(counter) + } + } +} diff --git a/app/src/main/groovy/jd/gui/controller/SearchInConstantPoolsController.groovy b/app/src/main/groovy/jd/gui/controller/SearchInConstantPoolsController.groovy new file mode 100644 index 00000000..f0d0cdd4 --- /dev/null +++ b/app/src/main/groovy/jd/gui/controller/SearchInConstantPoolsController.groovy @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.controller + +import groovy.swing.SwingBuilder +import groovy.transform.CompileStatic +import jd.gui.api.API +import jd.gui.api.feature.IndexesChangeListener +import jd.gui.api.model.Container +import jd.gui.api.model.Indexes +import jd.gui.model.configuration.Configuration +import jd.gui.model.container.FilteredContainerWrapper +import jd.gui.service.type.TypeFactoryService +import jd.gui.util.UriUtil +import jd.gui.view.SearchInConstantPoolsView + +import java.awt.Cursor +import java.util.regex.Pattern + +class SearchInConstantPoolsController implements IndexesChangeListener { + static final int CACHE_MAX_ENTRIES = 5*20*9 + + API api + SearchInConstantPoolsView searchInConstantPoolsView + Map>> cache + Set filteredContainerWrappers + Collection collectionOfIndexes + Closure openClosure + long indexesHashCode = 0L + + SearchInConstantPoolsController(SwingBuilder swing, Configuration configuration, API api) { + this.api = api + // Create UI + this.searchInConstantPoolsView = new SearchInConstantPoolsView( + swing, configuration, api, + { pattern, flags -> updateTree(pattern, flags) }, // onPatternChangedClosure + { uri, pattern, flags -> onTypeSelected(uri, pattern, flags) } // onTypeSelectedClosure + ) + // Create result cache + this.cache = new LinkedHashMap>(CACHE_MAX_ENTRIES*3/2, 0.7f, true) { + protected boolean removeEldestEntry(Map.Entry> eldest) { + return size() > CACHE_MAX_ENTRIES + } + } + this.filteredContainerWrappers = new HashSet() + } + + void show(Collection collectionOfIndexes, Closure openClosure) { + // Init attributes + this.collectionOfIndexes = collectionOfIndexes + this.openClosure = openClosure + // Refresh view + long hashCode = collectionOfIndexes.hashCode() + if (hashCode != indexesHashCode) { + // List of indexes has changed + updateTree(searchInConstantPoolsView.pattern, searchInConstantPoolsView.flags) + indexesHashCode = hashCode + } + // Show + searchInConstantPoolsView.show() + } + + void updateTree(String pattern, int flags) { + filteredContainerWrappers.clear() + + int matchingTypeCount = 0 + int patternLength = pattern.length() + + if (patternLength > 0) { + for (def indexes : collectionOfIndexes) { + def matchingEntries = new HashSet() + + // Waiting the end of indexation... + searchInConstantPoolsView.swing.searchInConstantPoolsDialog.rootPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)) + indexes.waitIndexers() + searchInConstantPoolsView.swing.searchInConstantPoolsDialog.rootPane.setCursor(Cursor.getDefaultCursor()) + // Find matched entries + filter(indexes, pattern, flags, matchingEntries) + + if (! matchingEntries.isEmpty()) { + // Search root container with first matching entry + def parentEntry = matchingEntries.iterator().next() + def container = null + + while (parentEntry.container.root) { + container = parentEntry.container + parentEntry = container.root.parent + } + + // TODO In a future release, display matching strings, types, inner-types, fields and methods, not only matching files + matchingEntries = getOuterEntries(matchingEntries) + + matchingTypeCount += matchingEntries.size() + + // Dummy parent entry wrapper + def parentEntryWrapper = new Container.Entry() { + Collection children + + Container getContainer() { parentEntry.container } + Container.Entry getParent() { null } + URI getUri() { parentEntry.uri } + String getPath() { parentEntry.path } + boolean isDirectory() { false } + long length() { 0 } + InputStream getInputStream() { null } + Collection getChildren() { children } + } + // Create a filtered container + def containerWrapper = new FilteredContainerWrapper(container, parentEntryWrapper, matchingEntries) + // Initialization of 'children' of dummy parent entry wrapper + parentEntryWrapper.children = containerWrapper.root.children + + filteredContainerWrappers.add(containerWrapper) + } + } + } + + searchInConstantPoolsView.updateTree(filteredContainerWrappers, matchingTypeCount) + } + + Collection getOuterEntries(Set matchingEntries) { + def innerTypeEntryToOuterTypeEntry = [:] + def matchingOuterEntriesSet = new HashSet() + + for (def entry : matchingEntries) { + def type = TypeFactoryService.instance.get(entry)?.make(api, entry, null) + + if (type?.outerName) { + def outerTypeEntry = innerTypeEntryToOuterTypeEntry.get(entry) + + if (outerTypeEntry == null) { + def typeNameToEntry = [:] + def innerTypeNameToOuterTypeName = [:] + + // Populate "typeNameToEntry" and "innerTypeNameToOuterTypeName" + for (def e : entry.parent.children) { + type = TypeFactoryService.instance.get(e)?.make(api, e, null) + + if (type) { + typeNameToEntry.put(type.name, e) + if (type.outerName) { + innerTypeNameToOuterTypeName.put(type.name, type.outerName) + } + } + } + + // Search outer type entries and populate "innerTypeEntryToOuterTypeEntry" + for (def e : innerTypeNameToOuterTypeName.entrySet()) { + def innerTypeEntry = typeNameToEntry.get(e.key) + + if (innerTypeEntry) { + def outerTypeName = e.value + + for (;;) { + def typeName = innerTypeNameToOuterTypeName.get(outerTypeName) + if (typeName) { + outerTypeName = typeName + } else { + break + } + } + + outerTypeEntry = typeNameToEntry.get(outerTypeName) + + if (outerTypeEntry) { + innerTypeEntryToOuterTypeEntry.put(innerTypeEntry, outerTypeEntry) + } + } + } + + // Get outer type entry + outerTypeEntry = innerTypeEntryToOuterTypeEntry.get(entry) ?: entry + } + + matchingOuterEntriesSet.add(outerTypeEntry) + } else { + matchingOuterEntriesSet.add(entry) + } + } + + // Return outer type entries sorted by path + return matchingOuterEntriesSet.sort { e1, e2 -> e1.path.compareTo(e2.path) } + } + + void filter(Indexes indexes, String pattern, int flags, Set matchingEntries) { + boolean declarations = ((flags & SearchInConstantPoolsView.SEARCH_TYPE_DECLARATION) != 0) + boolean references = ((flags & SearchInConstantPoolsView.SEARCH_TYPE_REFERENCE) != 0) + + def matchTypeEntriesWithCharClosure = { c, index -> matchTypeEntriesWithChar(c, index) } + def matchTypeEntriesWithStringClosure = { s, index -> matchTypeEntriesWithString(s, index) } + def matchWithCharClosure = { c, index -> matchWithChar(c, index) } + def matchWithStringClosure = { s, index -> matchWithString(s, index) } + + if ((flags & SearchInConstantPoolsView.SEARCH_TYPE_TYPE) != 0) { + if (declarations) + match(indexes, 'typeDeclarations', pattern, + matchTypeEntriesWithCharClosure, matchTypeEntriesWithStringClosure, matchingEntries) + if (references) + match(indexes, 'typeReferences', pattern, + matchTypeEntriesWithCharClosure, matchTypeEntriesWithStringClosure, matchingEntries) + } + + if ((flags & SearchInConstantPoolsView.SEARCH_TYPE_CONSTRUCTOR) != 0) { + if (declarations) + match(indexes, 'constructorDeclarations', pattern, + matchTypeEntriesWithCharClosure, matchTypeEntriesWithStringClosure, matchingEntries) + if (references) + match(indexes, 'constructorReferences', pattern, + matchTypeEntriesWithCharClosure, matchTypeEntriesWithStringClosure, matchingEntries) + } + + if ((flags & SearchInConstantPoolsView.SEARCH_TYPE_METHOD) != 0) { + if (declarations) + match(indexes, 'methodDeclarations', pattern, + matchWithCharClosure, matchWithStringClosure, matchingEntries) + if (references) + match(indexes, 'methodReferences', pattern, + matchWithCharClosure, matchWithStringClosure, matchingEntries) + } + + if ((flags & SearchInConstantPoolsView.SEARCH_TYPE_FIELD) != 0) { + if (declarations) + match(indexes, 'fieldDeclarations', pattern, + matchWithCharClosure, matchWithStringClosure, matchingEntries) + if (references) + match(indexes, 'fieldReferences', pattern, + matchWithCharClosure, matchWithStringClosure, matchingEntries) + } + + if ((flags & SearchInConstantPoolsView.SEARCH_TYPE_STRING) != 0) { + if (declarations || references) + match(indexes, 'strings', pattern, + matchWithCharClosure, matchWithStringClosure, matchingEntries) + } + } + + @CompileStatic + void match(Indexes indexes, String indexName, String pattern, + Closure matchWithCharClosure, Closure matchWithStringClosure, Set matchingEntries) { + int patternLength = pattern.length() + + if (patternLength > 0) { + String key = String.valueOf(indexes.hashCode()) + '***' + indexName + '***' + pattern + Map> matchedTypes = cache.get(key) + + if (matchedTypes == null) { + def index = indexes.getIndex(indexName) + + if (patternLength == 1) { + matchedTypes = (Map>)matchWithCharClosure(pattern.charAt(0), index) + } else { + def lastKey = key.substring(0, key.length() - 1) + def lastMatchedTypes = cache.get(lastKey) + if (lastMatchedTypes) { + matchedTypes = (Map>)matchWithStringClosure(pattern, lastMatchedTypes) + } else { + matchedTypes = (Map>)matchWithStringClosure(pattern, index) + } + } + + // Cache matchingEntries + cache.put(key, matchedTypes) + } + + if (matchedTypes) { + for (def entries : matchedTypes.values()) { + matchingEntries.addAll(entries) + } + } + } + } + + @CompileStatic + static Map> matchTypeEntriesWithChar(char c, Map> index) { + if ((c == '*') || (c == '?')) { + return Collections.emptyMap() + } else { + return index.findAll { String typeName, entries -> + // Search last package separator + int lastPackageSeparatorIndex = typeName.lastIndexOf('/') + 1 + int lastTypeNameSeparatorIndex = typeName.lastIndexOf('$') + 1 + int lastIndex = Math.max(lastPackageSeparatorIndex, lastTypeNameSeparatorIndex) + return (lastIndex < typeName.length()) && (typeName.charAt(lastIndex) == c) + } + } + } + + @CompileStatic + static Map> matchTypeEntriesWithString(String pattern, Map> index) { + def p = createPattern(pattern) + return index.findAll { String typeName, entries -> + // Search last package separator + int lastPackageSeparatorIndex = typeName.lastIndexOf('/') + 1 + int lastTypeNameSeparatorIndex = typeName.lastIndexOf('$') + 1 + int lastIndex = Math.max(lastPackageSeparatorIndex, lastTypeNameSeparatorIndex) + return p.matcher(typeName.substring(lastIndex)).matches() + } + } + + @CompileStatic + static Map> matchWithChar(char c, Map> index) { + if ((c == '*') || (c == '?')) { + return Collections.emptyMap() + } else { + return index.findAll { String key, entries -> !key.isEmpty() && (key.charAt(0) == c) } + } + } + + @CompileStatic + static Map> matchWithString(String pattern, Map> index) { + def p = createPattern(pattern) + return index.findAll { String key, entries -> p.matcher(key).find() } + } + + /** + * Create a simple regular expression + * + * Rules: + * '*' matchTypeEntries 0 ou N characters + * '?' matchTypeEntries 1 character + */ + @CompileStatic + static Pattern createPattern(String pattern) { + int patternLength = pattern.length() + def sbPattern = new StringBuffer(patternLength * 2) + + for (int i = 0; i < patternLength; i++) { + char c = pattern.charAt(i) + + if (c == '*') { + sbPattern.append('.*') + } else if (c == '?') { + sbPattern.append('.') + } else if (c == '.') { + sbPattern.append('\\.') + } else { + sbPattern.append(c) + } + } + + sbPattern.append('.*') + + return Pattern.compile(sbPattern.toString()) + } + + void onTypeSelected(URI uri, String pattern, int flags) { + // Open the single entry uri + def entry = null + + for (def container : filteredContainerWrappers) { + entry = container.getEntry(uri) + if (entry) + break + } + + if (entry) { + def sbPattern = new StringBuffer(200 + pattern.length()) + + sbPattern.append('highlightPattern=') + sbPattern.append(pattern) + sbPattern.append('&highlightFlags=') + + if ((flags & SearchInConstantPoolsView.SEARCH_TYPE_DECLARATION) != 0) + sbPattern.append('d') + if ((flags & SearchInConstantPoolsView.SEARCH_TYPE_REFERENCE) != 0) + sbPattern.append('r') + if ((flags & SearchInConstantPoolsView.SEARCH_TYPE_TYPE) != 0) + sbPattern.append('t') + if ((flags & SearchInConstantPoolsView.SEARCH_TYPE_CONSTRUCTOR) != 0) + sbPattern.append('c') + if ((flags & SearchInConstantPoolsView.SEARCH_TYPE_METHOD) != 0) + sbPattern.append('m') + if ((flags & SearchInConstantPoolsView.SEARCH_TYPE_FIELD) != 0) + sbPattern.append('f') + if ((flags & SearchInConstantPoolsView.SEARCH_TYPE_STRING) != 0) + sbPattern.append('s') + + // TODO In a future release, add 'highlightScope' to display search results in correct type and inner-type + // def type = TypeFactoryService.instance.get(entry)?.make(api, entry, null) + // if (type) { + // sbPattern.append('&highlightScope=') + // sbPattern.append(type.name) + // + // def query = sbPattern.toString() + // def outerPath = UriUtil.getOuterPath(collectionOfIndexes, entry, type) + // + // openClosure(new URI(entry.uri.scheme, entry.uri.host, outerPath, query, null)) + // } else { + def query = sbPattern.toString() + + openClosure(new URI(entry.uri.scheme, entry.uri.host, entry.uri.path, query, null)) + // } + } + } + + // --- IndexesChangeListener --- // + void indexesChanged(Collection collectionOfIndexes) { + if (searchInConstantPoolsView.isVisible()) { + // Update the list of containers + this.collectionOfIndexes = collectionOfIndexes + // And refresh + updateTree(searchInConstantPoolsView.pattern, searchInConstantPoolsView.flags) + } + } +} diff --git a/app/src/main/groovy/jd/gui/controller/SelectLocationController.groovy b/app/src/main/groovy/jd/gui/controller/SelectLocationController.groovy new file mode 100644 index 00000000..3d753ce8 --- /dev/null +++ b/app/src/main/groovy/jd/gui/controller/SelectLocationController.groovy @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.controller + +import groovy.swing.SwingBuilder +import jd.gui.api.API +import jd.gui.api.model.Container +import jd.gui.model.configuration.Configuration +import jd.gui.model.container.FilteredContainerWrapper +import jd.gui.service.type.TypeFactoryService +import jd.gui.view.SelectLocationView + +import java.awt.Point + +class SelectLocationController { + + API api + SelectLocationView selectLocationView + + SelectLocationController(SwingBuilder swing, Configuration configuration, API api) { + this.api = api + // Create UI + selectLocationView = new SelectLocationView(swing, configuration, api) + } + + void show(Point location, Collection entries, Closure locationSelectedClosure, Closure closeClosure) { + // Show UI + def map = [:].withDefault { [] } + + for (def entry : entries) { + def container = entry.container + + // Search root container + while (true) { + def parentContainer = container.root.parent.container + if (parentContainer.root == null) { + break + } else { + container = parentContainer + } + } + + map[container].add(entry) + } + + def filteredContainerWrappers = new HashSet() + + for (def mapEntry : map.entrySet()) { + def container = mapEntry.key + def parentEntry = container.root.parent + + // Dummy parent entry wrapper + def parentEntryWrapper = new Container.Entry() { + Collection children + + Container getContainer() { parentEntry.container } + Container.Entry getParent() { null } + URI getUri() { parentEntry.uri } + String getPath() { parentEntry.path } + boolean isDirectory() { false } + long length() { 0 } + InputStream getInputStream() { null } + Collection getChildren() { children } + } + // Create a filtered container + // TODO In a future release, display matching types and inner-types, not only matching files + def outerEntries = getOuterEntries(mapEntry.value) + + def containerWrapper = new FilteredContainerWrapper(container, parentEntryWrapper, outerEntries) + // Initialization of 'children' of dummy parent entry wrapper + parentEntryWrapper.children = containerWrapper.root.children + + filteredContainerWrappers.add(containerWrapper) + } + + selectLocationView.show( + location, filteredContainerWrappers, entries.size(), + { uri -> onLocationSelected(filteredContainerWrappers, uri, locationSelectedClosure) }, + closeClosure) + } + + Collection getOuterEntries(Collection entries) { + def innerTypeEntryToOuterTypeEntry = [:] + def outerEntriesSet = new HashSet() + + for (def entry : entries) { + def type = TypeFactoryService.instance.get(entry)?.make(api, entry, null) + + if (type?.outerName) { + def outerTypeEntry = innerTypeEntryToOuterTypeEntry.get(entry) + + if (outerTypeEntry == null) { + def typeNameToEntry = [:] + def innerTypeNameToOuterTypeName = [:] + + // Populate "typeNameToEntry" and "innerTypeNameToOuterTypeName" + for (def e : entry.parent.children) { + type = TypeFactoryService.instance.get(e)?.make(api, e, null) + + if (type) { + typeNameToEntry.put(type.name, e) + if (type.outerName) { + innerTypeNameToOuterTypeName.put(type.name, type.outerName) + } + } + } + + // Search outer type entries and populate "innerTypeEntryToOuterTypeEntry" + for (def e : innerTypeNameToOuterTypeName.entrySet()) { + def innerTypeEntry = typeNameToEntry.get(e.key) + + if (innerTypeEntry) { + def outerTypeName = e.value + + for (;;) { + def typeName = innerTypeNameToOuterTypeName.get(outerTypeName) + if (typeName) { + outerTypeName = typeName + } else { + break + } + } + + outerTypeEntry = typeNameToEntry.get(outerTypeName) + + if (outerTypeEntry) { + innerTypeEntryToOuterTypeEntry.put(innerTypeEntry, outerTypeEntry) + } + } + } + + // Get outer type entry + outerTypeEntry = innerTypeEntryToOuterTypeEntry.get(entry) ?: entry + } + + outerEntriesSet.add(outerTypeEntry) + } else { + outerEntriesSet.add(entry) + } + } + + // Return outer type entries sorted by path + return outerEntriesSet.sort { e1, e2 -> e1.path.compareTo(e2.path) } + } + + void onLocationSelected(Set filteredContainerWrappers, URI uri, Closure locationSelectedClosure) { + // Open the single entry uri + def entry = null + + for (def container : filteredContainerWrappers) { + entry = container.getEntry(uri) + if (entry) { + break + } + } + + if (entry) { + locationSelectedClosure(entry) + } + } +} diff --git a/app/src/main/groovy/jd/gui/model/configuration/Configuration.groovy b/app/src/main/groovy/jd/gui/model/configuration/Configuration.groovy new file mode 100644 index 00000000..cf981440 --- /dev/null +++ b/app/src/main/groovy/jd/gui/model/configuration/Configuration.groovy @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.model.configuration + +import java.awt.Dimension +import java.awt.Point + +class Configuration { + Point mainWindowLocation + Dimension mainWindowSize + boolean mainWindowMaximize + String lookAndFeel + + List recentFiles = [] + + File configRecentLoadDirectory + File configRecentSaveDirectory + + Map preferences = [:] + + void addRecentFile(File file) { + recentFiles.remove(file) + recentFiles.add(0, file) + if (recentFiles.size() > 10) { + recentFiles.remove(10) + } + } +} diff --git a/app/src/main/groovy/jd/gui/model/container/FilteredContainerWrapper.groovy b/app/src/main/groovy/jd/gui/model/container/FilteredContainerWrapper.groovy new file mode 100644 index 00000000..ebd3fe7d --- /dev/null +++ b/app/src/main/groovy/jd/gui/model/container/FilteredContainerWrapper.groovy @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.model.container + +import jd.gui.api.model.Container + +class FilteredContainerWrapper implements Container { + Container container + Map map + Container.Entry root + + FilteredContainerWrapper(Container container, Container.Entry parentEntry, Collection entries) { + this.container = container + this.map = new HashMap<>() + this.root = new EntryWrapper(container.root, parentEntry) + + for (def entry : entries) { + while (entry && !map.containsKey(entry.uri)) { + map.put(entry.uri, entry) + entry = entry.parent + } + } + } + + String getType() { container.type } + Container.Entry getRoot() { root } + Container.Entry getEntry(URI uri) { map.get(uri) } + Set getUris() { map.keySet() } + + class EntryWrapper implements Container.Entry, Comparable { + Container.Entry entry + Container.Entry parent + Collection children + + EntryWrapper(Container.Entry entry, Container.Entry parent) { + this.entry = entry + this.parent = parent + this.children = null + } + + Container getContainer() { FilteredContainerWrapper.this } + Container.Entry getParent() { parent } + URI getUri() { entry.uri } + String getPath() { entry.path } + boolean isDirectory() { entry.isDirectory() } + long length() { entry.length() } + InputStream getInputStream() { entry.inputStream } + + Collection getChildren() { + if (children == null) { + children = entry.children.grep { map.containsKey(it.uri) }.collect { new EntryWrapper(it, this) } + } + return children + } + + int compareTo(EntryWrapper other) { + if (entry.isDirectory()) { + if (!other.isDirectory()) { + return -1 + } + } else { + if (other.isDirectory()) { + return 1 + } + } + return entry.path.compareTo(other.path) + } + } +} diff --git a/app/src/main/groovy/jd/gui/model/history/History.groovy b/app/src/main/groovy/jd/gui/model/history/History.groovy new file mode 100644 index 00000000..04c51f2d --- /dev/null +++ b/app/src/main/groovy/jd/gui/model/history/History.groovy @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.model.history + +class History { + URI current = null + List backward = [] + List forward = [] + + void add(URI uri) { + if (current.equals(uri)) { + // Already stored -> Quit + return + } + + if (current == null) { + // Init history + forward.clear() + current = uri + return + } + + if (uri.path.toString().equals(current.path.toString())) { + if (uri.fragment == null) { + // Ignore + } else if (current.fragment == null) { + // Replace current URI + current = uri + } else { + // Store URI + forward.clear() + backward.add(current) + current = uri + } + return + } + + if (uri.toString().startsWith(current.toString())) { + // Replace current URI + current = uri + return + } + + // Store URI + forward.clear() + backward.add(current) + current = uri + } + + URI backward() { + if (! backward.isEmpty()) { + forward.add(current) + int size = backward.size() + current = backward.remove(size-1) + } + return current + } + + URI forward() { + if (! forward.isEmpty()) { + backward.add(current) + int size = forward.size() + current = forward.remove(size-1) + } + return current + } + + boolean canBackward() { !backward.isEmpty() } + boolean canForward() { !forward.isEmpty() } +} diff --git a/app/src/main/groovy/jd/gui/service/configuration/ConfigurationPersister.groovy b/app/src/main/groovy/jd/gui/service/configuration/ConfigurationPersister.groovy new file mode 100644 index 00000000..d61f3f45 --- /dev/null +++ b/app/src/main/groovy/jd/gui/service/configuration/ConfigurationPersister.groovy @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.configuration + +import jd.gui.model.configuration.Configuration + +interface ConfigurationPersister { + Configuration load(); + + void save(Configuration configuration); +} diff --git a/app/src/main/groovy/jd/gui/service/configuration/ConfigurationPersisterService.groovy b/app/src/main/groovy/jd/gui/service/configuration/ConfigurationPersisterService.groovy new file mode 100644 index 00000000..8ae9117e --- /dev/null +++ b/app/src/main/groovy/jd/gui/service/configuration/ConfigurationPersisterService.groovy @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.configuration + +@Singleton +class ConfigurationPersisterService { + private ConfigurationPersister provider = new ConfigurationXmlPersisterProvider() + + ConfigurationPersister get() { + return provider + } +} diff --git a/app/src/main/groovy/jd/gui/service/configuration/ConfigurationXmlPersisterProvider.groovy b/app/src/main/groovy/jd/gui/service/configuration/ConfigurationXmlPersisterProvider.groovy new file mode 100644 index 00000000..29ccd9d9 --- /dev/null +++ b/app/src/main/groovy/jd/gui/service/configuration/ConfigurationXmlPersisterProvider.groovy @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.configuration + +import groovy.xml.MarkupBuilder +import jd.gui.Constants +import jd.gui.model.configuration.Configuration + +import java.awt.* + +class ConfigurationXmlPersisterProvider implements ConfigurationPersister { + static final String ERROR_BACKGROUND_COLOR = 'JdGuiPreferences.errorBackgroundColor' + + static final File FILE = new File(Constants.CONFIG_FILENAME) + + Configuration load() { + // Default values + def screenSize = Toolkit.defaultToolkit.screenSize + + int w = (screenSize.width>Constants.DEFAULT_WIDTH) ? Constants.DEFAULT_WIDTH : screenSize.width + int h = (screenSize.height>Constants.DEFAULT_HEIGHT) ? Constants.DEFAULT_HEIGHT : screenSize.height + int x = (screenSize.width-w)/2 + int y = (screenSize.height-h)/2 + + def config = new Configuration() + config.mainWindowLocation = new Point(x, y) + config.mainWindowSize = new Dimension(w, h) + config.mainWindowMaximize = false + config.lookAndFeel = 'system' + config.configRecentLoadDirectory = config.configRecentSaveDirectory = new File(System.getProperty('user.dir')) + + try { + // Load values + def configuration = new XmlSlurper().parse(FILE) + if (configuration) { + config.recentFiles = configuration.recentFilePaths?.filePath?.collect({ new File(it.text()) }).grep({ it.exists() }) + + def recentDirectories = configuration.recentDirectories + if (recentDirectories) { + if (recentDirectories.loadPath) { + def loadDirectory = new File(recentDirectories.loadPath.text()) + if (loadDirectory.exists()) + config.configRecentLoadDirectory = loadDirectory + } + if (recentDirectories.savePath) { + def saveDirectory = new File(recentDirectories.savePath.text()) + if (saveDirectory.exists()) + config.configRecentSaveDirectory = saveDirectory + } + } + + config.lookAndFeel = configuration.gui.lookAndFeel ?: System.getProperty('swing.defaultlaf') ?: 'system' + + def mainWindow = configuration.gui.mainWindow + def l = mainWindow.location + def s = mainWindow.size + def m = Boolean.valueOf(mainWindow.maximize.text()) + def lx = l.@x.text() as int, ly = l.@y.text() as int + def sw = s.@w.text() as int, sh = s.@h.text() as int + + if ((lx >= 0) && (ly >= 0) && (lx + sw < screenSize.width) && (ly + sh < screenSize.height)) { + // Update preferences + config.mainWindowLocation = new Point(lx, ly) + config.mainWindowSize = new Dimension(sw, sh) + config.mainWindowMaximize = m + } + + for (def node : configuration.preferences.childNodes()) { + config.preferences.put(node.name(), node.text()) + } + } + } catch (Exception ignore) { + } + + if (! config.preferences.containsKey(ERROR_BACKGROUND_COLOR)) { + config.preferences.put(ERROR_BACKGROUND_COLOR, '0xFF6666') + } + + return config + } + + void save(Configuration configuration) { + Point l = configuration.mainWindowLocation + Dimension s = configuration.mainWindowSize + Writer writer = new StringWriter() + MarkupBuilder xml = new MarkupBuilder(writer) + + xml.configuration() { + gui() { + mainWindow() { + location(x:l.x as int, y:l.y as int) + size(w:s.width as int, h:s.height as int) + maximize configuration.mainWindowMaximize + } + lookAndFeel configuration.lookAndFeel + } + recentFilePaths() { + configuration.recentFiles.each { file -> + filePath file.absolutePath + } + } + recentDirectories() { + loadPath configuration.configRecentLoadDirectory?.absolutePath + savePath configuration.configRecentSaveDirectory?.absolutePath + } + preferences() { + configuration.preferences.each { key, value -> + "$key" "$value" + } + } + } + + FILE.write(writer.toString()) + } +} diff --git a/app/src/main/groovy/jd/gui/service/container/ContainerFactoryService.groovy b/app/src/main/groovy/jd/gui/service/container/ContainerFactoryService.groovy new file mode 100644 index 00000000..755a65ca --- /dev/null +++ b/app/src/main/groovy/jd/gui/service/container/ContainerFactoryService.groovy @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.container + +import jd.gui.api.API +import jd.gui.spi.ContainerFactory + +import java.nio.file.FileSystem + +@Singleton(lazy = true) +class ContainerFactoryService { + private List providers = ServiceLoader.load(ContainerFactory).toList() + + ContainerFactory get(API api, FileSystem fileSystem) { + return providers.find { it.accept(api, fileSystem) } + } +} diff --git a/app/src/main/groovy/jd/gui/service/fileloader/FileLoaderService.groovy b/app/src/main/groovy/jd/gui/service/fileloader/FileLoaderService.groovy new file mode 100644 index 00000000..16fc1c27 --- /dev/null +++ b/app/src/main/groovy/jd/gui/service/fileloader/FileLoaderService.groovy @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.fileloader + +import jd.gui.api.API +import jd.gui.spi.FileLoader + +@Singleton(lazy = true) +class FileLoaderService { + final List providers = ServiceLoader.load(FileLoader).toList() + + private Map mapProviders = providers.collectEntries { provider -> + provider.extensions.collectEntries { [it, provider] } + } + + FileLoader get(API api, File file) { + String name = file.name + int lastDot = name.lastIndexOf('.') + String extension = name.substring(lastDot+1) + def provider = mapProviders[extension] + + if (provider.accept(api, file)) { + return provider + } else { + return null + } + } +} diff --git a/app/src/main/groovy/jd/gui/service/indexer/IndexerService.groovy b/app/src/main/groovy/jd/gui/service/indexer/IndexerService.groovy new file mode 100644 index 00000000..22638500 --- /dev/null +++ b/app/src/main/groovy/jd/gui/service/indexer/IndexerService.groovy @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.indexer + +import groovy.transform.CompileStatic +import jd.gui.api.model.Container +import jd.gui.spi.Indexer + +@CompileStatic +@Singleton(lazy = true) +class IndexerService { + protected List providers = ServiceLoader.load(Indexer).toList() + + protected Map mapProviders = populate(providers) + + protected Map populate(List providers) { + Map mapProviders = [:] + + def mapProvidersWithDefault = mapProviders.withDefault { new Indexers() } + + for (def provider : providers) { + for (String type : provider.types) { + mapProvidersWithDefault[type].add(provider) + } + } + + return mapProviders + } + + Indexer get(Container.Entry entry) { + Indexer indexer = get(entry.container.type, entry) + return indexer ?: get('*', entry) + } + + Indexer get(String containerType, Container.Entry entry) { + String path = entry.path + String type = entry.isDirectory() ? 'dir' : 'file' + String prefix = containerType + ':' + type + Indexer indexer = mapProviders.get(prefix + ':' + path)?.match(path) + + if (!indexer) { + int lastSlashIndex = path.lastIndexOf('/') + String name = path.substring(lastSlashIndex+1) + + indexer = mapProviders.get(prefix + ':*/' + name)?.match(path) + + if (!indexer) { + int index = name.lastIndexOf('.') + if (index != -1) { + String extension = name.substring(index + 1) + indexer = mapProviders.get(prefix + ':*.' + extension)?.match(path) + } + if (!indexer) { + indexer = mapProviders.get(prefix + ':*')?.match(path) + } + } + } + + return indexer + } + + static class Indexers { + ArrayList indexers = [] + Indexer defaultIndexer + + void add(Indexer indexer) { + if (indexer.pathPattern) { + indexers << indexer + } else { + defaultIndexer = indexer + } + } + + Indexer match(String path) { + for (def indexer : indexers) { + if (path ==~ indexer.pathPattern) { + return indexer + } + } + return defaultIndexer + } + } +} diff --git a/app/src/main/groovy/jd/gui/service/mainpanel/ContainerPanelFactoryProvider.groovy b/app/src/main/groovy/jd/gui/service/mainpanel/ContainerPanelFactoryProvider.groovy new file mode 100644 index 00000000..90ad9b6b --- /dev/null +++ b/app/src/main/groovy/jd/gui/service/mainpanel/ContainerPanelFactoryProvider.groovy @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.mainpanel + +import groovy.transform.CompileStatic +import jd.gui.api.API +import jd.gui.api.feature.ContentIndexable +import jd.gui.api.feature.SourcesSavable +import jd.gui.api.feature.SourcesSavable.Controller +import jd.gui.api.feature.SourcesSavable.Listener +import jd.gui.api.feature.UriGettable +import jd.gui.api.model.Container +import jd.gui.api.model.Indexes +import jd.gui.spi.PanelFactory +import jd.gui.spi.SourceSaver +import jd.gui.spi.TreeNodeFactory +import jd.gui.view.component.panel.TreeTabbedPanel + +import javax.swing.JComponent +import javax.swing.tree.DefaultMutableTreeNode +import javax.swing.tree.DefaultTreeModel +import java.nio.file.Path + +class ContainerPanelFactoryProvider implements PanelFactory { + + String[] getTypes() { ['default'] } + + public T make(API api, Container container) { + return new ContainerPanel(api, container) + } + + class ContainerPanel extends TreeTabbedPanel implements ContentIndexable, SourcesSavable { + Container.Entry entry + + ContainerPanel(API api, Container container) { + super(api, container.root.uri) + + this.entry = container.root.parent + + def root = new DefaultMutableTreeNode() + + for (def entry : container.root.children) { + TreeNodeFactory factory = api.getTreeNodeFactory(entry) + if (factory) { + root.add(factory.make(api, entry)) + } + } + + tree.model = new DefaultTreeModel(root) + } + + // --- ContentIndexable --- // + @CompileStatic + Indexes index(API api) { + // Classic map + def map = new HashMap>() + // Map populating value automatically + def mapWithDefault = new HashMap>().withDefault { key -> + def subMap = new HashMap() + + map.put(key, subMap) + + return subMap.withDefault { subKey -> + def array = new ArrayList() + subMap.put(subKey, array) + return array + } + } + // Index populating value automatically + def indexesWithDefault = new Indexes() { + void waitIndexers() {} + Map getIndex(String name) { + mapWithDefault.get(name) + } + } + + api.getIndexer(entry)?.index(api, entry, indexesWithDefault) + + // To prevent memory leaks, return an index without the 'populate' behaviour + return new Indexes() { + void waitIndexers() {} + Map getIndex(String name) { map.get(name) } + } + } + + // --- SourcesSavable --- // + String getSourceFileName() { + def path = api.getSourceSaver(entry)?.getSourcePath(entry) + int index = path.lastIndexOf('/') + return path.substring(index+1) + } + + int getFileCount() { api.getSourceSaver(entry)?.getFileCount(api, entry) } + + void save(API api, Controller controller, Listener listener, Path path) { + api.getSourceSaver(entry)?.save( + api, + new SourceSaver.Controller() { + boolean isCancelled() { controller.isCancelled() } + }, + new SourceSaver.Listener() { + void pathSaved(Path p) { listener.pathSaved(p) } + }, + path, entry) + } + } +} diff --git a/app/src/main/groovy/jd/gui/service/mainpanel/PanelFactoryService.groovy b/app/src/main/groovy/jd/gui/service/mainpanel/PanelFactoryService.groovy new file mode 100644 index 00000000..b199e252 --- /dev/null +++ b/app/src/main/groovy/jd/gui/service/mainpanel/PanelFactoryService.groovy @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.mainpanel + +import jd.gui.api.model.Container +import jd.gui.spi.PanelFactory + +@Singleton(lazy = true) +class PanelFactoryService { + protected List providers = ServiceLoader.load(PanelFactory).toList() + + protected Map mapProviders = populate(providers) + + protected Map populate(List providers) { + Map mapProviders = [:] + + for (def provider : providers) { + for (String type : provider.types) { + mapProviders.put(type, provider) + } + } + + return mapProviders + } + + PanelFactory get(Container container) { + return mapProviders.get(container.type) ?: mapProviders.get('default') + } +} diff --git a/app/src/main/groovy/jd/gui/service/pastehandler/PasteHandlerService.groovy b/app/src/main/groovy/jd/gui/service/pastehandler/PasteHandlerService.groovy new file mode 100644 index 00000000..d5e16e19 --- /dev/null +++ b/app/src/main/groovy/jd/gui/service/pastehandler/PasteHandlerService.groovy @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.pastehandler + +import jd.gui.spi.PasteHandler + +@Singleton(lazy = true) +class PasteHandlerService { + protected List providers = ServiceLoader.load(PasteHandler).toList() + + PasteHandler get(Object obj) { + for (def provider : providers) { + if (provider.accept(obj)) { + return provider + } + } + return null + } +} diff --git a/app/src/main/groovy/jd/gui/service/platform/PlatformService.groovy b/app/src/main/groovy/jd/gui/service/platform/PlatformService.groovy new file mode 100644 index 00000000..e7bb7fb6 --- /dev/null +++ b/app/src/main/groovy/jd/gui/service/platform/PlatformService.groovy @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.platform + +@Singleton +class PlatformService { + enum OS { Linux, MacOSX, Windows } + + final OS os = initOS() + + final isLinux = (os == OS.Linux) + final isMac = (os == OS.MacOSX) + final isWindows = (os == OS.Windows) + + OS initOS() { + String osName = System.getProperty('os.name').toLowerCase() + + if (osName.contains('windows')) { + return OS.Windows + } else if (osName.contains('mac os')) { + return OS.MacOSX + } else { + return OS.Linux + } + } +} diff --git a/app/src/main/groovy/jd/gui/service/preferencespanel/PreferencesPanelService.groovy b/app/src/main/groovy/jd/gui/service/preferencespanel/PreferencesPanelService.groovy new file mode 100644 index 00000000..4973fe53 --- /dev/null +++ b/app/src/main/groovy/jd/gui/service/preferencespanel/PreferencesPanelService.groovy @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.preferencespanel + +import jd.gui.spi.PreferencesPanel + +@Singleton(lazy = true) +class PreferencesPanelService { + final List providers = ServiceLoader.load(PreferencesPanel).toList() +} diff --git a/app/src/main/groovy/jd/gui/service/sourcesaver/SourceSaverService.groovy b/app/src/main/groovy/jd/gui/service/sourcesaver/SourceSaverService.groovy new file mode 100644 index 00000000..92ea4d94 --- /dev/null +++ b/app/src/main/groovy/jd/gui/service/sourcesaver/SourceSaverService.groovy @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.sourcesaver + +import groovy.transform.CompileStatic +import jd.gui.api.model.Container +import jd.gui.spi.SourceSaver + +@CompileStatic +@Singleton(lazy = true) +class SourceSaverService { + protected List providers = ServiceLoader.load(SourceSaver).toList() + + protected Map mapProviders = populate(providers) + + protected Map populate(List providers) { + Map mapProviders = [:] + + def mapProvidersWithDefault = mapProviders.withDefault { new SourceSavers() } + + for (def provider : providers) { + for (String type : provider.types) { + mapProvidersWithDefault[type].add(provider) + } + } + + return mapProviders + } + + SourceSaver get(Container.Entry entry) { + SourceSaver saver = get(entry.container.type, entry) + return saver ?: get('*', entry) + } + + SourceSaver get(String containerType, Container.Entry entry) { + String path = entry.path + String type = entry.isDirectory() ? 'dir' : 'file' + String prefix = containerType + ':' + type + SourceSaver saver = mapProviders.get(prefix + ':' + path)?.match(path) + + if (!saver) { + int lastSlashIndex = path.lastIndexOf('/') + String name = path.substring(lastSlashIndex+1) + + saver = mapProviders.get(prefix + ':*/' + name)?.match(path) + + if (!saver) { + int index = name.lastIndexOf('.') + if (index != -1) { + String extension = name.substring(index + 1) + saver = mapProviders.get(prefix + ':*.' + extension)?.match(path) + } + if (!saver) { + saver = mapProviders.get(prefix + ':*')?.match(path) + } + } + } + + return saver + } + + static class SourceSavers { + ArrayList savers = [] + SourceSaver defaultSaver + + void add(SourceSaver saver) { + if (saver.pathPattern) { + savers << saver + } else { + defaultSaver = saver + } + } + + SourceSaver match(String path) { + for (def saver : savers) { + if (path ==~ saver.pathPattern) { + return saver + } + } + return defaultSaver + } + } +} diff --git a/app/src/main/groovy/jd/gui/service/treenode/TreeNodeFactoryService.groovy b/app/src/main/groovy/jd/gui/service/treenode/TreeNodeFactoryService.groovy new file mode 100644 index 00000000..01a0bf83 --- /dev/null +++ b/app/src/main/groovy/jd/gui/service/treenode/TreeNodeFactoryService.groovy @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.treenode + +import groovy.transform.CompileStatic +import jd.gui.api.model.Container +import jd.gui.spi.TreeNodeFactory + +@CompileStatic +@Singleton(lazy = true) +class TreeNodeFactoryService { + protected List providers = ServiceLoader.load(TreeNodeFactory).toList() + + protected Map mapProviders = populate(providers) + + protected Map populate(List providers) { + Map mapProviders = [:] + + def mapProvidersWithDefault = mapProviders.withDefault { new TreeNodeFactories() } + + for (def provider : providers) { + for (String type : provider.types) { + mapProvidersWithDefault[type].add(provider) + } + } + + return mapProviders + } + + @CompileStatic + TreeNodeFactory get(Container.Entry entry) { + TreeNodeFactory factory = get(entry.container.type, entry) + return factory ?: get('*', entry) + } + + @CompileStatic + TreeNodeFactory get(String containerType, Container.Entry entry) { + String path = entry.path + String type = entry.isDirectory() ? 'dir' : 'file' + String prefix = containerType + ':' + type + ':' + TreeNodeFactory factory = mapProviders.get(prefix + path)?.match(path) + + if (!factory) { + int lastSlashIndex = path.lastIndexOf('/') + String name = path.substring(lastSlashIndex+1) + + factory = mapProviders.get(prefix + '*/' + name)?.match(path) + if (!factory) { + int index = name.lastIndexOf('.') + if (index != -1) { + String extension = name.substring(index + 1) + factory = mapProviders.get(prefix + '*.' + extension)?.match(path) + } + if (!factory) { + factory = mapProviders.get(prefix + '*')?.match(path) + } + } + } + + return factory + } + + static class TreeNodeFactories { + ArrayList factories = [] + TreeNodeFactory defaultFactory + + void add(TreeNodeFactory factory) { + if (factory.pathPattern) { + factories << factory + } else { + defaultFactory = factory + } + } + + TreeNodeFactory match(String path) { + for (def factory : factories) { + if (path ==~ factory.pathPattern) { + return factory + } + } + return defaultFactory + } + } +} diff --git a/app/src/main/groovy/jd/gui/service/type/TypeFactoryService.groovy b/app/src/main/groovy/jd/gui/service/type/TypeFactoryService.groovy new file mode 100644 index 00000000..3e8fbe3d --- /dev/null +++ b/app/src/main/groovy/jd/gui/service/type/TypeFactoryService.groovy @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.type + +import groovy.transform.CompileStatic +import jd.gui.api.model.Container +import jd.gui.api.model.Type +import jd.gui.spi.TypeFactory + +@Singleton(lazy = true) +class TypeFactoryService { + protected List providers = ServiceLoader.load(TypeFactory).toList() + + protected Map mapProviders = populate(providers) + + protected Map populate(List providers) { + Map mapProviders = [:] + + def mapProvidersWithDefault = mapProviders.withDefault { new TypeFactories() } + + for (def provider : providers) { + for (String type : provider.types) { + mapProvidersWithDefault[type].add(provider) + } + } + + // Early interface loading + Type.class + Type.Field.class + Type.Method.class + + return mapProviders + } + + @CompileStatic + TypeFactory get(Container.Entry entry) { + TypeFactory factory = get(entry.container.type, entry) + return factory ?: get('*', entry) + } + + @CompileStatic + TypeFactory get(String containerType, Container.Entry entry) { + String path = entry.path + String type = entry.isDirectory() ? 'dir' : 'file' + String prefix = containerType + ':' + type + ':' + TypeFactory factory = mapProviders.get(prefix + path)?.match(path) + + if (!factory) { + int lastSlashIndex = path.lastIndexOf('/') + String name = path.substring(lastSlashIndex+1) + + factory = mapProviders.get(prefix + '*/' + name)?.match(path) + + if (!factory) { + int index = name.lastIndexOf('.') + if (index != -1) { + String extension = name.substring(index + 1) + factory = mapProviders.get(prefix + '*.' + extension)?.match(path) + } + if (!factory) { + factory = mapProviders.get(prefix + '*')?.match(path) + } + } + } + + return factory + } + + static class TypeFactories { + ArrayList factories = [] + TypeFactory defaultFactory + + void add(TypeFactory factory) { + if (factory.pathPattern) { + factories << factory + } else { + defaultFactory = factory + } + } + + TypeFactory match(String path) { + for (def factory : factories) { + if (path ==~ factory.pathPattern) { + return factory + } + } + return defaultFactory + } + } +} diff --git a/app/src/main/groovy/jd/gui/service/uriloader/UriLoaderService.groovy b/app/src/main/groovy/jd/gui/service/uriloader/UriLoaderService.groovy new file mode 100644 index 00000000..3c3d9105 --- /dev/null +++ b/app/src/main/groovy/jd/gui/service/uriloader/UriLoaderService.groovy @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.uriloader + +import jd.gui.api.API +import jd.gui.spi.UriLoader + +@Singleton(lazy = true) +class UriLoaderService { + final List providers = ServiceLoader.load(UriLoader).toList() + + private Map mapProviders = providers.collectEntries { provider -> + provider.schemes.collectEntries { [it, provider] } + } + + UriLoader get(API api, URI uri) { + def provider = mapProviders[uri.scheme] + + if (provider.accept(api, uri)) { + return provider + } else { + return null + } + } +} diff --git a/app/src/main/groovy/jd/gui/util/UriUtil.groovy b/app/src/main/groovy/jd/gui/util/UriUtil.groovy new file mode 100644 index 00000000..10d50cc8 --- /dev/null +++ b/app/src/main/groovy/jd/gui/util/UriUtil.groovy @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.util + +import jd.gui.api.API +import jd.gui.api.model.Container +import jd.gui.api.model.Indexes +import jd.gui.api.model.Type +import jd.gui.service.type.TypeFactoryService + +class UriUtil { + /* + * Convert inner entry URI to outer entry uri with a fragment. + * Example: + * file://codebase/a/b/c/D$E.class => file://codebase/a/b/c/D.class#typeDeclaration=D$E + */ + static URI createURI(API api, Collection collectionOfIndexes, Container.Entry entry, String query, String fragment) { + def type = TypeFactoryService.instance.get(entry)?.make(api, entry, null) + def uri = entry.uri + def path = type?.outerName ? getOuterPath(collectionOfIndexes, entry, type) : uri.path + return new URI(uri.scheme, uri.host, path, query, fragment) + } + + protected static String getOuterPath(Collection collectionOfIndexes, Container.Entry entry, Type type) { + def outerName = type.outerName + + if (outerName) { + for (def indexes : collectionOfIndexes) { + def outerEntries = indexes.getIndex('typeDeclarations').get(outerName) + if (outerEntries) { + for (def outerEntry : outerEntries) { + if (outerEntry.container == entry.container) { + return outerEntry.uri.path + } + } + } + } + } + + return entry.uri.path + } +} diff --git a/app/src/main/groovy/jd/gui/view/GoToDescription.groovy b/app/src/main/groovy/jd/gui/view/GoToDescription.groovy new file mode 100644 index 00000000..5d70cf89 --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/GoToDescription.groovy @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view + +dialog( + id:'goToDialog', + owner:mainFrame, + title:'Go to Line', + modal:false, + resizable:false) { + vbox(border:emptyBorder(15)) { + hbox { + label(id: 'goToEnterLineNumberLabel') + hglue() + } + vstrut(10) + textField(id:'goToEnterLineNumberTextField', columns:30) + vstrut(10) + hbox { + label(id:'goToEnterLineNumberErrorLabel', text:' ') + hglue() + } + vstrut(15) + hbox { + hglue() + button(id: 'goToOkButton') { + action(id:'goToOkAction', name:'Ok', enabled:false) + } + hstrut(5) + button { + action(id:'goToCancelAction', name:'Cancel', closure:{ goToDialog.visible = false }) + } + } + vstrut(13) + } +} \ No newline at end of file diff --git a/app/src/main/groovy/jd/gui/view/GoToView.groovy b/app/src/main/groovy/jd/gui/view/GoToView.groovy new file mode 100644 index 00000000..cc1f01d6 --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/GoToView.groovy @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view + +import groovy.swing.SwingBuilder +import jd.gui.api.feature.LineNumberNavigable +import jd.gui.model.configuration.Configuration + +import javax.swing.JComponent +import javax.swing.KeyStroke +import javax.swing.UIManager +import javax.swing.event.DocumentEvent +import javax.swing.event.DocumentListener +import java.awt.Color +import java.awt.event.KeyAdapter +import java.awt.event.KeyEvent + +class GoToView { + SwingBuilder swing + Listener listener + + GoToView(SwingBuilder swing, Configuration configuration) { + this.swing = swing + this.listener = new Listener(Color.decode(configuration.preferences.get('JdGuiPreferences.errorBackgroundColor'))) + // Load GUI description + swing.edt { + build(GoToDescription) + goToDialog.with { + rootPane.with { + defaultButton = goToOkButton + getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "OpenTypeView.cancel") + actionMap.put("OpenTypeView.cancel", goToCancelAction) + } + pack() + locationRelativeTo = parent + goToEnterLineNumberTextField.addKeyListener(new KeyAdapter() { + void keyTyped(KeyEvent e) { + if (! Character.isDigit(e.keyChar)) { + e.consume() + } + } + }) + } + // Add binding + goToEnterLineNumberTextField.document.addDocumentListener(listener) + } + } + + void show(LineNumberNavigable navigator, Closure okClosure) { + // Init + listener.navigator = navigator + swing.doLater { + goToEnterLineNumberLabel.text = "Enter line number (1..$navigator.maximumLineNumber):" + goToOkAction.closure = { + okClosure(Integer.valueOf(goToEnterLineNumberTextField.text)) + goToDialog.visible = false + } + goToEnterLineNumberTextField.text = '' + goToDialog.visible = true + } + } + + class Listener implements DocumentListener { + LineNumberNavigable navigator + Color backgroundColor + Color errorBackgroundColor + + Listener(Color errorBackgroundColor) { + this.backgroundColor = UIManager.getColor('TextField.background') + this.errorBackgroundColor = errorBackgroundColor + } + + void insertUpdate(DocumentEvent e) { onTextChange() } + void removeUpdate(DocumentEvent e) { onTextChange() } + void changedUpdate(DocumentEvent e) { onTextChange() } + + void onTextChange() { + swing.doLater { + String text = goToEnterLineNumberTextField.text + + if (text.length() == 0) { + goToOkAction.enabled = false + clearErrorMessage() + } else if (text.isInteger()) { + int lineNumber = Integer.valueOf(text) + + if (lineNumber > navigator.maximumLineNumber) { + goToOkAction.enabled = false + showErrorMessage('Line number out of range') + } else if (navigator.checkLineNumber(lineNumber)) { + goToOkAction.enabled = true + clearErrorMessage() + } else { + goToOkAction.enabled = false + showErrorMessage('Line number not found') + } + } else { + goToOkAction.enabled = false + showErrorMessage('Not a number') + } + } + } + + void showErrorMessage(String message) { + swing.with { + goToEnterLineNumberErrorLabel.text = message + goToEnterLineNumberTextField.background = errorBackgroundColor + } + } + + void clearErrorMessage() { + swing.with { + goToEnterLineNumberErrorLabel.text = ' ' + goToEnterLineNumberTextField.background = backgroundColor + } + } + } +} diff --git a/app/src/main/groovy/jd/gui/view/MainDescription.groovy b/app/src/main/groovy/jd/gui/view/MainDescription.groovy new file mode 100644 index 00000000..3da4654f --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/MainDescription.groovy @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view + +import javax.swing.UIManager +import java.awt.BorderLayout +import java.awt.Color +import java.awt.Desktop +import java.awt.Font +import java.awt.GridLayout +import java.awt.Toolkit + +import javax.swing.WindowConstants + +import jd.gui.Constants +import jd.gui.service.platform.PlatformService + +actions { + action( + id:'openAction', + name:'Open File...', + mnemonic:'O', + accelerator:shortcut('O'), + shortDescription:'Open a file' + ) + action( + id:'closeAction', + name:'Close', + accelerator:shortcut('W'), + enabled:false + ) + action( + id:'saveAction', + name:'Save', + accelerator:shortcut('S'), + enabled:false + ) + action( + id:'saveAllSourcesAction', + name:'Save All Sources', + accelerator:shortcut('alt S'), + enabled:false + ) + action( + id:'exitAction', + name:'Exit', + mnemonic:'x', + accelerator:'alt X', + shortDescription:'Quit this program', + closure:{ mainFrame.dispose() } + ) + action( + id:'copyAction', + name:'Copy', + accelerator:shortcut('C'), + enabled:false + ) + action( + id:'pasteAction', + name:'Paste Log', + accelerator:shortcut('V') + ) + action( + id:'selectAllAction', + name:'Select all', + accelerator:shortcut('A'), + enabled:false + ) + action( + id:'findAction', + name:'Find...', + accelerator:shortcut('F'), + enabled:false + ) + action( + id:'openTypeAction', + name:'Open Type...', + accelerator:shortcut('shift T'), + enabled:false + ) + action( + id:'openTypeHierarchyAction', + name:'Open Type Hierarchy...', + accelerator:'F4', + enabled:false + ) + action( + id:'goToAction', + name:'Go to Line...', + accelerator:shortcut('L'), + enabled:false + ) + action( + id:'backwardAction', + name:'Back', + accelerator:'alt LEFT', + enabled:false + ) + action( + id:'forwardAction', + name:'Forward', + accelerator:'alt RIGHT', + enabled:false + ) + action( + id:'searchAction', + name:'Search...', + accelerator:shortcut('shift S'), + enabled:false + ) + action( + id:'wikipediaAction', + name:'Wikipedia', + shortDescription:'Wikipedia', + enabled:Desktop.isDesktopSupported() ? Desktop.desktop.isSupported(Desktop.Action.BROWSE) : false + ) + action( + id:'preferencesAction', + name:'Preferences...', + accelerator:shortcut('shift P'), + shortDescription:'Preferences' + ) + action( + id:'aboutAction', + name:'About...', + accelerator:'F1', + shortDescription:'About JD-GUI', + closure:{ + aboutDialog.pack() + aboutDialog.setLocationRelativeTo(mainFrame) + aboutDialog.visible = true + } + ) + action( + id:'findNextAction', + name:'Next' + ) + action( + id:'findPreviousAction', + name:'Previous' + ) + action( + id:'findCaseSensitiveAction' + ) + action( + id:'findCloseAction', + closure: { findPanel.visible = false } + ) +} + +frame( + id:'mainFrame', + title:'Java Decompiler', + iconImage:Toolkit.defaultToolkit.getImage(getClass().classLoader.getResource('images/Icon_java_128.png')), + minimumSize:[Constants.MINIMAL_WIDTH, Constants.MINIMAL_HEIGHT], + defaultCloseOperation:WindowConstants.EXIT_ON_CLOSE) { + menuBar { + menu('File') { + menuItem(openAction) + separator() + menuItem(closeAction) + separator() + menuItem(saveAction) + menuItem(saveAllSourcesAction) + separator() + menu(id:'recentFiles', text:'Recent Files') + if (!PlatformService.instance.isMac) { + separator() + menuItem(exitAction) + } + } + menu('Edit') { + menuItem(copyAction) + menuItem(pasteAction) + separator() + menuItem(selectAllAction) + separator() + menuItem(findAction) { + } + } + menu('Navigation') { + menuItem(openTypeAction) + menuItem(openTypeHierarchyAction) + separator() + menuItem() { + action( + name:'Quick Outline...', + accelerator:shortcut('shift O'), + enabled:false, + closure:{ println("clicked on the Save menu item!") } + ) + } + separator() + menuItem(goToAction) + separator() + menuItem(backwardAction) + menuItem(forwardAction) + } + menu('Search') { + menuItem(searchAction) + } + menu('Help') { + menuItem(wikipediaAction) + separator() + menuItem(preferencesAction) + if (!PlatformService.instance.isMac) { + separator() + menuItem(aboutAction) + } + } + } + panel { + borderLayout() + toolBar(constraints:PAGE_START, floatable:false, rollover:true) { + iconButton(action:openAction, text:null, icon:imageIcon(resource:'/images/open.png')) + separator() + iconButton(action:openTypeAction, text:null, icon:imageIcon(resource:'/images/open_type.png')) + iconButton(action:searchAction, text:null, icon:imageIcon(resource:'/images/search_src.png')) + separator() + iconButton(action:backwardAction, text:null, icon:imageIcon(resource:'/images/backward_nav.png')) + iconButton(action:forwardAction, text:null, icon:imageIcon(resource:'/images/forward_nav.png')) + } + mainTabbedPanel(id:'mainTabbedPanel', constraints:CENTER) + hbox(id:'findPanel', constraints:PAGE_END, border:emptyBorder(2), visible:false) { + label(text:'Find: ') + comboBox(id:'findComboBox', editable: true) + hstrut(5) + toolBar(floatable:false, rollover:true) { + iconButton(action:findNextAction, icon:imageIcon(resource: '/images/next_nav.png')) + hstrut(5) + iconButton(action:findPreviousAction, icon:imageIcon(resource: '/images/prev_nav.png')) + } + checkBox(id:'findCaseSensitive', action:findCaseSensitiveAction, text:'Case sensitive') + hglue() + + def closeIcon = imageIcon(resource:'/images/close.gif') + def closeActivateIcon = imageIcon(resource:'/images/close_active.gif') + + iconButton(action:findCloseAction, contentAreaFilled:false, icon:closeIcon, rolloverIcon:closeActivateIcon) + } + } +} + +dialog( + id:'aboutDialog', + owner:mainFrame, + title:'About Java Decompiler', + modal:false, + resizable:false) { + panel(border:emptyBorder(15)) { + borderLayout() + vbox(constraints:BorderLayout.NORTH) { + panel( + border:lineBorder(color:Color.BLACK), + background:Color.WHITE) { + borderLayout() + label(icon:imageIcon(resource:'/images/Icon_java_64.png'), border:emptyBorder(15), constraints:BorderLayout.WEST) + vbox(border:emptyBorder([15,0,15,15]), constraints:BorderLayout.EAST) { + hbox { + label(text: 'Java Decompiler', font:UIManager.getFont('Label.font').deriveFont(Font.BOLD, 14)) + hglue() + } + hbox { + panel(layout:new GridLayout(2,2), opaque:false, border:emptyBorder([5,10,5,50])) { + label(text: 'JD-GUI') + label(text: 'version 1.0.0') + label(text: 'JD-Core') + label(text: 'version 0.7.1') + } + hglue() + } + hbox { + label(text: 'Copyright © 2008-2015 Emmanuel Dupuy') + hglue() + } + } + } + vstrut(10) + } + hbox(constraints:BorderLayout.SOUTH) { + hglue() + button { + action(id:'aboutOkAction', name:' Ok ', closure:{ aboutDialog.visible = false }) + } + hglue() + } + } +} diff --git a/app/src/main/groovy/jd/gui/view/MainView.groovy b/app/src/main/groovy/jd/gui/view/MainView.groovy new file mode 100644 index 00000000..db0df045 --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/MainView.groovy @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view + +import groovy.swing.SwingBuilder +import jd.gui.Constants +import jd.gui.api.feature.ContentSearchable +import jd.gui.api.feature.ContentSelectable +import jd.gui.api.feature.LineNumberNavigable +import jd.gui.api.feature.PageChangeListener +import jd.gui.api.feature.PageClosable +import jd.gui.api.feature.FocusedTypeGettable +import jd.gui.api.feature.ContentSavable +import jd.gui.api.feature.ContentCopyable +import jd.gui.api.feature.SourcesSavable +import jd.gui.api.feature.UriGettable +import jd.gui.api.feature.UriOpenable +import jd.gui.model.configuration.Configuration +import jd.gui.model.history.History +import jd.gui.spi.FileLoader + +import javax.swing.Icon +import javax.swing.JComponent +import javax.swing.JLabel +import javax.swing.event.ChangeEvent +import javax.swing.event.ChangeListener +import java.awt.Color +import java.awt.Dimension +import java.awt.Point +import javax.swing.JFileChooser +import javax.swing.JFrame +import javax.swing.JOptionPane +import javax.swing.filechooser.FileNameExtensionFilter + +import jd.gui.view.component.IconButton +import jd.gui.view.component.panel.MainTabbedPanel + +import java.awt.event.KeyAdapter +import java.awt.event.KeyEvent + +class MainView implements UriOpenable { + SwingBuilder swing + History history + Closure openFilesClosure + Color findBackgroundColor + Color findErrorBackgroundColor + + MainView( + SwingBuilder swing, Configuration configuration, History history, + Closure panelClosedClosure, + Closure currentPageChangedClosure, + Closure openFilesClosure, + Closure findCriteriaChangedClosure) { + this.swing = swing + this.history = history + this.openFilesClosure = openFilesClosure + + swing.edt { + // Setup + registerBeanFactory('iconButton', IconButton.class) + registerBeanFactory('mainTabbedPanel', MainTabbedPanel.class) + // Load GUI description + build(MainDescription) + // Add listeners + mainTabbedPanel.pageChangedListeners.add(new PageChangeListener() { + JComponent currentPage = null + + public void pageChanged(T page) { + if (currentPage != page) { + // Update current page + currentPage = page + currentPageChangedClosure(page) + + swing.doLater { + if (page) { + // Update title + def path = page.uri.path + int index = path.lastIndexOf('/') + def name = (index == -1) ? path : path.substring(index + 1) + mainFrame.title = name + ' - Java Decompiler' + // Update history + history.add(page.uri) + // Update history actions + updateHistoryActions() + // Update menu + saveAction.enabled = (page instanceof ContentSavable) + copyAction.enabled = (page instanceof ContentCopyable) + selectAllAction.enabled = (page instanceof ContentSelectable) + findAction.enabled = (page instanceof ContentSearchable) + openTypeHierarchyAction.enabled = (page instanceof FocusedTypeGettable) + goToAction.enabled = (page instanceof LineNumberNavigable) + } else { + // Update title + mainFrame.title = 'Java Decompiler' + // Update menu + saveAction.enabled = false + copyAction.enabled = false + selectAllAction.enabled = false + openTypeHierarchyAction.enabled = false + goToAction.enabled = false + } + } + } + } + }) + mainTabbedPanel.tabbedPane.addChangeListener(new ChangeListener() { + int lastTabCount = 0 + + void stateChanged(ChangeEvent e) { + swing.with { + int tabCount = mainTabbedPanel.tabbedPane.tabCount + boolean enabled = (tabCount > 0) + + closeAction.enabled = enabled + openTypeAction.enabled = enabled + searchAction.enabled = enabled + saveAllSourcesAction.enabled = (mainTabbedPanel.tabbedPane.selectedComponent instanceof SourcesSavable) + + if (tabCount < lastTabCount) { + panelClosedClosure() + } + + lastTabCount = tabCount + } + } + }) + findComboBox.editor.editorComponent.addKeyListener(new KeyAdapter() { + String lastStr = '' + + void keyReleased(KeyEvent e) { + def findComboBox = swing.findComboBox + + switch (e.keyCode) { + case KeyEvent.VK_ESCAPE: + swing.findPanel.visible = false + break + case KeyEvent.VK_ENTER: + def str = getFindText() + if (str.length() > 1) { + def index = findComboBox.model.getIndexOf(str) + if(index != -1 ) { + findComboBox.removeItemAt(index) + } + findComboBox.insertItemAt(str, 0) + findComboBox.selectedIndex = 0 + swing.findNextAction.closure() + } + break + default: + def str = getFindText() + if (! lastStr.equals(str)) { + findCriteriaChangedClosure() + lastStr = str + } + } + } + }) + findComboBox.editor.editorComponent.opaque = true + + this.findBackgroundColor = findComboBox.editor.editorComponent.background + this.findErrorBackgroundColor = Color.decode(configuration.preferences.get('JdGuiPreferences.errorBackgroundColor')) + } + swing.doLater { + // Lazy initialization + new JLabel('init HTML parser') + } + } + + void show(Point location, Dimension size, boolean maximize) { + swing.edt { + // Set position, resize and show + mainFrame.with { + setLocation(location) + setSize(size) + extendedState = maximize ? JFrame.MAXIMIZED_BOTH : 0 + } + mainFrame.show() + } + } + + void showFindPanel() { + swing.edt { + findPanel.visible = true + findComboBox.requestFocus() + } + } + + void setFindBackgroundColor(boolean wasFound) { + swing.doLater { + findComboBox.editor.editorComponent.background = wasFound ? findBackgroundColor : findErrorBackgroundColor + } + } + + JFileChooser createOpenFileChooser() { + JFileChooser chooser = new JFileChooser() { + void addFileFilters(Map loaders) { + removeChoosableFileFilter(getFileFilter()) + + def extensions = loaders.collect({ key, value -> key }).sort() + def description = extensions.collect({ "*.$it" }).join(', ') + + addChoosableFileFilter(new FileNameExtensionFilter("All files ($description)", extensions as String[])) + + for (def extension : extensions) { + def loader = loaders[extension] + addChoosableFileFilter(new FileNameExtensionFilter(loader.description, loader.extensions)) + } + } + void show(Closure okClosure) { + if (showOpenDialog(swing.mainFrame) == JFileChooser.APPROVE_OPTION) { + okClosure() + } + } + } + return chooser + } + + JFileChooser createSaveFileChooser() { + JFileChooser chooser = new JFileChooser() { + void show(Closure okClosure) { + if (showSaveDialog(swing.mainFrame) == JFileChooser.APPROVE_OPTION) { + if (selectedFile.exists()) { + def title = 'Are you sure?' + def message = "The file '$selectedFile.absolutePath' already isContainsIn.\n Do you want to replace the existing file?" + if (swing.optionPane().showConfirmDialog(swing.mainFrame, message, title, JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { + okClosure(selectedFile) + } + } else { + okClosure(selectedFile) + } + } + } + } + return chooser + } + + void showErrorDialog(String message) { + swing.optionPane().showMessageDialog(swing.mainFrame, message, 'Error', JOptionPane.ERROR_MESSAGE) + } + + public void addMainPanel(String title, Icon icon, String tip, T component) { + swing.edt { + swing.mainTabbedPanel.addPage(title, icon, tip, component) + } + } + + public List getMainPanels() { + return swing.mainTabbedPanel.getPages() + } + + public T getSelectedMainPanel() { + return swing.mainTabbedPanel.tabbedPane.getSelectedComponent() + } + + void closeCurrentTab() { + swing.doLater { + def component = mainTabbedPanel.tabbedPane.selectedComponent + if (component instanceof PageClosable) { + if (!component.closePage()) { + mainTabbedPanel.removeComponent(component) + } + } else { + mainTabbedPanel.removeComponent(component) + } + } + } + + void updateRecentFilesMenu(List files) { + swing.doLater { + recentFiles.removeAll() + files.each { f -> + recentFiles.add( + menuItem() { + action(name:reduceRecentFilePath(f.absolutePath), closure:{ openFilesClosure(f) }) + } + ) + } + } + } + + String getFindText() { + def doc = swing.findComboBox.editor.editorComponent.document + return doc.getText(0, doc.length) + } + + boolean getFindCaseSensitive() { swing.findCaseSensitive.isSelected() } + + void updateHistoryActions() { + swing.doLater { + backwardAction.enabled = history.canBackward() + forwardAction.enabled = history.canForward() + } + } + + // --- Utils --- // + static String reduceRecentFilePath(String path) { + int lastSeparatorPosition = path.lastIndexOf(File.separatorChar as int) + + if ((lastSeparatorPosition == -1) || (lastSeparatorPosition < Constants.RECENT_FILE_MAX_LENGTH)) { + return path + } + + int length = Constants.RECENT_FILE_MAX_LENGTH/2 - 2 + String left = path.substring(0, length) + String right = path.substring(path.length() - length) + + return left + "..." + right + } + + // --- URIOpener --- // + boolean openUri(URI uri) { + boolean success + swing.edt { + success = swing.mainTabbedPanel.openUri(uri) + } + return success + } +} diff --git a/app/src/main/groovy/jd/gui/view/OpenTypeDescription.groovy b/app/src/main/groovy/jd/gui/view/OpenTypeDescription.groovy new file mode 100644 index 00000000..6fc5df86 --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/OpenTypeDescription.groovy @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view + +import javax.swing.ScrollPaneConstants +import java.awt.BorderLayout +import java.awt.Dimension + +dialog( + id:'openTypeDialog', + owner:mainFrame, + title:'Open Type', + modal:false) { + panel(border:emptyBorder(15)) { + borderLayout() + vbox(constraints:BorderLayout.NORTH) { + hbox { + label(text:'Select a type to select (* = any string, ? = any character, TZ = TimeZone):') + hglue() + } + vstrut(10) + textField(id:'openTypeEnterTextField', columns:30) + vstrut(10) + hbox { + label(id:'openTypeMatchLabel', text:'Matching types:') + hglue() + } + vstrut(10) + } + scrollPane( + constraints:BorderLayout.CENTER, + horizontalScrollBarPolicy:ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER, + preferredSize:new Dimension(400, 150)) { + list(id:'openTypeList') + } + vbox(constraints:BorderLayout.SOUTH) { + vstrut(25) + hbox { + hglue() + button(id:'openTypeOpenButton') { + action(id:'openTypeOpenAction', name:'Open', enabled:false) + } + hstrut(5) + button { + action(id:'openTypeCancelAction', name:'Cancel', closure:{ openTypeDialog.visible = false }) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/groovy/jd/gui/view/OpenTypeHierarchyDescription.groovy b/app/src/main/groovy/jd/gui/view/OpenTypeHierarchyDescription.groovy new file mode 100644 index 00000000..f7aadcec --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/OpenTypeHierarchyDescription.groovy @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view + +import javax.swing.ScrollPaneConstants +import java.awt.BorderLayout +import java.awt.Dimension + +dialog( + id:'openTypeHierarchyDialog', + owner:mainFrame, + title:'Hierarchy Type', + modal:false) { + panel(border:emptyBorder(15)) { + borderLayout() + scrollPane( + id:'openTypeHierarchyScrollPane', + constraints:BorderLayout.CENTER, + horizontalScrollBarPolicy:ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER, + preferredSize:new Dimension(400, 150)) { + tree(id:'openTypeHierarchyTree') + } + vbox(constraints:BorderLayout.SOUTH) { + vstrut(25) + hbox { + hglue() + button(id:'openTypeHierarchyOpenButton') { + action(id:'openTypeHierarchyOpenAction', name:'Open', enabled:false) + } + hstrut(5) + button { + action(id:'openTypeHierarchyCancelAction', name:'Cancel', closure:{ openTypeHierarchyDialog.visible = false }) + } + } + } + } +} diff --git a/app/src/main/groovy/jd/gui/view/OpenTypeHierarchyView.groovy b/app/src/main/groovy/jd/gui/view/OpenTypeHierarchyView.groovy new file mode 100644 index 00000000..9e25dd95 --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/OpenTypeHierarchyView.groovy @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view + +import groovy.swing.SwingBuilder +import jd.gui.api.API +import jd.gui.api.model.Container +import jd.gui.api.model.TreeNodeData +import jd.gui.api.model.Type +import jd.gui.model.configuration.Configuration +import jd.gui.view.component.Tree +import jd.gui.view.renderer.TreeNodeRenderer + +import javax.swing.* +import javax.swing.event.TreeExpansionEvent +import javax.swing.event.TreeExpansionListener +import javax.swing.event.TreeSelectionEvent +import javax.swing.event.TreeSelectionListener +import javax.swing.tree.DefaultMutableTreeNode +import javax.swing.tree.DefaultTreeModel +import javax.swing.tree.TreePath +import java.awt.Point +import java.awt.Rectangle +import java.awt.event.KeyAdapter +import java.awt.event.KeyEvent +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent + +class OpenTypeHierarchyView { + static final ImageIcon rootClassIcon = new ImageIcon(OpenTypeHierarchyView.class.classLoader.getResource('images/generate_class.png')) + static final ImageIcon rootInterfaceIcon = new ImageIcon(OpenTypeHierarchyView.class.classLoader.getResource('images/generate_int.png')) + + SwingBuilder swing + API api + Closure onTypeSelectedClosure + Closure getSubTypeNamesClosure + Closure getEntriesClosure + Container.Entry entry + String typeName + + OpenTypeHierarchyView( + SwingBuilder swing, Configuration configuration, API api, + Closure onTypeSelectedClosure, Closure getSubTypeNamesClosure, Closure getEntriesClosure) { + this.swing = swing + this.api = api + this.onTypeSelectedClosure = onTypeSelectedClosure + this.getSubTypeNamesClosure = getSubTypeNamesClosure + this.getEntriesClosure = getEntriesClosure + // Load GUI description + swing.edt { + // Setup + registerBeanFactory('tree', Tree.class) + // Load GUI description + build(OpenTypeHierarchyDescription) + openTypeHierarchyDialog.with { + rootPane.with { + defaultButton = openTypeHierarchyOpenButton + getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "OpenTypeHierarchyView.cancel") + actionMap.put("OpenTypeHierarchyView.cancel", openTypeHierarchyCancelAction) + } + minimumSize = size + openTypeHierarchyTree.model = new DefaultTreeModel(new DefaultMutableTreeNode()) + openTypeHierarchyTree.cellRenderer = new TreeNodeRenderer() + openTypeHierarchyTree.addMouseListener(new MouseAdapter() { + void mouseClicked(MouseEvent e) { + if (e.clickCount == 2) { + onTypeSelected(e.source) + } + } + }) + openTypeHierarchyTree.addTreeExpansionListener(new TreeExpansionListener() { + void treeExpanded(TreeExpansionEvent e) { + def node = e.path.lastPathComponent + if (node.getChildAt(0).userObject == null) { + populateTreeNode(node, null) + e.source.model.reload(node) + } + } + void treeCollapsed(TreeExpansionEvent e) {} + }) + openTypeHierarchyTree.addKeyListener(new KeyAdapter() { + void keyPressed(KeyEvent e) { + if (e.keyCode == KeyEvent.VK_F4) { + def node = swing.openTypeHierarchyTree.lastSelectedPathComponent + if (node) { + updateTree(node.entry, node.typeName) + } + } + } + }) + openTypeHierarchyTree.addTreeSelectionListener(new TreeSelectionListener() { + void valueChanged(TreeSelectionEvent e) { + swing.openTypeHierarchyOpenAction.enabled = (swing.openTypeHierarchyTree.lastSelectedPathComponent?.entry != null) + } + }) + openTypeHierarchyOpenAction.closure = { onTypeSelected(openTypeHierarchyTree) } + pack() + } + } + } + + void show() { + swing.doLater { + openTypeHierarchyDialog.locationRelativeTo = openTypeHierarchyDialog.parent + openTypeHierarchyDialog.visible = true + openTypeHierarchyTree.requestFocus() + } + } + + boolean isVisible() { swing.openTypeHierarchyDialog.visible } + + void updateTree(Container.Entry entry, String typeName) { + swing.doLater { + // Store current entry and type name + this.entry = entry + this.typeName = typeName + // Clear tree + JTree tree = swing.openTypeHierarchyTree + def model = tree.model + def root = model.root + root.removeAllChildren() + + def selectedTreeNode = createTreeNode(entry, typeName) + def parentTreeNode = createParentTreeNode(selectedTreeNode) + + root.add(parentTreeNode) + model.reload() + + if (selectedTreeNode) { + // Select tree node + def path = new TreePath(selectedTreeNode.path) + tree.selectionPath = path + // Expand + tree.expandPath(path) + // Scroll to show tree node + tree.makeVisible(path) + Rectangle bounds = tree.getPathBounds(path) + + if(bounds) { + bounds.x = 0 + + Rectangle lastRowBounds = tree.getRowBounds(tree.getRowCount()-1) + + if (lastRowBounds) { + bounds.y = Math.max(bounds.y-30, 0) + bounds.height = Math.min(bounds.height+bounds.y+60, lastRowBounds.height+lastRowBounds.y) - bounds.y + } + + tree.scrollRectToVisible(bounds) + if (tree.accessibleContext) { + tree.accessibleContext.fireVisibleDataPropertyChange() + } + } + } + } + } + + TreeNode createTreeNode(Container.Entry entry, String typeName) { + def type = api.getTypeFactory(entry).make(api, entry, typeName) + def entries = getEntriesClosure(typeName) + def treeNode = new TreeNode(entry, typeName, entries, new TreeNodeBean(type)) + def childTypeNames = getSubTypeNamesClosure(typeName) + + if (childTypeNames) { + // Add dummy node + treeNode.add(new DefaultMutableTreeNode()) + } + + return treeNode + } + + /** + * Create parent and sibling tree nodes + */ + TreeNode createParentTreeNode(TreeNode treeNode) { + def type = api.getTypeFactory(treeNode.entry).make(api, treeNode.entry, treeNode.typeName) + def superTypeName = type.superName + + if (superTypeName == null) { + // super type undefined + return treeNode + } else { + def superEntries = getEntriesClosure(superTypeName) + + // Search entry in the sane container of 'entry' + def superEntry + + if (superEntries) { + superEntry = superEntries.find { it.container == treeNode.entry.container } + + if (superEntry == null) { + // Not found -> Choose 1st one + superEntry = superEntries.get(0) + } + } else { + superEntry = null + } + + if (superEntry == null) { + // Entry not found --> Most likely hypothesis : Java type entry + int lastPackageSeparatorIndex = superTypeName.lastIndexOf('/') + def package_ = superTypeName.substring(0, lastPackageSeparatorIndex).replace('/', '.') + def name = superTypeName.substring(lastPackageSeparatorIndex + 1).replace('$', '.') + def label = package_ ? name + ' - ' + package_ : name + def icon = ((type.flags & Type.FLAG_INTERFACE) == 0) ? rootClassIcon : rootInterfaceIcon + def rootTreeNode = new TreeNode(null, superTypeName, null, new TreeNodeBean(label, icon)) + + if (package_.startsWith('java.')) { + // If root type is a JDK type, do not create a tree node for each child types + rootTreeNode.add(treeNode) + } else { + populateTreeNode(rootTreeNode, treeNode) + } + + return rootTreeNode + } else { + // Create parent tree node + def superTreeNode = createTreeNode(superEntry, superTypeName) + // Populate parent tree node + populateTreeNode(superTreeNode, treeNode) + // Recursive call + return createParentTreeNode(superTreeNode) + } + } + } + + void populateTreeNode(TreeNode superTreeNode, TreeNode treeNode) { + superTreeNode.removeAllChildren() + + def subTypeNames = getSubTypeNamesClosure(superTreeNode.typeName) + + subTypeNames.collect { tn -> + if (tn.equals(treeNode?.typeName)) { + return treeNode + } else { + def entries = getEntriesClosure(tn) + // Search entry in the sane container of 'entry' + def e = entries.find { it.container == superTreeNode.entry.container } + if (e == null) { + // Not found -> Choose 1st one + e = entries.get(0) + } + if (e == null) { + return null + } + // Create type + def t = api.getTypeFactory(e).make(api, e, tn) + if (t == null) { + return null + } + // Create tree node + return createTreeNode(e, t.name) + } + }.grep { tn -> + tn != null + }.sort { tn1, tn2 -> + tn1.userObject.label.compareTo(tn2.userObject.label) + }.each { tn -> + superTreeNode.add(tn) + } + } + + void focus() { + swing.doLater { + openTypeHierarchyTree.requestFocus() + } + } + + void onTypeSelected(JTree openTypeHierarchyTree) { + def selectedTreeNode = openTypeHierarchyTree.lastSelectedPathComponent + if (selectedTreeNode) { + def path = new TreePath(selectedTreeNode.path) + Rectangle bounds = openTypeHierarchyTree.getPathBounds(path) + Point listLocation = openTypeHierarchyTree.locationOnScreen + Point leftBottom = new Point(listLocation.x+bounds.x as int, listLocation.y+bounds.y+bounds.height as int) + onTypeSelectedClosure(leftBottom, selectedTreeNode.entries, selectedTreeNode.typeName) + } + } + + static class TreeNode extends DefaultMutableTreeNode { + Container.Entry entry + String typeName + List entries + + TreeNode(Container.Entry entry, String typeName, List entries, Object userObject) { + super(userObject) + this.entry = entry + this.typeName = typeName + this.entries = entries + } + } + + // Graphic data for renderer + static class TreeNodeBean implements TreeNodeData { + String label + String tip + Icon icon + Icon openIcon + + TreeNodeBean(Type type) { + this.label = type.displayPackageName ? type.displayTypeName + ' - ' + type.displayPackageName : type.displayTypeName + this.icon = type.icon + } + + TreeNodeBean(String label, Icon icon) { + this.label = label + this.icon = icon + } + } +} diff --git a/app/src/main/groovy/jd/gui/view/OpenTypeView.groovy b/app/src/main/groovy/jd/gui/view/OpenTypeView.groovy new file mode 100644 index 00000000..d0285657 --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/OpenTypeView.groovy @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view + +import groovy.swing.SwingBuilder +import jd.gui.api.API +import jd.gui.api.model.Container +import jd.gui.model.configuration.Configuration +import jd.gui.view.bean.OpenTypeListCellBean +import jd.gui.view.renderer.OpenTypeListCellRenderer + +import javax.swing.* +import javax.swing.event.DocumentEvent +import javax.swing.event.DocumentListener +import javax.swing.event.ListSelectionEvent +import javax.swing.event.ListSelectionListener +import java.awt.Point +import java.awt.Rectangle +import java.awt.event.FocusEvent +import java.awt.event.FocusListener +import java.awt.event.KeyAdapter +import java.awt.event.KeyEvent +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent + +class OpenTypeView { + static final MAX_LINE_COUNT = 80 + + SwingBuilder swing + API api + + OpenTypeView(SwingBuilder swing, Configuration configuration, API api, Closure onPatternChangedClosure, Closure onTypeSelectedClosure) { + this.swing = swing + this.api = api + // Load GUI description + swing.edt { + // Load GUI description + build(OpenTypeDescription) + openTypeDialog.with { + rootPane.with { + defaultButton = openTypeOpenButton + getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "OpenTypeView.cancel") + actionMap.put("OpenTypeView.cancel", openTypeCancelAction) + } + minimumSize = size + openTypeEnterTextField.addKeyListener(new KeyAdapter() { + void keyTyped(KeyEvent e) { + switch (e.keyChar) { + case '=': case '(': case ')': case '{': case '}': case '[': case ']': + e.consume() + break + default: + if (Character.isDigit(e.keyChar) && (swing.openTypeEnterTextField.text.length() == 0)) { + // First character can not be a digit + e.consume() + } + break + } + } + void keyPressed(KeyEvent e) { + if (e.keyCode == KeyEvent.VK_DOWN) { + swing.edt { + if (openTypeList.model.size > 0) { + openTypeList.selectedIndex = 0 + openTypeList.requestFocus() + e.consume() + } + } + } + } + }) + openTypeEnterTextField.addFocusListener(new FocusListener() { + void focusGained(FocusEvent e) { + swing.edt { + openTypeList.clearSelection() + } + } + void focusLost(FocusEvent e) {} + }) + openTypeEnterTextField.document.addDocumentListener(new DocumentListener() { + void insertUpdate(DocumentEvent e) { call(e) } + void removeUpdate(DocumentEvent e) { call(e) } + void changedUpdate(DocumentEvent e) { call(e) } + void call(DocumentEvent e) { onPatternChangedClosure(e.document.getText(0, e.document.length)) } + }) + openTypeList.addKeyListener(new KeyAdapter() { + void keyPressed(KeyEvent e) { + if (e.keyCode == KeyEvent.VK_UP) { + swing.edt { + if (openTypeList.selectedIndex == 0) { + openTypeEnterTextField.requestFocus() + e.consume() + } + } + } + } + }) + openTypeList.model = new DefaultListModel() + openTypeList.cellRenderer = new OpenTypeListCellRenderer() + openTypeList.addMouseListener(new MouseAdapter() { + void mouseClicked(MouseEvent e) { + if (e.clickCount == 2) { + onTypeSelected(onTypeSelectedClosure) + } + } + }) + openTypeList.addListSelectionListener(new ListSelectionListener() { + void valueChanged(ListSelectionEvent e) { + swing.edt { + openTypeOpenAction.enabled = (openTypeList.selectedValue != null) + } + } + }) + openTypeOpenAction.closure = { onTypeSelected(onTypeSelectedClosure) } + pack() + } + } + } + + void show() { + swing.doLater { + swing.openTypeEnterTextField.selectAll() + // Show + openTypeDialog.locationRelativeTo = openTypeDialog.parent + openTypeDialog.visible = true + openTypeEnterTextField.requestFocus() + } + } + + boolean isVisible() { swing.openTypeDialog.visible } + + String getPattern() { swing.openTypeEnterTextField.text } + + void updateList(Map> map) { + swing.doLater { + def model = openTypeList.model + def typeNames = map.keySet().toList().sort() + + model.removeAllElements() + + typeNames.sort { name1, name2 -> + int lasPackageSeparatorIndex = name1.lastIndexOf('/') + def shortName1 = name1.substring(lasPackageSeparatorIndex+1) + + lasPackageSeparatorIndex = name2.lastIndexOf('/') + def shortName2 = name2.substring(lasPackageSeparatorIndex+1) + + return shortName1.compareTo(shortName2) + }.eachWithIndex { typeName, index -> + if (index < MAX_LINE_COUNT) { + def entries = map.get(typeName) + def firstEntry = entries.iterator().next() + def type = api.getTypeFactory(firstEntry).make(api, firstEntry, typeName) + + if (type) { + model.addElement(new OpenTypeListCellBean(label:type.displayTypeName, packag:type.displayPackageName, icon:type.icon, entries:entries, typeName:typeName)) + } else { + model.addElement(new OpenTypeListCellBean(label:typeName, entries:entries, typeName:typeName)) + } + } else if (index == MAX_LINE_COUNT) { + model.addElement(null) + } + } + + int count = typeNames.size() + switch (count) { + case 0: + openTypeMatchLabel.text = 'Matching types:' + break + case 1: + openTypeMatchLabel.text = '1 matching type:' + break + default: + openTypeMatchLabel.text = count + ' matching types:' + } + } + } + + void focus() { + swing.doLater { + openTypeList.requestFocus() + } + } + + void onTypeSelected(Closure typeSelectedClosure) { + swing.doLater { + def index = openTypeList.selectedIndex + if (index != -1) { + def selectedCellBean = openTypeList.model.getElementAt(index) + Point listLocation = openTypeList.locationOnScreen + Rectangle cellBound = openTypeList.getCellBounds(index, index) + Point leftBottom = new Point(listLocation.x + cellBound.x as int, listLocation.y + cellBound.y + cellBound.height as int) + typeSelectedClosure(leftBottom, selectedCellBean.entries, selectedCellBean.typeName) + } + } + } +} diff --git a/app/src/main/groovy/jd/gui/view/PreferencesDescription.groovy b/app/src/main/groovy/jd/gui/view/PreferencesDescription.groovy new file mode 100644 index 00000000..a600dfc0 --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/PreferencesDescription.groovy @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view + +import javax.swing.ScrollPaneConstants +import java.awt.BorderLayout + +dialog( + id:'preferencesDialog', + owner:mainFrame, + title:'Preferences', + modal:false) { + panel(border:emptyBorder(15)) { + borderLayout() + scrollPane( + id:'preferencesScrollPane', + constraints:BorderLayout.CENTER, + horizontalScrollBarPolicy:ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER, + border:emptyBorder(0)) { + vbox(id:'preferencesPanels') + } + vbox(constraints:BorderLayout.SOUTH) { + vstrut(15) + hbox { + hglue() + button(id:'preferencesOkButton') { + action(id:'preferencesOkAction', name:' Ok ') + } + hstrut(5) + button { + action(id:'preferencesCancelAction', name:'Cancel', closure:{ preferencesDialog.visible = false }) + } + } + } + } +} diff --git a/app/src/main/groovy/jd/gui/view/PreferencesView.groovy b/app/src/main/groovy/jd/gui/view/PreferencesView.groovy new file mode 100644 index 00000000..3d7cfcca --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/PreferencesView.groovy @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view + +import groovy.swing.SwingBuilder +import jd.gui.model.configuration.Configuration +import jd.gui.spi.PreferencesPanel + +import javax.swing.BorderFactory +import javax.swing.Box +import javax.swing.JComponent +import javax.swing.JLabel +import javax.swing.KeyStroke +import java.awt.Color +import java.awt.Dimension +import java.awt.Font +import java.awt.Toolkit +import java.awt.event.KeyEvent + +class PreferencesView implements PreferencesPanel.PreferencesPanelChangeListener { + SwingBuilder swing + Map preferences + List panels + Map valids + + PreferencesView(SwingBuilder swing, Configuration configuration, List panels) { + this.swing = swing + this.preferences = configuration.preferences + this.panels = panels + this.valids = [:] + // Load GUI description + swing.edt { + build(PreferencesDescription) + preferencesDialog.with { + rootPane.with { + defaultButton = preferencesOkButton + getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), 'PreferencesDescription.cancel') + actionMap.put("PreferencesDescription.cancel", preferencesCancelAction) + } + + preferencesPanels.opaque = true + preferencesPanels.background = preferencesDialog.background + + def groups = [:].withDefault { [] } + def errorBackgroundColor = Color.decode(configuration.preferences.get('JdGuiPreferences.errorBackgroundColor')) + + for (def panel : panels) { + panel.init(errorBackgroundColor) + panel.addPreferencesChangeListener(this) + groups.get(panel.preferencesGroupTitle).add(panel) + } + + for (def groupEntry : groups.entrySet().sort { e1, e2 -> e1.key.compareTo(e2.key) }) { + def vbox = Box.createVerticalBox() + vbox.border = BorderFactory.createTitledBorder(groupEntry.key) + + for (def panel : groupEntry.value.sort { p1, p2 -> p1.preferencesPanelTitle.compareTo(p2.preferencesPanelTitle) }) { + // Add title + def hbox = Box.createHorizontalBox() + def title = new JLabel(panel.preferencesPanelTitle) + title.font = title.font.deriveFont(Font.BOLD) + hbox.add(title) + hbox.add(Box.createHorizontalGlue()) + hbox.border = BorderFactory.createEmptyBorder(0, 0, 5, 0) + vbox.add(hbox) + // Add panel + panel.maximumSize = new Dimension(panel.maximumSize.width as int, panel.preferredSize.height as int) + vbox.add(panel) + } + + preferencesPanels.add(vbox) + } + + preferencesPanels.add(Box.createVerticalGlue()) + + // Size of the screen + def screenSize = Toolkit.defaultToolkit.screenSize + // Height of the task bar + def scnMax = Toolkit.defaultToolkit.getScreenInsets(getGraphicsConfiguration()) + // screen height in pixels without taskbar + int taskBarHeight = scnMax.bottom + scnMax.top + int maxHeight = screenSize.height - taskBarHeight + + int preferredHeight = preferencesPanels.preferredSize.height + if (preferredHeight > maxHeight) + preferredHeight = maxHeight + preferencesScrollPane.preferredSize = new Dimension(400, preferredHeight) + + pack() + locationRelativeTo = parent + } + } + } + + void show(Closure okClosure) { + swing.doLater { + preferencesOkAction.closure = { onOk(okClosure) } + for (def panel : panels) { + panel.loadPreferences(preferences) + } + preferencesDialog.visible = true + } + } + + void onOk(Closure okClosure) { + swing.doLater { + for (def panel : panels) { + panel.savePreferences(preferences) + } + preferencesDialog.visible = false + okClosure() + } + } + + // --- PreferencesPanel.PreferencesChangeListener --- // + void preferencesPanelChanged(PreferencesPanel source) { + swing.doLater { + boolean valid = source.arePreferencesValid() + + valids.put(source, Boolean.valueOf(valid)) + + if (valid) { + for (def panel : panels) { + if (valids.get(panel) == Boolean.FALSE) { + preferencesOkAction.enabled = false + return + } + } + preferencesOkAction.enabled = true + } else { + preferencesOkAction.enabled = false + } + } + } +} diff --git a/app/src/main/groovy/jd/gui/view/SaveAllSourcesDescription.groovy b/app/src/main/groovy/jd/gui/view/SaveAllSourcesDescription.groovy new file mode 100644 index 00000000..3468329f --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/SaveAllSourcesDescription.groovy @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view + +dialog( + id:'saveAllSourcesDialog', + owner:mainFrame, + title:'Save All Sources', + modal:false, + resizable:false) { + vbox(border:emptyBorder(15)) { + hbox { + label(id: 'saveAllSourcesLabel', text: ' ') + hglue() + } + vstrut(10) + progressBar(id:'saveAllSourcesProgressBar') + vstrut(15) + hbox { + hglue() + button { + action(id:'saveAllSourcesCancelAction', name:'Cancel') + } + } + } +} diff --git a/app/src/main/groovy/jd/gui/view/SaveAllSourcesView.groovy b/app/src/main/groovy/jd/gui/view/SaveAllSourcesView.groovy new file mode 100644 index 00000000..8c7ebe1f --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/SaveAllSourcesView.groovy @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view + +import groovy.swing.SwingBuilder +import jd.gui.api.API +import jd.gui.model.configuration.Configuration + +import java.awt.event.WindowAdapter +import java.awt.event.WindowEvent + +class SaveAllSourcesView { + SwingBuilder swing + API api + + SaveAllSourcesView(SwingBuilder swing, Configuration configuration, API api, Closure cancelClosure) { + this.swing = swing + this.api = api + // Load GUI description + swing.edt { + // Load GUI description + build(SaveAllSourcesDescription) + saveAllSourcesDialog.with { + saveAllSourcesCancelAction.closure = cancelClosure + addWindowListener(new WindowAdapter() { + void windowClosing(WindowEvent e) { + cancelClosure() + } + }) + pack() + } + } + } + + void show(File file) { + swing.doLater { + // Init GUI + saveAllSourcesLabel.text = "Saving '$file.absolutePath'..." + saveAllSourcesProgressBar.value = 0 + saveAllSourcesProgressBar.maximum = 10 + saveAllSourcesProgressBar.indeterminate = true + saveAllSourcesDialog.pack() + // Show + saveAllSourcesDialog.locationRelativeTo = saveAllSourcesDialog.parent + saveAllSourcesDialog.visible = true + } + } + + boolean isVisible() { swing.saveAllSourcesDialog.isVisible() } + + void setMaxValue(int maxValue) { + swing.doLater { + if (maxValue > 0) { + saveAllSourcesProgressBar.maximum = maxValue + saveAllSourcesProgressBar.indeterminate = false + } else { + saveAllSourcesProgressBar.indeterminate = true + } + } + } + + void updateProgressBar(int value) { + swing.doLater { + saveAllSourcesProgressBar.value = value + } + } + + void hide() { + swing.doLater { + saveAllSourcesDialog.visible = false + } + } +} diff --git a/app/src/main/groovy/jd/gui/view/SearchInConstantPoolsDescription.groovy b/app/src/main/groovy/jd/gui/view/SearchInConstantPoolsDescription.groovy new file mode 100644 index 00000000..0a96719f --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/SearchInConstantPoolsDescription.groovy @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view + +import javax.swing.ScrollPaneConstants +import java.awt.BorderLayout +import java.awt.Dimension + +dialog( + id:'searchInConstantPoolsDialog', + owner:mainFrame, + title:'Search', + modal:false) { + panel(border: emptyBorder(15)) { + borderLayout() + vbox(constraints: BorderLayout.NORTH) { + hbox { + label(text: 'Search string (* = any string, ? = any character):') + hglue() + } + vstrut(10) + hbox { + textField(id: 'searchInConstantPoolsEnterTextField', columns: 30) + } + vstrut(10) + hbox { + panel(border:titledBorder(title:'Search For')) { + borderLayout() + hbox(constraints: BorderLayout.WEST) { + panel { + gridLayout(cols: 1, rows: 2) + checkBox(id: 'searchInConstantPoolsCheckBoxType', text: 'Type', selected:true) + checkBox(id: 'searchInConstantPoolsCheckBoxField', text: 'Field') + } + panel { + gridLayout(cols: 1, rows: 2) + checkBox(id: 'searchInConstantPoolsCheckBoxConstructor', text: 'Constructor') + checkBox(id: 'searchInConstantPoolsCheckBoxMethod', text: 'Method') + } + panel { + gridLayout(cols: 1, rows: 2) + checkBox(id: 'searchInConstantPoolsCheckBoxString', text: 'String Constant') + } + } + } + panel(border:titledBorder(title:'Limit To')) { + borderLayout() + hbox(constraints: BorderLayout.WEST) { + panel { + gridLayout(cols: 1, rows: 2) + checkBox(id: 'searchInConstantPoolsCheckBoxDeclarations', text: 'Declarations', selected:true) + checkBox(id: 'searchInConstantPoolsCheckBoxReferences', text: 'References', selected:true) + } + } + } + } + vstrut(10) + hbox { + label(id:'searchInConstantPoolsLabel', text:'Matching types:') + hglue() + } + vstrut(10) + } + scrollPane( + constraints: BorderLayout.CENTER, + horizontalScrollBarPolicy: ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER, + preferredSize: new Dimension(400, 150)) { + tree(id:'searchInConstantPoolsTree') + } + vbox(constraints: BorderLayout.SOUTH) { + vstrut(25) + hbox { + hglue() + button(id: 'searchInConstantPoolsOkButton') { + action(id: 'searchInConstantPoolsOpenAction', name: 'Open', enabled: false) + } + hstrut(5) + button { + action(id: 'searchInConstantPoolsCancelAction', name: 'Cancel', closure:{ searchInConstantPoolsDialog.visible = false }) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/groovy/jd/gui/view/SearchInConstantPoolsView.groovy b/app/src/main/groovy/jd/gui/view/SearchInConstantPoolsView.groovy new file mode 100644 index 00000000..947293a0 --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/SearchInConstantPoolsView.groovy @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view + +import groovy.swing.SwingBuilder +import jd.gui.api.API +import jd.gui.api.feature.TreeNodeExpandable +import jd.gui.model.configuration.Configuration +import jd.gui.model.container.FilteredContainerWrapper +import jd.gui.view.component.Tree +import jd.gui.view.renderer.TreeNodeRenderer + +import javax.swing.JComponent +import javax.swing.JTree +import javax.swing.KeyStroke +import javax.swing.event.DocumentEvent +import javax.swing.event.DocumentListener +import javax.swing.event.TreeExpansionEvent +import javax.swing.event.TreeExpansionListener +import javax.swing.tree.DefaultMutableTreeNode +import javax.swing.tree.DefaultTreeModel +import javax.swing.tree.TreeModel +import javax.swing.tree.TreePath +import java.awt.event.FocusEvent +import java.awt.event.FocusListener +import java.awt.event.ItemEvent +import java.awt.event.ItemListener +import java.awt.event.KeyAdapter +import java.awt.event.KeyEvent +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent + +class SearchInConstantPoolsView { + static final int SEARCH_TYPE_TYPE = 1 + static final int SEARCH_TYPE_CONSTRUCTOR = 2 + static final int SEARCH_TYPE_METHOD = 4 + static final int SEARCH_TYPE_FIELD = 8 + static final int SEARCH_TYPE_STRING = 16 + static final int SEARCH_TYPE_DECLARATION = 32 + static final int SEARCH_TYPE_REFERENCE = 64 + + SwingBuilder swing + API api + Closure onTypeSelectedClosure + Set accepted + Set expanded + + SearchInConstantPoolsView( + SwingBuilder swing, Configuration configuration, API api, + Closure onPatternChangedClosure, + Closure onTypeSelectedClosure) { + this.swing = swing + this.api = api + this.onTypeSelectedClosure = onTypeSelectedClosure + // Create listeners + accepted = new HashSet<>() + expanded = new HashSet<>() + // Load GUI description + swing.edt { + // Setup + registerBeanFactory('tree', Tree.class) + // Load GUI description + build(SearchInConstantPoolsDescription) + searchInConstantPoolsDialog.with { + rootPane.with { + defaultButton = searchInConstantPoolsOkButton + getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "SearchInConstantPoolsView.cancel") + actionMap.put("SearchInConstantPoolsView.cancel", searchInConstantPoolsCancelAction) + } + minimumSize = size + searchInConstantPoolsEnterTextField.addKeyListener(new KeyAdapter() { + void keyTyped(KeyEvent e) { + switch (e.keyChar) { + case '=': case '(': case ')': case '{': case '}': case '[': case ']': + e.consume() + break + default: + if (Character.isDigit(e.keyChar) && (swing.searchInConstantPoolsEnterTextField.text.length() == 0)) { + // First character can not be a digit + e.consume() + } + break + } + } + void keyPressed(KeyEvent e) { + if (e.keyCode == KeyEvent.VK_DOWN) { + swing.edt { + def root = searchInConstantPoolsTree.model.root + if (root.childCount > 0) { + searchInConstantPoolsTree.requestFocus() + if (searchInConstantPoolsTree.selectionCount == 0) { + searchInConstantPoolsTree.selectionPath = new TreePath(root.getChildAt(0).path) + } + e.consume() + } + } + } + } + }) + searchInConstantPoolsEnterTextField.addFocusListener(new FocusListener() { + void focusGained(FocusEvent e) { + swing.edt { + searchInConstantPoolsTree.clearSelection() + searchInConstantPoolsOpenAction.enabled = false + } + } + void focusLost(FocusEvent e) {} + }) + searchInConstantPoolsEnterTextField.document.addDocumentListener(new DocumentListener() { + void insertUpdate(DocumentEvent e) { call() } + void removeUpdate(DocumentEvent e) { call() } + void changedUpdate(DocumentEvent e) { call() } + void call() { onPatternChangedClosure(swing.searchInConstantPoolsEnterTextField.text, flags) } + }) + + def checkBoxListener = new ItemListener() { + void itemStateChanged(ItemEvent e) { + onPatternChangedClosure(swing.searchInConstantPoolsEnterTextField.text, flags) + swing.searchInConstantPoolsEnterTextField.requestFocus() + } + } + + searchInConstantPoolsCheckBoxType.addItemListener(checkBoxListener) + searchInConstantPoolsCheckBoxField.addItemListener(checkBoxListener) + searchInConstantPoolsCheckBoxConstructor.addItemListener(checkBoxListener) + searchInConstantPoolsCheckBoxMethod.addItemListener(checkBoxListener) + searchInConstantPoolsCheckBoxString.addItemListener(checkBoxListener) + searchInConstantPoolsCheckBoxDeclarations.addItemListener(checkBoxListener) + searchInConstantPoolsCheckBoxReferences.addItemListener(checkBoxListener) + + searchInConstantPoolsTree.showsRootHandles = true + searchInConstantPoolsTree.addKeyListener(new KeyAdapter() { + void keyPressed(KeyEvent e) { + if (e.keyCode == KeyEvent.VK_UP) { + swing.edt { + if (searchInConstantPoolsTree.leadSelectionRow == 0) { + searchInConstantPoolsEnterTextField.requestFocus() + e.consume() + } + } + } + } + }) + searchInConstantPoolsTree.model = new DefaultTreeModel(new DefaultMutableTreeNode()) + searchInConstantPoolsTree.cellRenderer = new TreeNodeRenderer() + searchInConstantPoolsTree.addMouseListener(new MouseAdapter() { + void mouseClicked(MouseEvent e) { + if (e.clickCount == 2) { + def node = e.source.lastSelectedPathComponent + if (node) { + onTypeSelectedClosure(node.uri, swing.searchInConstantPoolsEnterTextField.text, flags) + } + } + } + }) + searchInConstantPoolsTree.addFocusListener(new FocusListener() { + void focusGained(FocusEvent e) { + swing.edt { + searchInConstantPoolsOpenAction.enabled = searchInConstantPoolsTree.selectionCount > 0 + } + } + void focusLost(FocusEvent e) {} + }) + searchInConstantPoolsTree.addTreeExpansionListener(new TreeExpansionListener() { + void treeExpanded(TreeExpansionEvent e) { + populate(e.source.model, e.path.lastPathComponent) + } + void treeCollapsed(TreeExpansionEvent e) {} + }) + searchInConstantPoolsOpenAction.closure = { onTypeSelected(searchInConstantPoolsTree) } + pack() + } + } + } + + void populate(TreeModel model, DefaultMutableTreeNode node) { + // Populate node + populate(node) + // Populate children + int i = node.childCount + while (i-- > 0) { + def child = node.getChildAt(i) + if ((child instanceof TreeNodeExpandable) && !expanded.contains(child.uri)) { + populate(child) + } + } + // Refresh + model.reload(node) + } + + void populate(DefaultMutableTreeNode node) { + if ((node instanceof TreeNodeExpandable) && !expanded.contains(node.uri)) { + // Populate + node.populateTreeNode(api) + expanded.add(node.uri) + // Filter + int i = node.childCount + while (i-- > 0) { + if (!accepted.contains(node.getChildAt(i).uri)) { + node.remove(i) + } + } + } + } + + void show() { + swing.doLater { + swing.searchInConstantPoolsEnterTextField.selectAll() + // Show + searchInConstantPoolsDialog.locationRelativeTo = searchInConstantPoolsDialog.parent + searchInConstantPoolsDialog.visible = true + searchInConstantPoolsEnterTextField.requestFocus() + } + } + + boolean isVisible() { swing.searchInConstantPoolsDialog.visible } + + String getPattern() { swing.searchInConstantPoolsEnterTextField.text } + + int getFlags() { + int flags = 0 + + if (swing.searchInConstantPoolsCheckBoxType.selected) + flags += SEARCH_TYPE_TYPE + if (swing.searchInConstantPoolsCheckBoxConstructor.selected) + flags += SEARCH_TYPE_CONSTRUCTOR + if (swing.searchInConstantPoolsCheckBoxMethod.selected) + flags += SEARCH_TYPE_METHOD + if (swing.searchInConstantPoolsCheckBoxField.selected) + flags += SEARCH_TYPE_FIELD + if (swing.searchInConstantPoolsCheckBoxString.selected) + flags += SEARCH_TYPE_STRING + if (swing.searchInConstantPoolsCheckBoxDeclarations.selected) + flags += SEARCH_TYPE_DECLARATION + if (swing.searchInConstantPoolsCheckBoxReferences.selected) + flags += SEARCH_TYPE_REFERENCE + + return flags + } + + void updateTree(Collection containers, int matchingTypeCount) { + swing.doLater { + def model = searchInConstantPoolsTree.model + def root = model.root + + // Reset tree nodes + root.removeAllChildren() + + accepted.clear() + expanded.clear() + + if (containers) { + containers.sort { c1, c2 -> + c1.root.uri.compareTo(c2.root.uri) + }.each { container -> + // Init uri set + accepted.addAll(container.uris) + // Populate tree + def parentEntry = container.root.parent + root.add(api.getTreeNodeFactory(parentEntry)?.make(api, parentEntry)) + } + + // Expand node and find the first leaf + def node = root + while (true) { + populate(model, node) + if (node.childCount == 0) { + break + } + node = node.getChildAt(0) + } + searchInConstantPoolsTree.selectionPath = new TreePath(node.path) + } else { + model.reload() + } + + // Update matching item counter + switch (matchingTypeCount) { + case 0: + searchInConstantPoolsLabel.text = 'Matching types:' + break + case 1: + searchInConstantPoolsLabel.text = '1 matching type:' + break + default: + searchInConstantPoolsLabel.text = matchingTypeCount + ' matching types:' + } + } + } + + void onTypeSelected(JTree searchInConstantPoolsTree) { + def selectedTreeNode = searchInConstantPoolsTree.lastSelectedPathComponent + if (selectedTreeNode) { + onTypeSelectedClosure(selectedTreeNode.uri, swing.searchInConstantPoolsEnterTextField.text, flags) + } + } +} diff --git a/app/src/main/groovy/jd/gui/view/SelectLocationView.groovy b/app/src/main/groovy/jd/gui/view/SelectLocationView.groovy new file mode 100644 index 00000000..4f1648bd --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/SelectLocationView.groovy @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view + +import groovy.swing.SwingBuilder +import jd.gui.api.API +import jd.gui.api.feature.TreeNodeExpandable +import jd.gui.model.configuration.Configuration +import jd.gui.model.container.FilteredContainerWrapper +import jd.gui.view.component.Tree +import jd.gui.view.renderer.TreeNodeRenderer + +import javax.swing.AbstractAction +import javax.swing.JComponent +import javax.swing.JDialog +import javax.swing.JLabel +import javax.swing.JPanel +import javax.swing.JTree +import javax.swing.KeyStroke +import javax.swing.UIManager +import javax.swing.border.EmptyBorder +import javax.swing.border.LineBorder +import javax.swing.tree.DefaultMutableTreeNode +import javax.swing.tree.DefaultTreeModel +import javax.swing.tree.TreePath +import java.awt.BorderLayout +import java.awt.Color +import java.awt.Dimension +import java.awt.Point +import java.awt.event.ActionEvent +import java.awt.event.FocusAdapter +import java.awt.event.FocusEvent +import java.awt.event.KeyEvent +import java.awt.event.KeyListener +import java.awt.event.MouseEvent +import java.awt.event.MouseListener +import java.awt.event.WindowAdapter +import java.awt.event.WindowEvent + +class SelectLocationView { + SwingBuilder swing + API api + + TreeListener treeListener + DialogClosedListener dialogClosedListener + + JDialog selectLocationDialog + JLabel selectLocationLabel + Tree selectLocationTree + + SelectLocationView(SwingBuilder swing, Configuration configuration, API api) { + this.swing = swing + this.api = api + // Load GUI description + this.treeListener = new TreeListener() + this.dialogClosedListener = new DialogClosedListener() + + Color bg = UIManager.getColor('ToolTip.background') + + selectLocationLabel = new JLabel() + selectLocationLabel.border = new EmptyBorder(5, 5, 0, 5) + + selectLocationTree = new Tree() + selectLocationTree.with { + border = new EmptyBorder(5, 5, 5, 5) + opaque = false + model = new DefaultTreeModel(new DefaultMutableTreeNode()) + cellRenderer = new TreeNodeRenderer() + addKeyListener(treeListener) + addMouseListener(treeListener) + } + + def selectLocationPanel = new JPanel(new BorderLayout()) + selectLocationPanel.with { + border = new LineBorder(bg.darker()) + background = bg + add(selectLocationLabel, BorderLayout.NORTH) + add(selectLocationTree, BorderLayout.CENTER) + } + + selectLocationDialog = new JDialog(swing.mainFrame, '', false) + selectLocationDialog.with { + undecorated = true + add(selectLocationPanel) + rootPane.with { + getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), 'SelectLocationView.closeClosure') + actionMap.put('SelectLocationView.closeClosure', new AbstractAction() { + void actionPerformed(ActionEvent e) { selectLocationDialog.visible = false } + }) + } + addWindowListener(dialogClosedListener) + } + + selectLocationTree.addFocusListener(new FocusAdapter() { + void focusLost(FocusEvent e) { selectLocationDialog.visible = false } + }) + } + + void show(Point location, Collection containers, int locationCount, Closure entrySelectedClosure, Closure closeClosure) { + swing.doLater { + treeListener.entrySelectedClosure = entrySelectedClosure + dialogClosedListener.closeClosure = closeClosure + + selectLocationTree.with { + def root = model.root + + // Reset tree nodes + root.removeAllChildren() + + containers.sort { c1, c2 -> + c1.root.uri.compareTo(c2.root.uri) + }.each { container -> + def parentEntry = container.root.parent + def node = api.getTreeNodeFactory(parentEntry)?.make(api, parentEntry) + + if (node) { + root.add(node) + populate(container.uris, node) + } + } + + model.reload() + + // Expand all nodes + for (int row = 0; row < getRowCount(); row++) { + expandRow(row) + } + + // Select first leaf + def node = root + while (true) { + if (node.childCount == 0) { + break + } + node = node.getChildAt(0) + } + selectionPath = new TreePath(node.path) + + // Reset preferred size + preferredSize = null + + // Resize + Dimension ps = preferredSize + if (ps.width < 200) + ps.width = 200 + if (ps.height < 50) + ps.height = 50 + preferredSize = ps + } + + // Update label + selectLocationLabel.text = '' + locationCount + ' locations:' + + selectLocationDialog.with { + pack() + setLocation(location) + visible = true + } + + selectLocationTree.requestFocus() + } + } + + void populate(Set uris, DefaultMutableTreeNode node) { + if (node instanceof TreeNodeExpandable) { + node.populateTreeNode(api) + + int i = node.childCount + + while (i-- > 0) { + def child = node.getChildAt(i) + + if (uris.contains(child.uri)) { + populate(uris, child) + } else { + node.remove(i) + } + } + } + } + + class TreeListener implements KeyListener, MouseListener { + Closure entrySelectedClosure + + void callClosure(JTree tree) { + def node = tree.lastSelectedPathComponent + if (node) { + selectLocationDialog.visible = false + entrySelectedClosure(node.uri) + } + } + + // --- KeyListener --- // + void keyPressed(KeyEvent e) { + if (e.keyCode == KeyEvent.VK_ENTER) { + callClosure(e.source) + } + } + + void keyTyped(KeyEvent e) {} + void keyReleased(KeyEvent e) {} + + // --- MouseListener --- // + void mouseClicked(MouseEvent e) { + if (e.clickCount == 2) { + callClosure(e.source) + } + } + + void mousePressed(MouseEvent e) {} + void mouseReleased(MouseEvent e) {} + void mouseEntered(MouseEvent e) {} + void mouseExited(MouseEvent e) {} + } + + class DialogClosedListener extends WindowAdapter { + Closure closeClosure + + void windowDeactivated(WindowEvent e) { closeClosure() } + } +} diff --git a/app/src/main/groovy/jd/gui/view/bean/OpenTypeListCellBean.groovy b/app/src/main/groovy/jd/gui/view/bean/OpenTypeListCellBean.groovy new file mode 100644 index 00000000..0f927559 --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/bean/OpenTypeListCellBean.groovy @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view.bean + +import jd.gui.api.model.Container + +import javax.swing.* + +class OpenTypeListCellBean { + String label + String packag + Icon icon + Collection entries + String typeName +} diff --git a/app/src/main/groovy/jd/gui/view/component/IconButton.groovy b/app/src/main/groovy/jd/gui/view/component/IconButton.groovy new file mode 100644 index 00000000..264e094a --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/component/IconButton.groovy @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view.component + +import java.awt.Insets + +import javax.swing.JButton + +class IconButton extends JButton { + + IconButton() { + focusPainted = false + margin = new Insets(0, 0, 0, 0) + } +} diff --git a/app/src/main/groovy/jd/gui/view/component/List.groovy b/app/src/main/groovy/jd/gui/view/component/List.groovy new file mode 100644 index 00000000..2fc2b13f --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/component/List.groovy @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view.component + +import jd.gui.api.model.TreeNodeData +import sun.swing.DefaultLookup + +import javax.swing.BorderFactory +import javax.swing.JLabel +import javax.swing.JList +import javax.swing.KeyStroke +import javax.swing.ListCellRenderer +import java.awt.Color +import java.awt.Component +import java.awt.Insets +import java.awt.Toolkit +import java.awt.event.KeyEvent + +class List extends JList { + + List() { + super() + + def ctrlA = KeyStroke.getKeyStroke(KeyEvent.VK_A, Toolkit.defaultToolkit.menuShortcutKeyMask) + def ctrlC = KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.defaultToolkit.menuShortcutKeyMask) + def ctrlV = KeyStroke.getKeyStroke(KeyEvent.VK_V, Toolkit.defaultToolkit.menuShortcutKeyMask) + + inputMap.put(ctrlA, 'none') + inputMap.put(ctrlC, 'none') + inputMap.put(ctrlV, 'none') + setCellRenderer(new Renderer()) + } + + class Renderer implements ListCellRenderer { + Color textSelectionColor + Color backgroundSelectionColor + Color textNonSelectionColor + Color backgroundNonSelectionColor + + JLabel label + + Renderer() { + label = new JLabel() + label.opaque = true + + textSelectionColor = DefaultLookup.getColor(label, ui, "List.dropCellForeground"); + backgroundSelectionColor = DefaultLookup.getColor(label, ui, "List.dropCellBackground"); + textNonSelectionColor = DefaultLookup.getColor(label, ui, "List.foreground"); + backgroundNonSelectionColor = DefaultLookup.getColor(label, ui, "List.background"); + Insets margins = DefaultLookup.getInsets(label, label.ui, "List.contentMargins") + + if (textSelectionColor == null) + textSelectionColor = List.this.getSelectionForeground() + if (backgroundSelectionColor == null) + backgroundSelectionColor = List.this.getSelectionBackground() + + if (margins) { + label.border = BorderFactory.createEmptyBorder(margins.top, margins.left, margins.bottom, margins.right) + } else { + label.border = BorderFactory.createEmptyBorder(0, 2, 1, 2) + } + } + + Component getListCellRendererComponent( + JList list, Object value, + int index, boolean selected, boolean hasFocus) { + def data = value.userObject + + if (data instanceof TreeNodeData) { + label.icon = data.icon + + + label.text = data.label + + + } else { + label.icon = null + label.text = '' + data + } + + if (selected) { + label.foreground = textSelectionColor + label.background = backgroundSelectionColor + } else { + label.foreground = textNonSelectionColor + label.background = backgroundNonSelectionColor + } + + return label + } + } +} diff --git a/app/src/main/groovy/jd/gui/view/component/Tree.groovy b/app/src/main/groovy/jd/gui/view/component/Tree.groovy new file mode 100644 index 00000000..800cff3a --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/component/Tree.groovy @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view.component + +import javax.swing.* +import java.awt.* +import java.awt.event.KeyEvent + +class Tree extends JTree { + Tree() { + def ctrlA = KeyStroke.getKeyStroke(KeyEvent.VK_A, Toolkit.defaultToolkit.menuShortcutKeyMask) + def ctrlC = KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.defaultToolkit.menuShortcutKeyMask) + def ctrlV = KeyStroke.getKeyStroke(KeyEvent.VK_V, Toolkit.defaultToolkit.menuShortcutKeyMask) + + inputMap.put(ctrlA, 'none') + inputMap.put(ctrlC, 'none') + inputMap.put(ctrlV, 'none') + rootVisible = false + } +} diff --git a/app/src/main/groovy/jd/gui/view/component/panel/MainTabbedPanel.groovy b/app/src/main/groovy/jd/gui/view/component/panel/MainTabbedPanel.groovy new file mode 100644 index 00000000..63a08779 --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/component/panel/MainTabbedPanel.groovy @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view.component.panel + +import jd.gui.api.feature.PageChangeListener +import jd.gui.api.feature.PageChangeable +import jd.gui.api.feature.UriGettable +import jd.gui.api.feature.UriOpenable + +import javax.swing.Icon +import javax.swing.JComponent +import javax.swing.event.ChangeEvent +import javax.swing.event.ChangeListener +import java.awt.CardLayout +import java.awt.Color +import java.awt.Font +import javax.swing.BorderFactory +import javax.swing.Box +import javax.swing.BoxLayout +import javax.swing.JLabel +import javax.swing.JPanel + +import jd.gui.service.platform.PlatformService + +class MainTabbedPanel extends TabbedPanel implements UriOpenable, PageChangeListener { + List pageChangedListeners = [] + + void create() { + Color bg = darker(background) + + if (PlatformService.instance.isWindows) { + background = bg + } + + tabbedPane = createTabPanel() + tabbedPane.addChangeListener(new ChangeListener() { + void stateChanged(ChangeEvent e) { + def page = tabbedPane.selectedComponent?.getClientProperty('currentPage') + + if (page == null) { + page = tabbedPane.selectedComponent + } + + // Notify all container pages are closeClosure + for (def listener : pageChangedListeners) { + listener.pageChanged(page) + } + } + }) + + setLayout(new CardLayout()) + add('panel', createPanel(bg)) + add('tabs', tabbedPane) + + border = BorderFactory.createMatteBorder(1, 0, 0, 0, darker(darker(background))) + } + + JPanel createPanel(Color background) { + JPanel panel = new JPanel() + + String fileManager + + switch (PlatformService.instance.os) { + case PlatformService.OS.Linux: + fileManager = 'your file manager' + break + case PlatformService.OS.MacOSX: + fileManager = 'the Finder' + break + case PlatformService.OS.Windows: + fileManager = 'Explorer' + break + } + + panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)) + panel.background = background + + Color fontColor = panel.background.darker() + + panel.add(Box.createHorizontalGlue()) + + JPanel box = new JPanel() + box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS)) + box.background = panel.background + box.add(Box.createVerticalGlue()) + + JLabel title = new JLabel(text:'No files are open', foreground:fontColor) + title.font = title.font.deriveFont(Font.BOLD, title.font.size+8) + + box.add(title) + box.add(new JLabel()) + box.add(new JLabel(text:'Open a file with menu "File > Open File..."', foreground:fontColor)) + box.add(new JLabel(text:'Open recent files with menu "File > Recent Files"', foreground:fontColor)) + box.add(new JLabel(text:'Drag and drop files from ' + fileManager, foreground:fontColor)) + box.add(Box.createVerticalGlue()) + + panel.add(box) + panel.add(Box.createHorizontalGlue()) + + return panel + } + + public void addPage(String title, Icon icon, String tip, T page) { + super.addPage(title, icon, tip, page) + if (page instanceof PageChangeable) { + page.addPageChangeListener(this) + } + } + + public List getPages() { + int i = tabbedPane.getTabCount() + def pages = new ArrayList(i) + while (i-- > 0) { + pages.add(tabbedPane.getComponentAt(i)) + } + return pages + } + + // --- URIOpener --- // + boolean openUri(URI uri) { + def page = showPage(uri) + if (page) { + if (page instanceof UriOpenable) { + page.openUri(uri) + } + return true + } else { + return false + } + } + + // --- PageChangedListener --- // + public void pageChanged(T page) { + // Store active page for current tabbed pane + tabbedPane.selectedComponent?.putClientProperty('currentPage', page) + // Forward event + for (def listener : pageChangedListeners) { + listener.pageChanged(page) + } + } +} diff --git a/app/src/main/groovy/jd/gui/view/component/panel/TabbedPanel.groovy b/app/src/main/groovy/jd/gui/view/component/panel/TabbedPanel.groovy new file mode 100644 index 00000000..14ca5d43 --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/component/panel/TabbedPanel.groovy @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view.component.panel + +import jd.gui.api.feature.UriGettable +import jd.gui.service.platform.PlatformService + +import javax.swing.JComponent +import javax.swing.JMenuItem +import javax.swing.JPopupMenu +import javax.swing.ToolTipManager +import java.awt.BorderLayout +import java.awt.CardLayout +import java.awt.Color +import java.awt.Component +import java.awt.event.ActionEvent +import java.awt.event.ActionListener + +import javax.swing.BorderFactory +import javax.swing.Icon +import javax.swing.ImageIcon +import javax.swing.JLabel +import javax.swing.JPanel +import javax.swing.JTabbedPane +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent +import java.awt.event.MouseListener + +class TabbedPanel extends JPanel { + static final ImageIcon closeIcon = new ImageIcon(TabbedPanel.class.classLoader.getResource('images/close.gif')) + static final ImageIcon closeActivateIcon = new ImageIcon(TabbedPanel.class.classLoader.getResource('images/close_active.gif')) + + JTabbedPane tabbedPane + + TabbedPanel() { + create() + } + + void create() { + setLayout(new CardLayout()) + add('panel', createPanel(background)) + add('tabs', tabbedPane = createTabPanel()) + } + + JPanel createPanel(Color background) { + return new JPanel() + } + + JTabbedPane createTabPanel() { + JTabbedPane tabPanel = new JTabbedPane() { + String getToolTipText(MouseEvent e) { + int index = indexAtLocation(e.x, e.y) + if (index != -1) { + return getTabComponentAt(index).toolTipText + } + return super.getToolTipText(e) + } + } + ToolTipManager.sharedInstance().registerComponent(tabPanel) + tabPanel.addMouseListener(new MouseAdapter() { + void mousePressed(MouseEvent e) { showPopupTabMenu(e) } + void mouseReleased(MouseEvent e) { showPopupTabMenu(e) } + void showPopupTabMenu(MouseEvent e) { + if (e.isPopupTrigger()) { + int index = tabPanel.indexAtLocation(e.x, e.y) + if (index != -1) { + new PopupTabMenu(tabPanel.getComponentAt(index)).show(e.component, e.x, e.y) + } + } + } + }) + return tabPanel + } + + static Color darker(Color c) { + return new Color( + Math.max((int)(c.red *0.85), 0), + Math.max((int)(c.green*0.85), 0), + Math.max((int)(c.blue *0.85), 0), + c.alpha) + } + + public void addPage(String title, Icon icon, String tip, T page) { + JLabel tabCloseButton = new JLabel(closeIcon) + tabCloseButton.toolTipText = 'Close this panel' + tabCloseButton.addMouseListener(new MouseListener() { + void mousePressed(MouseEvent e) {} + void mouseReleased(MouseEvent e) {} + void mouseEntered(MouseEvent e) { e.source.icon = closeActivateIcon } + void mouseExited(MouseEvent e) { e.source.icon = closeIcon } + void mouseClicked(MouseEvent e) { removeComponent(page) } + }) + + JPanel tab = new JPanel(new BorderLayout()) + if (PlatformService.instance.isMac) { + tab.border = BorderFactory.createEmptyBorder(2, 0, 3, 0) + } else { + tab.border = BorderFactory.createEmptyBorder(1, 0, 1, 0) + } + tab.opaque = false + tab.toolTipText = tip + // Show label and icon: panel.add(new JLabel(title, icon, JLabel.LEADING), BorderLayout.CENTER) + tab.add(new JLabel(title), BorderLayout.CENTER) + tab.add(tabCloseButton, BorderLayout.EAST) + ToolTipManager.sharedInstance().unregisterComponent(tab) + + int index = tabbedPane.getTabCount() + tabbedPane.addTab(title, page) + tabbedPane.setTabComponentAt(index, tab) + tabbedPane.selectedIndex = index + + getLayout().show(this, 'tabs') + } + + Object showPage(URI uri) { + def u1 = uri.toString() + int i = tabbedPane.getTabCount() + + while (i-- > 0) { + def page = tabbedPane.getComponentAt(i) + def u2 = page.uri.toString() + if (u1.startsWith(u2)) { + tabbedPane.setSelectedIndex(i) + return page + } + } + + return null + } + + class PopupTabMenu extends JPopupMenu { + PopupTabMenu(Component component) { + def menuItem = new JMenuItem('Close', null) + menuItem.addActionListener(new ActionListener() { + void actionPerformed(ActionEvent e) { removeComponent(component) } + }) + add(menuItem) + + menuItem = new JMenuItem('Close Others', null) + menuItem.addActionListener(new ActionListener() { + void actionPerformed(ActionEvent e) { removeOtherComponents(component) } + }) + add(menuItem) + + menuItem = new JMenuItem('Close All', null) + menuItem.addActionListener(new ActionListener() { + void actionPerformed(ActionEvent e) { removeAllComponents() } + }) + add(menuItem) + } + } + + // --- Popup menu actions --- // + void removeComponent(Component component) { + tabbedPane.remove(component) + if (tabbedPane.tabCount == 0) { + getLayout().show(this, 'panel') + } + } + + void removeOtherComponents(Component component) { + int i = tabbedPane.tabCount + while (i-- > 0) { + def c = tabbedPane.getComponentAt(i) + if (c != component) { + tabbedPane.remove(i) + } + } + if (tabbedPane.tabCount == 0) { + getLayout().show(this, 'panel') + } + } + + void removeAllComponents() { + tabbedPane.removeAll() + if (tabbedPane.tabCount == 0) { + getLayout().show(this, 'panel') + } + } +} diff --git a/app/src/main/groovy/jd/gui/view/component/panel/TreeTabbedPanel.groovy b/app/src/main/groovy/jd/gui/view/component/panel/TreeTabbedPanel.groovy new file mode 100644 index 00000000..af19b27f --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/component/panel/TreeTabbedPanel.groovy @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view.component.panel + +import jd.gui.api.API +import jd.gui.api.feature.PageChangeListener +import jd.gui.api.feature.PageChangeable +import jd.gui.api.feature.PageClosable +import jd.gui.api.feature.TreeNodeExpandable +import jd.gui.api.feature.UriGettable +import jd.gui.api.model.TreeNodeData +import jd.gui.api.feature.PageCreator +import jd.gui.api.feature.UriOpenable +import jd.gui.view.component.Tree +import jd.gui.view.renderer.TreeNodeRenderer + +import javax.swing.* +import javax.swing.event.ChangeEvent +import javax.swing.event.ChangeListener +import javax.swing.event.TreeExpansionEvent +import javax.swing.event.TreeExpansionListener +import javax.swing.event.TreeSelectionEvent +import javax.swing.event.TreeSelectionListener +import javax.swing.tree.DefaultMutableTreeNode +import javax.swing.tree.TreePath +import java.awt.* +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent +import java.util.List + +class TreeTabbedPanel extends JPanel implements UriGettable, UriOpenable, PageChangeable, PageClosable { + API api + URI uri + Tree tree + TabbedPanel tabbedPanel + List pageChangedListeners = [] + + TreeTabbedPanel(API api, URI uri) { + this.api = api + this.uri = uri + + tree = new Tree() + tree.showsRootHandles = true + tree.setMinimumSize([150, 10] as Dimension) + tree.expandsSelectedPaths = true + tree.cellRenderer = new TreeNodeRenderer() + tree.addTreeSelectionListener(new TreeSelectionListener() { + void valueChanged(TreeSelectionEvent e) { + def path = tree.lastSelectedPathComponent + if (path) { + showPage(path) + } + } + }) + tree.addMouseListener(new MouseAdapter() { + void mouseClicked(MouseEvent e) { + TreePath path = tree.getPathForLocation(e.x, e.y) + if (path) { + showPage(path.lastPathComponent) + } + } + }) + tree.addTreeExpansionListener(new TreeExpansionListener() { + void treeExpanded(TreeExpansionEvent e) { + def node = e.path.lastPathComponent + if (node instanceof TreeNodeExpandable) { + def oldList = node.children().toList() + node.populateTreeNode(api); + def newList = node.children().toList() + if (! oldList.equals(newList)) { + tree.model.reload(node) + } + } + } + void treeCollapsed(TreeExpansionEvent e) {} + }) + + tabbedPanel = new TabbedPanel() + tabbedPanel.setMinimumSize([150, 10] as Dimension) + tabbedPanel.tabbedPane.addChangeListener(new ChangeListener() { + void stateChanged(ChangeEvent e) { pageChanged() } + }) + + layout = new BorderLayout() + + JSplitPane splitter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(tree), tabbedPanel) + splitter.resizeWeight = 0.2 + + add(splitter, BorderLayout.CENTER) + } + + protected void showPage(T node) { + // Search base tree node + def uri = node.uri + + if ((uri.fragment == null) && (uri.query == null)) { + showPage(uri, uri, node) + } else { + def baseUri = new URI(uri.scheme, uri.host, uri.path, null) + def baseNode = node + + while (!baseNode?.uri.equals(baseUri)) { + baseNode = baseNode.parent + } + + if (baseNode?.uri.equals(baseUri)) { + showPage(uri, baseUri, baseNode) + } + } + } + + protected boolean showPage(URI uri, URI baseUri, DefaultMutableTreeNode baseNode) { + def page = tabbedPanel.showPage(baseUri) + + if ((page == null) && (baseNode instanceof PageCreator)) { + page = baseNode.createPage(api) + page.putClientProperty('node', baseNode) + page.putClientProperty('preferences-stamp', Integer.valueOf(api.preferences.hashCode())) + page.putClientProperty('collectionOfIndexes-stamp', Integer.valueOf(api.collectionOfIndexes.hashCode())) + + def path = baseUri.path + def label = path.substring(path.lastIndexOf('/')+1) + def data = baseNode.userObject + + if (data instanceof TreeNodeData) { + tabbedPanel.addPage(label, data.icon, data.tip, page) + } else { + tabbedPanel.addPage(label, null, null, page) + } + } + + if (page instanceof UriOpenable) { + api.addURI(uri) + page.openUri(uri) + } + + return (page != null) + } + + void pageChanged() { + def page = tabbedPanel.tabbedPane.selectedComponent + // Synchronize tree + if (page) { + def node = page.getClientProperty('node') + // Select tree node + tree.selectionPath = node.path + tree.scrollPathToVisible(tree.selectionPath) + } else { + tree.clearSelection() + } + // Fire page changed event + for (def listener : pageChangedListeners) { + listener.pageChanged(page) + } + } + + // --- URIGetter --- // + URI getUri() { uri } + + // --- URIOpener --- // + boolean openUri(URI uri) { + def baseUri = new URI(uri.scheme, uri.host, uri.path, null) + def baseNode = searchTreeNode(baseUri, tree.model.root) + + if (baseNode && showPage(uri, baseUri, baseNode)) { + def node = searchTreeNode(uri, baseNode) + if (node) { + // Select tree node + tree.selectionPath = node.path + tree.scrollPathToVisible(tree.selectionPath) + } + return true + } + return false + } + + protected DefaultMutableTreeNode searchTreeNode(URI uri, DefaultMutableTreeNode node) { + if (node instanceof TreeNodeExpandable) { + node.populateTreeNode(api) + } + + def u = uri.toString() + def child = node.children().find { u.startsWith(it.uri.toString()) } + + if (child) { + if (u.equals(child.uri.toString())) { + return child + } else { + // Parent tree node found -> Recursive call + return searchTreeNode(uri, child) + } + } else { + // Not found + return null + } + } + + // --- PageChanger --- // + void addPageChangeListener(PageChangeListener listener) { + pageChangedListeners.add(listener) + } + + // --- PageCloser --- // + boolean closePage() { + def component = tabbedPanel.tabbedPane.selectedComponent + if (component) { + tabbedPanel.removeComponent(component) + return true + } else { + return false + } + } +} diff --git a/app/src/main/groovy/jd/gui/view/renderer/OpenTypeListCellRenderer.groovy b/app/src/main/groovy/jd/gui/view/renderer/OpenTypeListCellRenderer.groovy new file mode 100644 index 00000000..b71f5888 --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/renderer/OpenTypeListCellRenderer.groovy @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view.renderer + +import jd.gui.view.bean.OpenTypeListCellBean + +import javax.swing.JLabel +import javax.swing.JList +import javax.swing.JPanel +import javax.swing.ListCellRenderer +import javax.swing.UIManager +import java.awt.BorderLayout +import java.awt.Color +import java.awt.Component + +class OpenTypeListCellRenderer implements ListCellRenderer { + Color textSelectionColor + Color textNonSelectionColor + Color infoSelectionColor + Color infoNonSelectionColor + Color backgroundSelectionColor + Color backgroundNonSelectionColor + + JPanel panel + JLabel label, info + + StringBuffer sb = new StringBuffer() + + OpenTypeListCellRenderer() { + textSelectionColor = UIManager.getColor("List.selectionForeground") + textNonSelectionColor = UIManager.getColor("List.foreground") + backgroundSelectionColor = UIManager.getColor("List.selectionBackground") + backgroundNonSelectionColor = UIManager.getColor("List.background") + + infoSelectionColor = infoColor(textSelectionColor) + infoNonSelectionColor = infoColor(textNonSelectionColor) + + panel = new JPanel(new BorderLayout()) + panel.add(label = new JLabel(), BorderLayout.WEST) + panel.add(info = new JLabel(), BorderLayout.CENTER) + } + + static protected Color infoColor(Color c) { + if (c.red + c.green + c.blue > (3*127)) { + return new Color( + (int)((c.red-127) *0.7 + 127), + (int)((c.green-127)*0.7 + 127), + (int)((c.blue-127) *0.7 + 127), + c.alpha) + } else { + return new Color( + (int)(127 - (127-c.red) *0.7), + (int)(127 - (127-c.green)*0.7), + (int)(127 - (127-c.blue) *0.7), + c.alpha) + } + } + + Component getListCellRendererComponent( + JList list, OpenTypeListCellBean value, + int index, boolean selected, boolean hasFocus) { + + if (value) { + // Display first level item + label.text = value.label + label.icon = value.icon + + sb.setLength(0) + if (value.packag) { + sb.append(' - ').append(value.packag) + } + info.text = sb.toString() + + if (selected) { + label.foreground = textSelectionColor + info.foreground = infoSelectionColor + panel.background = backgroundSelectionColor + } else { + label.foreground = textNonSelectionColor + info.foreground = infoNonSelectionColor + panel.background = backgroundNonSelectionColor + } + } else { + label.text = ' ...' + label.icon = null + info.text = '' + label.foreground = textNonSelectionColor + panel.background = backgroundNonSelectionColor + } + + return panel + } +} diff --git a/app/src/main/groovy/jd/gui/view/renderer/TreeNodeRenderer.groovy b/app/src/main/groovy/jd/gui/view/renderer/TreeNodeRenderer.groovy new file mode 100644 index 00000000..10e98966 --- /dev/null +++ b/app/src/main/groovy/jd/gui/view/renderer/TreeNodeRenderer.groovy @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view.renderer + +import jd.gui.api.model.TreeNodeData + +import javax.swing.BorderFactory +import javax.swing.JLabel +import javax.swing.JPanel +import javax.swing.JTree +import javax.swing.UIManager +import javax.swing.tree.TreeCellRenderer +import java.awt.BorderLayout +import java.awt.Color +import java.awt.Component +import java.awt.Insets + +class TreeNodeRenderer implements TreeCellRenderer { + Color textSelectionColor + Color backgroundSelectionColor + Color textNonSelectionColor + Color backgroundNonSelectionColor + + JPanel panel + JLabel icon, label + + TreeNodeRenderer() { + panel = new JPanel(new BorderLayout()) + panel.add(icon = new JLabel(), BorderLayout.WEST) + panel.add(label = new JLabel(), BorderLayout.CENTER) + panel.opaque = false + + textSelectionColor = UIManager.getColor("Tree.selectionForeground") + backgroundSelectionColor = UIManager.getColor("Tree.selectionBackground") + textNonSelectionColor = UIManager.getColor("Tree.textForeground") + backgroundNonSelectionColor = UIManager.getColor("Tree.textBackground") + Insets margins = UIManager.getInsets("Tree.rendererMargins") + + icon.foreground = textNonSelectionColor + icon.opaque = label.opaque = false + icon.border = BorderFactory.createEmptyBorder(0, 0, 0, 2) + + label.background = backgroundSelectionColor + + if (margins) { + label.border = BorderFactory.createEmptyBorder(margins.top, margins.left, margins.bottom, margins.right) + } else { + label.border = BorderFactory.createEmptyBorder(0, 4, 0, 4) + } + } + + Component getTreeCellRendererComponent( + JTree tree, Object value, + boolean selected, boolean expanded, + boolean leaf, int row, boolean hasFocus) { + def data = value.userObject + + if (data instanceof TreeNodeData) { + icon.icon = expanded ? (data.openIcon ?: data.icon) : data.icon + label.text = data.label + } else { + icon.icon = null + label.text = '' + data + } + + if (selected) { + label.foreground = textSelectionColor + label.opaque = true + } else { + label.foreground = textNonSelectionColor + label.opaque = false + } + + return panel + } +} diff --git a/app/src/main/resources/META-INF/services/jd.gui.spi.PanelFactory b/app/src/main/resources/META-INF/services/jd.gui.spi.PanelFactory new file mode 100644 index 00000000..3751dfc2 --- /dev/null +++ b/app/src/main/resources/META-INF/services/jd.gui.spi.PanelFactory @@ -0,0 +1 @@ +jd.gui.service.mainpanel.ContainerPanelFactoryProvider diff --git a/app/src/main/resources/images/Icon_java_128.png b/app/src/main/resources/images/Icon_java_128.png new file mode 100644 index 0000000000000000000000000000000000000000..b29e5a9f921bf01909a187a0a0ecbbe5c3939730 GIT binary patch literal 14178 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 E1C>}A)c^nh literal 0 HcmV?d00001 diff --git a/app/src/main/resources/images/Icon_java_64.png b/app/src/main/resources/images/Icon_java_64.png new file mode 100644 index 0000000000000000000000000000000000000000..2e457df1fe17d9b63cef470857d719e39453ca47 GIT binary patch literal 5673 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 HN@xNA_?yv~ literal 0 HcmV?d00001 diff --git a/app/src/main/resources/images/close.gif b/app/src/main/resources/images/close.gif new file mode 100644 index 0000000000000000000000000000000000000000..17b75735821ec641eeaa248a3ac831868fef802b GIT binary patch literal 88 zcmZ?wbhEHb6krfwn8?IXn4j_=3>X*~6o0ZXGB7YP=m6P3Spgthb4vfp(`y+7S@c=7 m8jfCy+pD{v+%!3JQjF`OlN^<+8I!&W%T7N0y)KA>!5RRu%^e8< literal 0 HcmV?d00001 diff --git a/app/src/main/resources/images/close_active.gif b/app/src/main/resources/images/close_active.gif new file mode 100644 index 0000000000000000000000000000000000000000..8816521a86318b71da5a47372efb18bf767f4e09 GIT binary patch literal 88 zcmZ?wbhEHb6krfwSjfbXnVI=#!Gix_p!k!8k&A(eL5BedK=KSsnp65$o?go!$fD1p m)o}Du++N)U<)+D*lVV&Ko#d!o&6xC6Sa$N^?{z^84AuZcbsts$ literal 0 HcmV?d00001 diff --git a/app/src/main/resources/images/forward_nav.png b/app/src/main/resources/images/forward_nav.png new file mode 100644 index 0000000000000000000000000000000000000000..a6afdee3a9ca37c32ed41c0ecf8d90f43fa05c0f GIT binary patch literal 470 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMffdHQn*MEQC|NZ^!@AsSkem(p1 z>C`_UcI(f}6@T9D{QK$TU!eH6o4+6Q{CP6-_mi1_Uaa`@V&&hrJAdD8 z{sRqNFzi)^hC+0!Jpvq5xsli2D4!PSL=EAs@`mk6yb5?Y=k zuq<2P|Ns9$`>6uHK0CS|XplxpkY6y+SYiOfzEye>Ks}5}-tI2;cF6{%Kn`btM`SUO z_5fqIli7AaMzyDlV~E7%*7LXdnhbav9$L91YBR0vI8}J!;oticxMo-gJ>LK3+3p)r zGs+J7pZF{r60q|EgNgK&?0W}Si&wZ!l%L~&D!j33&q4Hq)$ literal 0 HcmV?d00001 diff --git a/app/src/main/resources/images/next_nav.png b/app/src/main/resources/images/next_nav.png new file mode 100644 index 0000000000000000000000000000000000000000..0328357942896a794cede49d02168af7922bd65b GIT binary patch literal 536 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMffdHQn*MrAywoYF6?Z=-VKYy3^ zY-yXa?)~RqozvDlee!V8em;2h=`>l~QZTh^$vlq-? zxMa?<6*E__n!0sE|HicwcW&z2e(n)oiD>38oLlSPsUr`posV z&bP0l+XkKV^JR{ literal 0 HcmV?d00001 diff --git a/app/src/main/resources/images/open.png b/app/src/main/resources/images/open.png new file mode 100644 index 0000000000000000000000000000000000000000..0430baaf50765aa5c313b3da35d3d2ad5092f2d0 GIT binary patch literal 498 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMffdHQn*Qt#iQyV)wt9y$IC&#DE zO-PxS03=iACa2GgPn{bUKQAz5aZv0c*U%NNVJp0%mbOkjVd=ltGGL8;$SMuD&3c|2 z^u0Ffdu=fFTRUm%n@QW=OxpT-(ze%gkA9ka?9;rXpXMF=wDQ`|l~;ePy!K<`!@s{? z&ii(M+W(J-{=eS*=3@8%r%V3d>iiEBxmf!DYVG5LwKq2vURYCcac$*=HI@It0O(RY z;D%)CX`r-ONswPKL_LWl!@_<)L!b$aN#5=*_IAkzr9cj6fk$L9koEv$x0Bg+Kt`vh zi(`ny<AEIQcD@AqbASA9v%ZozqTFR<<1)U%OUub!r|GDoxbkV1Kg(vdH~V1K>zun{_{es))rK)0iwc{CwhLonDOJoiJza& z|9G+C=j&a+KVSRx_R#P5CtqCX_;6#wj|Ve;JXrAKM#ql}6+eL73k~OITJ5UWIM}Ma zsZwKcy6oy)rCpU82kW(0r_0VslwX~zIwxAZ*I(p67yvyrM1koil`TN0JCy|a1w;Ho z0mVvgNO=tnSp*^X|C)c7kKy0Y#1`Nt0Kmr5U|zHga7z z;CX&pBWlKxZR$r_E>By`$~N7^_oZ9J$AZ3ODefBM3bhjTC$kTBs~t-J>@DAVDc}3v Yt`9m3?Bk3)f$nASboFyt=akR{0AlzWTL1t6 literal 0 HcmV?d00001 diff --git a/app/src/main/resources/images/prev_nav.png b/app/src/main/resources/images/prev_nav.png new file mode 100644 index 0000000000000000000000000000000000000000..830c2c990b07d4ebc67b5078bd6034410a197aa0 GIT binary patch literal 527 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMffdHQn*MrAye*5v~=dVBIJzL&? z{`K_DkKP$8Uw!!b;MI>uufMQz(!{e8c6L;uFL6L)Uz`S*?RGSN{Ec`uD@3zaI|&1G2wf{r#Zt z&(pcTpUnLYB=0u=dC<4FMQl&A*p@2cjTORMszkO_i|lC<+gUHVqh54(qu8!Sv6XoO zEAs@`mkO;d5?Ws>ygWx>S+>Cc|Nnt*hXZ%(sv022rX#w2fd z7kj&8gHj-ev%n*=7)X17vD?XPJ0N3$r;B5V#O2U)H-(xEcpNTrgj`s)LurvmEF)vN z>x=*Yr+Z4ezJH?nTv2$!ys+n{cp~_EfpZTqt|NsfrmEFWEzesPS{%^^nKMb zF2B<^A0QD~=pEylw54Evq+eT)uwo;?)Os@87p`@ABD8_io#>bJLDvhmM^*cJla<;|KR0 zJayvKk%LD)a~J;qfAatTfB(MpzIw3a_lM0duND7%x#|}Pt^ReZ_WS*LU$0L5a&^+z zD--YUt$(t}^5y#Q*PCM3_QmgO>_ z45U54*zIJt9gs1>)5S4F;&N>NOQAywJS~rF?`NzG)t=`&wW{IT_j;p+7iMPEJ-wZh zR{rp_xkK5?&0joND*G0taZM4Ip2+xg>y1o>{~K?pU*hbzKKr4w(p>IMC-?l{P@dl1 z(_6jx)#**50)<|#8fySEhN;8)B9K!ZR50DS-c9RL6f21EQ9 z85yy*w*HR6h!Fo;TZ@Q@U;q&eX2hDPj*MVNMnpu2$B82G1k8645#smn7~=O4Yk+uw zNPiz8Ha9{fe*6;K5+Sxf@*P7w)0%j)HBtK^ekV3)Z4D5c9wB}b4PY=tn#lbyNj&@= zGXjVZTNELh0f;7v{}T@$T_^EU|L2F}JH>5TElug0YO}Rp&eE)Vj3SXP~j1gQPDB6aq$U>Ny+yi=rl}vMrKxa4i=Z2mtRm=RE#ev zEi?has;X;h>*^aCo0?l%+uA!iyB>D;^tOX4QV2te1IDAnjh zmlju1E86R8TY;OJFSd8@zfynm`n~5n)sG)OJ0GZg`vOdUHM}g0eRv6)#3ea6&Ri2l zwJ0EY`BJW|*IyUy1vIPW2V&UitxqZ>4i9jgS4vfeAqy1a1&lkMFu511xSw<0d5?B4 zI#lHndq57It5pt$$tSVsk@q1U^O2CqJE}ng9}C?|U;*MiyLE)_fZ(!I%T=o?khTtFc zT|Z;V5MxqF!q&MyhkYOa*o~gzrXX7M#pG?$L90ar!U`xU0&C*xYa?Y>mHU-_(S`03^u zXA}Dwk`L`}?T)(sck7#d23Rc})NH~$ksO8TCR%(vbGjcmyy%>O@USOd3cOda{zZq2 z(`jZX^$*ViSi$UUmh2_kEDxT+czPo=)=8Gk?lReG8B6CsUG+Ux_+i<1#jN2@{C(H@ zWY-psLbF&PQXFGO2A^H^W9_!-3ZaYbV~w~kwzp(rh~MA}AfNugeaCu6k0}q7H8X7+9b&8XhA)RI*A=$nbuPAv%ULejI>iOGONNY-MzH9`E#h$-Ok_IY zdRQY3-?V5p@xs&5vu7rrgVQE^uL2Bx1cv6SY;C!*~uQg-cSfy1rO{E#X| zrZD@mK#skFBHdN_R~pLO3qn^y`D{JpF}G$Z3OJN6tFRSF z23kPH!%j4OB~3ey*%dAHUaxZ%E_>Os$jP)BJ(DXyT^#soUTmn(YvQyKdSG4rAi=Pt zS(^;$+Aml>amlGZg0#q&?N&ICE;UJ$TT=qf&bh!uGeMk-B^$%^=(mQ2vth|TF-0Y* zCLE&u?M~597Y(lAOAFeyG_6~&#A@@5wTtPgas8lvPIf+?O-$C*_A*gbzZFnUUY4@q`4f%!!`yc z(m0_F2ihA1E2Xsao-!2WXRi0}+~JS}b$_hz`xa-4hgj&&sah|Sb{w1%^wgO-`^_Ne znnF{kKQjxv#b@jIP~I`*R>>m0&|t#}a!&rcARIo8mVW-ES_nfm6A7xn^L+g6fR%GH zeqmiqT>1U7$O{^%Y@M55%EyD%mQ6u2HeGL^=0OR*Ikhgu@CIxs3Z%aBmk1M-$$A_~ z_Vt7TLiQ$)t1{|gASZ(1avzS~)I*34xu=uXcOza_)6vYF`cRFjKPuielyNYRO=PB< zOOG{7hY zhyG^r%{Bn>K7Xy3PehpKNhW_TdvP!8ikk4Gyss8{j3_^M{E*Z%%%iZn%#L1=U;D1s zO3R;7GVGeigbZOP&zn%d-=*hPs6WR;hu&RWq8#~C2x{h-dzd3Pbd`$-R z=|T#dSxnf}1&L1vT7V@uMy|;i{KQ^6m!E;=1c#CN6_^HBmrE`B%m^JB>iUrQ!%Qgq zOR6+N!?-yEwnym>XxLl#sgOCll;)a5HA3UW{!l|4Q@F&~4g`mJ=Z=L6*8TujoHvC~D(VhO=UR6Hnw&vgD*BGVGqTQl z7a6KKCaJQu1D1n9`P(&#V$~LY><@AHyj>=}vNck}gCV^~HK~mwR*)}EWWr@RIz90g zY@}$;mHM5STRTP~QR0IL)^1c^)txJM&}1<(MahJC!)qD3WIAOzF_XzgH@>VegS2zv zM_n#SFL{x*zbd8LHzHX(WQ66uvq<{;#f8Jc?0ciYo<{;sxJ5bY-eew>t@sSh&H=Ua zh$Z`i<;97m#uECeJf4dzx`JBjFD7+M_XR3IS6{lrI9k^o>JdB_LX@wyJ}Ed={{STT z%7C=FGmGI23y5{+uC5{eaB6?c>&&imk<?XZ*A~BzayB{$Iw36P7p8a? zYtI-O_{Po8*@@(oI_lbfv)A^h+qhC*e#+64W1-r6*Tb$}&@s|EV;Xj6v9Hzmjlq4R z3FaG(y?n6|Vdwmo$OiU%9)5MUyT?i^v?SKAQtonh(r^Vs;yuTC%F;RyH};kCGoeV( zNfrHNj_uBs0nKd3^mkvLF<$X}lv1(lcStI+BK6mm9uZ2XNcYTjvF{(-U#RSRm(Fjz z*l!$m=tZ0~5tz{<>w5R(`ui4Xzj`Jc<2u5txA=R8JFH8e`oHbI*Fb*_^=b5(0gZZQ z-ut$@PwD%Z==dNQFzCGWb>V3Mb-(K2KKlDE%j@@3jjG?D7~lD__Bvp{ z+S#Am;~8uq{?daw@!E4YplIlt6-n-fL#)f8-R4Kn7Fzpqo_nd9NYdh~RXil$Zo&SN z|7)!3M(R6B8__e2TekavU7UqPmpj~c%95w7v@dkMx470U^HJHN8saPz%^{$EADq`gTz2LjyP^v1Bb5lTlfvUeZ#A6Vm=8ZCE zzql-nIzU*}J~s-M4>uVHsIW2`F6LskMhDB1O5@?NO;8f5hzqnTbT~-z#)D2xQEf}T z^ri^CDi9qNdsZ=u2}e~}Ajwi|PIo94SrQHlWAvS=4Mi{zBx{ZEiG_-Q%>sGt{uriph%0x$JAKF`EH z!Nz+65fDPuSMLNG0?FyBxK`eX+x_;;5~QcQqKCs1co-6Cx1;3ZL6CS5AkW0BK*C%F zP+&n@W)K!Eh?yNk(M8M7oMasjVqymgVIU&gz~2!zG~;?OSh5KMpb$=`5l+!kNMS-G zQK%(LS0x$n(cIWhKJ={u7?zWGK&kfe$*RkMj6y0kA5=af)%pNJ(Urukh8EOEtNWxF zFsB$FMBni-A*D*Aq(ZABlQr~H7?3GK7!aj!+FAWn^)7%^7)`pIR$B+$x|KEuBq3++ zkWzslRB6v;0ct7`g$pc^8N@q_c7$QP=|QB+7%X42C!O9% zzu*bvGiQLQ(gqYV71=Q^FrXQeAVRER3MqvL4^-@&b72|aWnhp1bYLKZ`VitW!CD6` zi%k-+%a%Jxe1NxTU{3Gl!_3=dEbxJr4=}3{_msO5U);(r$OAD^fy5P{@`UVe9|(T? z5GeEkl=v`p{aErjxhj0-i}RR<2%E?H$plRD0&`j;-pHK~)J90(BqXXUpaDeg+nH=> zAmbTd`Wf;JN|#LPaa=01WuOn>FM%85gV6FrP734xX2ucpP1++sD2Xi1i2M$_B$j1> z$tBOk2P?y#^8uD3kIxb%&nfare}T?Zl7OVaa#CSA6FljVJ)G!}1%FG5nnIF1e?fpk z0g@rZk{=|&4_T1N4kF}{S>gg`?>6e^mq}-o%;M~>LRJVCS0hr|4^kn**d%$Tw|r^d zEkK=5CPN9fnvf~im6x^#2sIZ=QKgmOU2_P4EG*|xBGf(zKdX-sJuCs`Cgo9@76kf2 zB>4-2^ox@eAcc{scsvH?1FMR_G+;874zMSY#q#60l(+Q)SGWWJNYhz()! zYXxwY@~W#?yOOM(&0HB|k>XUz4fRUaz{**E>>xfXjRo|oByTkWLD)|0ApFYeKHt>o!q@OYBL zPARUT92W|Z@G*Sqt^*L@IbI0E?B9#&v3C`&_kF+|8nx6?&iVhHUd}RHVmD{^nY?mN z5mLnrvL-cBc3^ESMme9Z=ftAG7CcNqYN!R4@aFhwS6(Rv@=4d6u z@-|&7X!!zN+i%~pNUCYf3U1CygXKTkevy?Yk{!cW)BvqkE{*wc4Z=?m1t4R~Xa3fw zs4x@0x*2s{%Crs;&M#JQ4Ce2q`P9A+ZMCau>yjxI+P)yKPzv8HnAmU6?a5g)?0N6o zc_+2g#WdDoD%vK#xq~8@U$Qqyvscb9Xg;IYm%Ue6ne_J8UN@>fjgzEWMtw9Z1j-~431{nvgw)&VDh0V~M?FQWnPg?^vt{(EHu z0V4zVmEk68Cqs+|!~6!rGY2Ev22s&{v0n${SqX`fgk&Q^svjXOlaSs<$Xp;~eFUq8@tV%sM*nkH`Z*SD#a~78#z4c37*m<$FyI9^^)l#iQ>o}O?Hz?jW z4CcLgQ?01N?&f+tQWn$<6i$jMS=_k(;qDn2J$ImtiL_IwVwc+!f{9EOJq7sJaS#Pq zj>ci@$2f4&&;;eW>C-{L5Tpmc)ha{*C&G@^D33tgRPh=2%s3DG|p!~^e-X@mRRKg`VK(n}P;`4{H z`HIL{@|O?8EzANT?9v)@WRCLnNg6@FYZ2TFXcri6rsQaE z2lfb#QVL42i}Y3YL!)gl%9*$jS^Wn%JBJ)d(48W*PEKkCu1Y$-wy4Ud^{%BxTbFKp z=)*o|**?PE9x43L!+{nJ#hC2Le01JZ>Di?DLeSjOV$NFH(!%Ce;q+F9_p_&EkC$TX zS0~G|*A38*0Qt9`t0_DWQ-cll%!YzrJn8h-ppgt|>NUO00cGc&8FU@4{hHkrdv_>_`oX|jaDsY`$7 zr?3aMn?Mr+`MWM4c`f1pb+j13cGTzR|J~hGJI7&9M-~=>2vSsrgasi?hoB*q$RMWC zKD$sbYpe?QVC5SLNo3Rzh21?Vb4yj28-Q|m4^fZwa`Q5`h;@r}w>S4!fD<#_GATC~ z?N*qOhs`VXDXM^AN^1%#>Z@y#%IjMjn_61yO`06K`rzG7@%{DsO?AT+gSkWFZFx_u zs-YFL%?n0@PcpP}>y6CJ$BgDSo61Vsyy1;g;dEO-;z(*FVze3lk%na z5W5iAqx~`ZR1&?bexOMyjesbL!*stroGhFU_E?MRUuRziBmnlK^j`UI$H$B5_{hk@ zAPaSRf+tT*3yQ~6>GYTbPJ#kumD>WbfPCB2yLeNT_^|^IU+4Qi#>)PIj?PZ-Xj3om z1aF9`rF49}H_S9TF)<^~KRX7R5|Wotkb+Gqk1Nizsi-v#s7kD>&1y_6X|`-DP9|>c zR`(Y5=X4G=))7V%ddkNQYhVpN8XegC0nHLVGnPpZ^wKvgDc<WMOc?|U;my=lVy@Qz;8e}YkiZxiQ31%Uox>u6;>fP7lKoQDE(6zy zz2+f?_~)bI&VmZbbK{fe3XSM;R|qAck&;pO`H}s)x%#A-#H3Z>=}JLCO7iVxqedR@rkjxVS$m&3G`yatlzA1At+J1EWz|Vn(a0~* zZ?edk6pe@l=kAep#^{r&T}VXGUa^EfqS9-2J2{LNwxBuaD=Hk#xDxzJnfnn0XMyv? z;duGaa6rMt;SiuB#yhgBjFLjrOq3n)?gTDeGT1Y3Uan-~=LQ;#FM1j$d#!8;`17g& zG+qG2@xC+?^dQj2$?QJLP&3%kBow9Lm1?gDfgxcEaCC02RdPluC?~HpIz|axT$&qT zS8p0$gLZ9b!)muy=%{v@hHAGBn!=O{2!tM)x<`-3;g2Vus5SK8nqSCuUyx1IXj_OM zwObfA*a&^@yDDRYAMDTVvV*SZG=23n>RndUje2rJe7U5If0=@`O#Q$sRLnP0trmSKA1X9c6*ukB1wVfh)k7qXBqvGys$^aF8p3i#Id~ z5v0Jahzdm@fh}KR(cxs@iY44})=OIiKe9q%t9ay2gf@y-_)ohUfP8I{wx*so5E~yy z*9S3yR)Iz+2gg8-v}EmoduciLa%gY)oE#rxrR+ePLVsLIc}2Qiy-7f3l~$8VORF~Q z&Vxwh;)Vee583{~QLxOz(Z|MPQWM<|Zt2y}N@u&yEG{i9!ZoFmS7y`K)9h6 z4x8}h9f#L}1B)Nuw{aCSSZlY4CX|$sZ>?*Aj3R}NYsE@)Pg{Pc?C-&qkxRS50d_u@ zv4tKxd|PDub+mogD4UgKeeWHP%xyjB%-Wb*R%rzYiz+=yF4TeL7VdihQ`O``;x~d zo)U_utZZkVmBXGyS$B;W*9^(mtlOE#Jb!9FnCKe?S**ynd^xPt{C$-vWm3Fi%1j~^cRtk%&7{lC7^@IM&$6|8-B{+<@VK}n7{Et@rD%FVS}ik! zTiB4DDFuv9U+V}@xO+YrmyDelaTinrzZ}v5`zI34^rv4$OqckI<-?Oe(LC+%sT?g# zHl|48O|6ru7{P6c8TThUgq_V+nt->ZYU_z74d>uf6YYSM48Qz!!KD3HDJQVq>+;Ai zhD}U~F^?3;yNq0RI4m@an`_T69bBe5ZJPNJLu$k4mTt%+()-W~8az%7qvP|A-cR!0zpGlKV(zI63m)1ReC(8mqHMyQD7ei|; zq`n;d_>58^807^ogIQ2_U*cHDnB0cTL}=>OL(qPd={y&;crVYGYBRL-X4=TP4W2ng zd0>TJ5AVa}Dc_y5(kNE>#OLj2Jz$q(Gvv92@7+!#zfnUnRnYl|7&F-J69C@Y3?&t!E7`3{ps)NgQB-Gh08Nm{-(FwXHv z?lZ;m+g1%Y_V^}VT{}Z}#io$kh0Rt*pweC!=wHZIIw!~9YP(EGHHtK$zQ^7TvoAf2 ztd8be#nkpt=u6d{lN?i?d3f&8TSdl3s+jjfXEhU-Xk4>&>m0SQyof*t4{A?NT}`== z_D&Oy+tG&!F&}2;90f(D7L+qx3&M3KGUw%4`=Ko27vAj8y``5n7u>85WT9bHFXj}K z5`D$RtViy4wmq4G`j=!^0L*|B0F;>Qv&A(511ZN zJ8@*~sL5XXU#`>ONc&-q;;4%>#I>5xKlT3TVYbonCQW{#|8$Yu<<~Bn9S@rS5wtoU zwEiP#_f!3?w;Yb--+RmPC;B^Yxe(QVyhR*8s`GRtzuW@2{v>~E)cseZ#4z|3^*UaTzvHn0qV!KJ|IS;1$AdwC1VfL&pPlH1{SvOI;~S0m0~U2W7V`%z z?szPLDE%RilaA!yM@Gs|^mmbwcD&8>BkAYB{3nkykH@nAfMJQ+ae173q#d8f`MzMpvcC%rJW)NSR+an_EI$H&j=+CHqw@GhtN(!29*@-%rC;OwzXiAHc(CQa_Wt9j zw&SsmKVV(QW8FmQpUeDxz3n~He;my;t$y5@z~TKu&2jkvqb552QM5CKKrk||2TO0cx?3#*z@DD zjXz*pMD4f)-Z|2aPvDoovj3C7yFc0AdG`%bJ zc1Ha22lU%d^moM;0R8_$^na&e5K%imI3PdCUuRR>ANR9A?&rur|K88h{J5XPi~jdz zJ(ClG5ch4te_qy0<>^{=z5nB7J#SkOYwG6F%X%_kKYz=RA1~|aLr@@SM64Q3)@PkFVG~KQM$v|Mx?$+V-x^|24 z3F6H>Dql9t^eMbIZDc9-QG&vg^^GU9rq85N-P@p{<+s7BC7T~VDLT8{>X3RpzX5}2 zy;jTgBP*JqkvqxOD1YJ{*!QWDad*_jK9mZ9<-mtga!1xlS93~6^QPoa4&DNWW6oJT z=F@*;Ius(R5|&KRJas6amE*)IFmoZWN(liknr)TwKRWv0D}B;0aj2S8X&cLU*aY5&a^)!@G@SR{GQJb9niI;T^4 z``$y(O&SP`=-x8R2>-mY8^d(@)p^pTasNArkhXKr8b>}_OH;RBvy5u!bLB#?-QRDo zXuE%Y(Nl1+ZFB9l=2DjElNRn1{bL=kq5fO@^(Y#Zv{&deXUD#6&XIm$MJH+}blI5t zp?E*(k?pl{uwS=0)Ye)KA$>cM5z6cLmPF!!%#>M~on(I8Ezylssi;rX zh_ptHahFZWa=E2hmuwei)^I{Jn)H1p*|JjYcksm;n)FV7WF#;QzMua^nJ28;TsE1z zile-3f2UMbrQw4dPKudxr*e=-=>nzY!;;?8LgNzqe3yx!9=ic@S$l~mI`_%0f@ZA4 zYu%DH6M+FtHm##*mBU5>2PqXxt8~zQi2n=5=N!ZlNy^b6CXeKeb z7*?H4`A7@nv;rz$)lWGHS#cLQDWQ|7`fZ>AeX+iV+Gi}#8=v+4CbxKz$)er1kBkVz z739-5o`-XFw~XydTBa+mO^=XUIZ4^P7W!J5#OVK*Y`>Do=e?2P&mro(uQ<*F)`f77 zcQfu+#fBIoQr>ibw9WkXX)ZWhQcPZX?VH4E((CJPxAXs!{P;P$v-joe&9fv zCT05gUouVE8Mi~a`H>gTaZBP(u1g8=yaf3Q=67F;EReDc8&HSKxSXcX;gu1%E~V?tvP@sj)G55Bc-q)9mtjbxU)*5z P9<`-$BAB?rf9?MPx8!pr literal 0 HcmV?d00001 diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..f8249108 --- /dev/null +++ b/build.gradle @@ -0,0 +1,60 @@ +apply plugin: 'java' +apply plugin: 'distribution' + +// Common configuration // +allprojects { + version='1.0.0' + + apply plugin: 'eclipse' + apply plugin: 'idea' + + tasks.withType(JavaCompile) { + sourceCompatibility = '1.7' + targetCompatibility = '1.7' + } + tasks.withType(GroovyCompile) { + sourceCompatibility = '1.7' + targetCompatibility = '1.7' + } + + repositories { + mavenCentral() + } +} + +// 'cleanIdea' task extension // +task fullCleanIdea { + new File(project.name + '.iws').delete() + ant.delete(dir: 'out') +} +fullCleanIdea.mustRunAfter cleanIdea + +// All in one JAR // +subprojects.each { subproject -> + evaluationDependsOn(subproject.path) +} + +jar { + dependsOn subprojects.tasks['classes'] + manifest { + attributes 'Main-Class': 'jd.gui.App', 'SplashScreen-Image': 'images/Icon_java_128.png' + } + def deps = [] + subprojects.each { subproject -> + from subproject.sourceSets.main.output.classesDir + from subproject.sourceSets.main.output.resourcesDir + deps += subproject.configurations.compile + } + from { deps.unique().collect { it.isDirectory() ? it : zipTree(it) } } +} + +// Distribution for OSX // +distributions { + osx { + contents { + into('JD-GUI.app/Contents/Resources/Java') { + from { fileTree('build/libs') { include 'jd-gui-*.jar' } } + } + } + } +} diff --git a/services/build.gradle b/services/build.gradle new file mode 100644 index 00000000..c709bb61 --- /dev/null +++ b/services/build.gradle @@ -0,0 +1,11 @@ +apply plugin: 'java' +apply plugin: 'groovy' + +dependencies { + compile 'org.codehaus.groovy:groovy:2.4.0' + compile 'org.codehaus.groovy:groovy-swing:2.4.0' + compile 'org.codehaus.groovy:groovy-xml:2.4.0' + compile 'com.fifesoft:rsyntaxtextarea:2.5.6' + compile files('lib/jd-core-0.7.1.jar') + compile project(':api') +} diff --git a/services/lib/jd-core-0.7.1.jar b/services/lib/jd-core-0.7.1.jar new file mode 100644 index 0000000000000000000000000000000000000000..6ea1b7bd38ba80713a2d7b2908514fadfdc39ffc GIT binary patch literal 619215 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 z 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

-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
kSD>)ET(O#8(L#=CF45* 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

pS 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 CQl)soGa#J${6sF|L? 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 kms5bM}{M8zjnn@L9>9F!1L5z?0vF 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 literal 0 HcmV?d00001 diff --git a/services/src/main/groovy/jd/gui/model/container/GenericContainer.groovy b/services/src/main/groovy/jd/gui/model/container/GenericContainer.groovy new file mode 100644 index 00000000..3edd14ae --- /dev/null +++ b/services/src/main/groovy/jd/gui/model/container/GenericContainer.groovy @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.model.container + +import groovy.transform.CompileStatic +import jd.gui.api.API +import jd.gui.api.model.Container + +import java.nio.file.* + +@CompileStatic +class GenericContainer implements Container { + protected API api + protected int rootNameCount + protected Container.Entry root + + GenericContainer(API api, Container.Entry parentEntry, Path rootPath) { + this.api = api + this.rootNameCount = rootPath.nameCount + this.root = newEntry(parentEntry, rootPath, parentEntry.uri) + } + + protected Container.Entry newEntry(Container.Entry parent, Path fsPath, URI uri) { + return new Entry(parent, fsPath, uri) + } + + String getType() { 'generic' } + Container.Entry getRoot() { root } + + class Entry implements Container.Entry, Comparable { + protected Container.Entry parent + protected Path fsPath + protected String strPath + protected URI uri + protected Boolean isDirectory + protected Collection children + + Entry(Container.Entry parent, Path fsPath, URI uri) { + this.parent = parent + this.fsPath = fsPath + this.strPath = null + this.uri = uri + this.isDirectory = null + this.children = null + } + + Container getContainer() { GenericContainer.this } + Container.Entry getParent() { parent } + + URI getUri() { + if (uri == null) { + uri = URI.create(root.uri.toString() + '!/' + path) + } + return uri + } + + String getPath() { + if (strPath == null) { + if (rootNameCount == fsPath.nameCount) { + strPath = '' + } else { + strPath = fsPath.subpath(rootNameCount, fsPath.nameCount).join('/') + if (strPath.endsWith(fsPath.fileSystem.separator)) { + // Cut last separator + strPath = strPath.substring(0, strPath.length()-fsPath.fileSystem.separator.length()) + } + } + } + return strPath + } + + boolean isDirectory() { + if (isDirectory == null) { + isDirectory = Boolean.valueOf(Files.isDirectory(fsPath)) + } + return isDirectory + } + + long length() { Files.size(fsPath) } + InputStream getInputStream() { Files.newInputStream(fsPath) } + + Collection getChildren() { + if (children == null) { + if (Files.isDirectory(fsPath)) { + children = loadChildrenFromDirectoryEntry() + } else { + children = loadChildrenFromFileEntry() + } + } + return children + } + + protected Collection loadChildrenFromDirectoryEntry() { + return Files.newDirectoryStream(fsPath).collect { Path subPath -> new Entry(this, subPath, null) }.sort() + } + + protected Collection loadChildrenFromFileEntry() { + def tmpFile = File.createTempFile('jd-gui.', '.tmp.zip') + def tmpPath = Paths.get(tmpFile.toURI()) + + tmpFile.withOutputStream { OutputStream os -> + Files.copy(fsPath, os) + } + + FileSystem subFileSystem = FileSystems.newFileSystem(tmpPath, null) + + if (subFileSystem) { + def rootDirectories = subFileSystem.rootDirectories.iterator() + + if (rootDirectories.hasNext()) { + tmpFile.deleteOnExit() + + def rootPath = rootDirectories.next() + def container = api.getContainerFactory(subFileSystem)?.make(api, this, rootPath) + if (container) { + return container.root.children + } + } + } + + tmpFile.delete() + return Collections.emptyList() + } + + /** + * Directories before files, sorted by path + */ + int compareTo(Entry other) { + if (Files.isDirectory(fsPath)) { + if (!other.isDirectory()) { + return -1 + } + } else { + if (other.isDirectory()) { + return 1 + } + } + return fsPath.compareTo(other.fsPath) + } + } +} diff --git a/services/src/main/groovy/jd/gui/model/container/JarContainer.groovy b/services/src/main/groovy/jd/gui/model/container/JarContainer.groovy new file mode 100644 index 00000000..2f8339be --- /dev/null +++ b/services/src/main/groovy/jd/gui/model/container/JarContainer.groovy @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.model.container + +import groovy.transform.CompileStatic +import jd.gui.api.API +import jd.gui.api.model.Container + +import java.nio.file.Path + +@CompileStatic +class JarContainer extends GenericContainer { + + JarContainer(API api, Container.Entry parentEntry, Path rootPath) { + super(api, parentEntry, rootPath) + } + + String getType() { 'jar' } +} diff --git a/services/src/main/groovy/jd/gui/service/container/GenericContainerFactoryProvider.groovy b/services/src/main/groovy/jd/gui/service/container/GenericContainerFactoryProvider.groovy new file mode 100644 index 00000000..eb15f726 --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/container/GenericContainerFactoryProvider.groovy @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.container + +import jd.gui.api.API +import jd.gui.api.model.Container +import jd.gui.model.container.GenericContainer +import jd.gui.spi.ContainerFactory + +import java.nio.file.FileSystem +import java.nio.file.Path + +class GenericContainerFactoryProvider implements ContainerFactory { + + String getType() { 'generic' } + + boolean accept(API api, FileSystem fileSystem) { true } + + Container make(API api, Container.Entry parentEntry, Path rootPath) { + return new GenericContainer(api, parentEntry, rootPath) + } +} diff --git a/services/src/main/groovy/jd/gui/service/container/JarContainerFactoryProvider.groovy b/services/src/main/groovy/jd/gui/service/container/JarContainerFactoryProvider.groovy new file mode 100644 index 00000000..16e75e02 --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/container/JarContainerFactoryProvider.groovy @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.container + +import jd.gui.api.API +import jd.gui.api.model.Container +import jd.gui.model.container.JarContainer +import jd.gui.spi.ContainerFactory + +import java.nio.file.FileSystem +import java.nio.file.Files +import java.nio.file.InvalidPathException +import java.nio.file.Path + +class JarContainerFactoryProvider implements ContainerFactory { + + String getType() { 'jar' } + + boolean accept(API api, FileSystem fileSystem) { + def rootDirectories = fileSystem.rootDirectories.iterator() + + if (rootDirectories.hasNext()) { + def rootPath = rootDirectories.next() + + if (rootPath.toUri().toString().toLowerCase().endsWith('.jar!/')) { + // Specification: http://docs.oracle.com/javase/6/docs/technotes/guides/jar/jar.html + return true + } else { + // Extension: accept uncompressed JAR file containing a folder 'META-INF' + try { + return Files.exists(fileSystem.getPath('/META-INF')) + } catch (InvalidPathException e) { + return false + } + } + } else { + return false + } + } + + Container make(API api, Container.Entry parentEntry, Path rootPath) { + return new JarContainer(api, parentEntry, rootPath) + } +} diff --git a/services/src/main/groovy/jd/gui/service/fileloader/AbstractFileLoaderProvider.groovy b/services/src/main/groovy/jd/gui/service/fileloader/AbstractFileLoaderProvider.groovy new file mode 100644 index 00000000..9b44b1b6 --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/fileloader/AbstractFileLoaderProvider.groovy @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.fileloader + +import jd.gui.api.API +import jd.gui.api.feature.UriGettable +import jd.gui.api.model.Container +import jd.gui.spi.FileLoader + +import javax.swing.* +import java.nio.file.Path + +abstract class AbstractFileLoaderProvider implements FileLoader { + protected T load(API api, File file, Path rootPath) { + // Dummy parent container + def parentContainer = new Container() { + String getType() { 'generic' } + Container.Entry getRoot() { null } + } + // Dummy parent entry + def uri = file.toURI() + def parentEntry = new Container.Entry() { + Collection children = Collections.emptyList() + + Container getContainer() { parentContainer } + Container.Entry getParent() { null } + URI getUri() { uri } + String getPath() { uri.path } + boolean isDirectory() { file.isDirectory() } + long length() { 0 } + InputStream getInputStream() { null } + Collection getChildren() { children } + } + def container = api.getContainerFactory(rootPath.fileSystem)?.make(api, parentEntry, rootPath) + + if (container) { + parentEntry.children = container.root.children + + def mainPanel = api.getMainPanelFactory(container)?.make(api, container) + if (mainPanel) { + api.addPanel(file.name, null, 'Location: ' + file.absolutePath, mainPanel) + return mainPanel + } + } + + return null + } +} diff --git a/services/src/main/groovy/jd/gui/service/fileloader/ClassFileLoaderProvider.groovy b/services/src/main/groovy/jd/gui/service/fileloader/ClassFileLoaderProvider.groovy new file mode 100644 index 00000000..1fa5e921 --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/fileloader/ClassFileLoaderProvider.groovy @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.fileloader + +import groovyjarjarasm.asm.ClassReader +import jd.gui.api.API +import jd.gui.api.feature.UriOpenable + +import java.nio.file.Paths + +class ClassFileLoaderProvider extends AbstractFileLoaderProvider { + + String[] getExtensions() { ['class'] } + String getDescription() { 'Class files (*.class)' } + + boolean accept(API api, File file) { + return file.exists() && file.canRead() && file.name.toLowerCase().endsWith('.class') + } + + boolean load(API api, File file) { + file.withInputStream { is -> + ClassReader classReader = new ClassReader(is) + + // Search root path + def pathSuffix = classReader.className.replace('/', File.separator) + '.class' + def path = file.path + + while (! path.endsWith(pathSuffix)) { + int index = pathSuffix.indexOf(File.separatorChar) + + if (index == -1) { + pathSuffix = '' + } else { + pathSuffix = pathSuffix.substring(index) + } + } + + if (pathSuffix) { + // Init root file + File rootFile = file + int index = pathSuffix.indexOf(File.separator) + + while (index != -1) { + rootFile = rootFile.parentFile + pathSuffix = pathSuffix.substring(index+1) + index = pathSuffix.indexOf(File.separator) + } + rootFile = rootFile.parentFile + + // Create panel + def mainPanel = load(api, rootFile, Paths.get(rootFile.toURI())) + + if (mainPanel instanceof UriOpenable) { + // Open page + pathSuffix = file.absolutePath.substring(rootFile.absolutePath.length()).replace(File.separator, '/') + def uri = URI.create(rootFile.toURI().toString() + '!' + pathSuffix) + mainPanel.openUri(uri) + return true + } else { + return mainPanel != null + } + } + } + } +} diff --git a/services/src/main/groovy/jd/gui/service/fileloader/JarFileLoaderProvider.groovy b/services/src/main/groovy/jd/gui/service/fileloader/JarFileLoaderProvider.groovy new file mode 100644 index 00000000..3257b92e --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/fileloader/JarFileLoaderProvider.groovy @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.fileloader + +import jd.gui.api.API + +class JarFileLoaderProvider extends ZipFileLoaderProvider { + + String[] getExtensions() { ['jar'] } + String getDescription() { 'Jar files (*.jar)' } + + boolean accept(API api, File file) { + return file.exists() && file.canRead() && file.name.toLowerCase().endsWith('.jar') + } +} diff --git a/services/src/main/groovy/jd/gui/service/fileloader/LogFileLoaderProvider.groovy b/services/src/main/groovy/jd/gui/service/fileloader/LogFileLoaderProvider.groovy new file mode 100644 index 00000000..619d0f87 --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/fileloader/LogFileLoaderProvider.groovy @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.fileloader + +import jd.gui.api.API +import jd.gui.view.component.LogPage + +class LogFileLoaderProvider extends ZipFileLoaderProvider { + + String[] getExtensions() { ['log'] } + String getDescription() { 'Log files (*.log)' } + + boolean accept(API api, File file) { + return file.exists() && file.canRead() && file.name.toLowerCase().endsWith('.log') + } + + boolean load(API api, File file) { + api.addPanel(file.name, null, 'Location: ' + file.absolutePath, new LogPage(api, file.toURI(), file.text)) + return true + } +} diff --git a/services/src/main/groovy/jd/gui/service/fileloader/ZipFileLoaderProvider.groovy b/services/src/main/groovy/jd/gui/service/fileloader/ZipFileLoaderProvider.groovy new file mode 100644 index 00000000..ca2c42e6 --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/fileloader/ZipFileLoaderProvider.groovy @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.fileloader + +import jd.gui.api.API + +import java.nio.file.FileSystemNotFoundException +import java.nio.file.FileSystems + +class ZipFileLoaderProvider extends AbstractFileLoaderProvider { + + String[] getExtensions() { ['zip'] } + String getDescription() { 'Zip files (*.zip)' } + + boolean accept(API api, File file) { + return file.exists() && file.canRead() && file.name.toLowerCase().endsWith('.zip') + } + + boolean load(API api, File file) { + def uri = URI.create('jar:' + file.toURI().toString() + '!/') + def fileSystem + + try { + fileSystem = FileSystems.getFileSystem(uri) + } catch (FileSystemNotFoundException e) { + fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap()) + } + + if (fileSystem) { + def rootDirectories = fileSystem.rootDirectories.iterator() + + if (rootDirectories.hasNext()) { + return load(api, file, rootDirectories.next()) != null + } + } + + return false + } +} diff --git a/services/src/main/groovy/jd/gui/service/indexer/DirectoryIndexerProvider.groovy b/services/src/main/groovy/jd/gui/service/indexer/DirectoryIndexerProvider.groovy new file mode 100644 index 00000000..b282ff6f --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/indexer/DirectoryIndexerProvider.groovy @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.indexer + +import groovy.transform.CompileStatic +import jd.gui.api.API +import jd.gui.api.model.Container +import jd.gui.api.model.Indexes +import jd.gui.spi.Indexer + +import java.util.regex.Pattern + +class DirectoryIndexerProvider implements Indexer { + String[] getTypes() { ['*:dir:*'] } + + Pattern getPathPattern() { null } + + @CompileStatic + void index(API api, Container.Entry entry, Indexes indexes) { + int depth = 15 + + try { + depth = Integer.valueOf(api.preferences.get('DirectoryIndexerPreferences.maximumDepth')) + } catch (NumberFormatException ignore) { + } + + index(api, entry, indexes, depth) + } + + @CompileStatic + void index(API api, Container.Entry entry, Indexes indexes, int depth) { + if (depth-- > 0) { + for (def e : entry.children) { + if (e.isDirectory()) { + index(api, e, indexes, depth) + } else { + api.getIndexer(e)?.index(api, e, indexes) + } + } + } + } +} diff --git a/services/src/main/groovy/jd/gui/service/indexer/MetainfServiceFileIndexerProvider.groovy b/services/src/main/groovy/jd/gui/service/indexer/MetainfServiceFileIndexerProvider.groovy new file mode 100644 index 00000000..2c3fe998 --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/indexer/MetainfServiceFileIndexerProvider.groovy @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.indexer + +import groovy.transform.CompileStatic +import jd.gui.api.API +import jd.gui.api.model.Container +import jd.gui.api.model.Indexes +import jd.gui.spi.Indexer + +import java.util.regex.Pattern + +class MetainfServiceFileIndexerProvider implements Indexer { + Pattern pattern = ~/META-INF\/services\/[^\/]+/ + + String[] getTypes() { ['*:file:*'] } + + Pattern getPathPattern() { pattern } + + @CompileStatic + void index(API api, Container.Entry entry, Indexes indexes) { + def index = indexes.getIndex('typeReferences') + + entry.inputStream.text.eachLine { String line -> + index.get(line).add(entry) + } + } +} diff --git a/services/src/main/groovy/jd/gui/service/indexer/TextFileIndexerProvider.groovy b/services/src/main/groovy/jd/gui/service/indexer/TextFileIndexerProvider.groovy new file mode 100644 index 00000000..71470c5c --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/indexer/TextFileIndexerProvider.groovy @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.indexer + +import groovy.transform.CompileStatic +import jd.gui.api.API +import jd.gui.api.model.Container +import jd.gui.api.model.Indexes +import jd.gui.spi.Indexer + +import java.util.regex.Pattern + +class TextFileIndexerProvider implements Indexer { + String[] getTypes() { ['*:file:*.txt', '*:file:*.html', '*:file:*.js', '*:file:*.jsp', '*:file:*.xml', '*:file:*.xsl', '*:file:*.xslt', '*:file:*.xsd', '*:file:*.properties'] } + + Pattern getPathPattern() { null } + + @CompileStatic + void index(API api, Container.Entry entry, Indexes indexes) { + indexes.getIndex('strings').get(entry.inputStream.text).add(entry) + } +} diff --git a/services/src/main/groovy/jd/gui/service/indexer/XmlFileIndexerProvider.groovy b/services/src/main/groovy/jd/gui/service/indexer/XmlFileIndexerProvider.groovy new file mode 100644 index 00000000..6661575b --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/indexer/XmlFileIndexerProvider.groovy @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.indexer + +import groovy.transform.CompileStatic +import jd.gui.api.API +import jd.gui.api.model.Container +import jd.gui.api.model.Indexes +import jd.gui.spi.Indexer + +import javax.xml.stream.XMLInputFactory +import javax.xml.stream.XMLStreamConstants +import java.util.regex.Pattern + +class XmlFileIndexerProvider implements Indexer { + XMLInputFactory factory + + XmlFileIndexerProvider() { + factory = XMLInputFactory.newInstance() + factory.setProperty(XMLInputFactory.SUPPORT_DTD, false) + } + + String[] getTypes() { ['*:file:*.xml', '*:file:*.xsl', '*:file:*.xslt', '*:file:*.xsd'] } + + Pattern getPathPattern() { null } + + @CompileStatic + void index(API api, Container.Entry entry, Indexes indexes) { + def index = indexes.getIndex('strings') + def reader + + try { + reader = factory.createXMLStreamReader(entry.inputStream) + + index.get(reader.version).add(entry) + index.get(reader.encoding).add(entry) + index.get(reader.characterEncodingScheme).add(entry) + + while (reader.hasNext()) { + switch (reader.next()) { + case XMLStreamConstants.START_ELEMENT: + index.get(reader.localName).add(entry) + for (int i = reader.attributeCount - 1; i >= 0; i--) { + index.get(reader.getAttributeLocalName(i)).add(entry) + index.get(reader.getAttributeValue(i)).add(entry) + } + for (int i = reader.namespaceCount - 1; i >= 0; i--) { + index.get(reader.getNamespacePrefix(i)).add(entry) + index.get(reader.getNamespaceURI(i)).add(entry) + } + break + case XMLStreamConstants.PROCESSING_INSTRUCTION: + index.get(reader.getPITarget()).add(entry) + index.get(reader.getPIData()).add(entry) + break + case XMLStreamConstants.START_DOCUMENT: + index.get(reader.version).add(entry) + index.get(reader.encoding).add(entry) + index.get(reader.characterEncodingScheme).add(entry) + break + case XMLStreamConstants.ENTITY_REFERENCE: + index.get(reader.localName).add(entry) + index.get(reader.text).add(entry) + break + case XMLStreamConstants.ATTRIBUTE: + index.get(reader.prefix).add(entry) + index.get(reader.namespaceURI).add(entry) + index.get(reader.localName).add(entry) + index.get(reader.text).add(entry) + break + case XMLStreamConstants.COMMENT: + case XMLStreamConstants.DTD: + case XMLStreamConstants.CDATA: + case XMLStreamConstants.CHARACTERS: + index.get(reader.text.trim()).add(entry) + break + case XMLStreamConstants.NAMESPACE: + for (int i = reader.namespaceCount - 1; i >= 0; i--) { + index.get(reader.getNamespacePrefix(i)).add(entry) + index.get(reader.getNamespaceURI(i)).add(entry) + } + break + } + } + } catch (Exception ignore) { + } finally { + reader?.close() + } + } +} diff --git a/services/src/main/groovy/jd/gui/service/indexer/ZipFileIndexerProvider.groovy b/services/src/main/groovy/jd/gui/service/indexer/ZipFileIndexerProvider.groovy new file mode 100644 index 00000000..70ee268f --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/indexer/ZipFileIndexerProvider.groovy @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.indexer + +import groovy.transform.CompileStatic +import jd.gui.api.API +import jd.gui.api.model.Container +import jd.gui.api.model.Indexes +import jd.gui.spi.Indexer + +import java.util.regex.Pattern + +class ZipFileIndexerProvider implements Indexer { + String[] getTypes() { ['*:file:*.zip', '*:file:*.jar'] } + + Pattern getPathPattern() { null } + + @CompileStatic + void index(API api, Container.Entry entry, Indexes indexes) { + for (def e : entry.children) { + if (e.isDirectory()) { + index(api, e, indexes) + } else { + api.getIndexer(e)?.index(api, e, indexes) + } + } + } +} diff --git a/services/src/main/groovy/jd/gui/service/pastehandler/LogPasteHandler.groovy b/services/src/main/groovy/jd/gui/service/pastehandler/LogPasteHandler.groovy new file mode 100644 index 00000000..d7c364fc --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/pastehandler/LogPasteHandler.groovy @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.pastehandler + +import jd.gui.api.API +import jd.gui.spi.PasteHandler +import jd.gui.view.component.LogPage + +class LogPasteHandler implements PasteHandler { + protected static int counter = 0 + + boolean accept(Object obj) { obj instanceof String } + + void paste(API api, Object obj) { + def title = 'clipboard-' + (++counter) + '.log' + def uri = URI.create('memory://' + title) + def content = obj?.toString() + api.addPanel(title, null, null, new LogPage(api, uri, content)) + } +} diff --git a/services/src/main/groovy/jd/gui/service/preferencespanel/ClassFileSaverPreferencesProvider.groovy b/services/src/main/groovy/jd/gui/service/preferencespanel/ClassFileSaverPreferencesProvider.groovy new file mode 100644 index 00000000..bcfd2676 --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/preferencespanel/ClassFileSaverPreferencesProvider.groovy @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.preferencespanel + +import jd.gui.spi.PreferencesPanel + +import javax.swing.JCheckBox +import javax.swing.JPanel +import java.awt.Color +import java.awt.GridLayout + +class ClassFileSaverPreferencesProvider extends JPanel implements PreferencesPanel { + + static final String ESCAPE_UNICODE_CHARACTERS = 'ClassFileSaverPreferences.escapeUnicodeCharacters' + static final String OMIT_THIS_PREFIX = 'ClassFileSaverPreferences.omitThisPrefix' + static final String REALIGN_LINE_NUMBERS = 'ClassFileSaverPreferences.realignLineNumbers' + static final String WRITE_DEFAULT_CONSTRUCTOR = 'ClassFileSaverPreferences.writeDefaultConstructor' + static final String WRITE_LINE_NUMBERS = 'ClassFileSaverPreferences.writeLineNumbers' + static final String WRITE_METADATA = 'ClassFileSaverPreferences.writeMetadata' + + JCheckBox escapeUnicodeCharactersCheckBox + JCheckBox omitThisPrefixCheckBox + JCheckBox realignLineNumbersCheckBox + JCheckBox writeDefaultConstructorCheckBox + JCheckBox writeLineNumbersCheckBox + JCheckBox writeMetadataCheckBox + + ClassFileSaverPreferencesProvider() { + super(new GridLayout(0,1)) + + escapeUnicodeCharactersCheckBox = new JCheckBox('Escape unicode characters') + omitThisPrefixCheckBox = new JCheckBox("Omit the prefix 'this' if possible") + realignLineNumbersCheckBox = new JCheckBox('Realign line numbers') + writeDefaultConstructorCheckBox = new JCheckBox('Write default constructor') + writeLineNumbersCheckBox = new JCheckBox('Write line numbers') + writeMetadataCheckBox = new JCheckBox('Write metadata') + + add(escapeUnicodeCharactersCheckBox) + add(omitThisPrefixCheckBox) + add(realignLineNumbersCheckBox) + add(writeDefaultConstructorCheckBox) + add(writeLineNumbersCheckBox) + add(writeMetadataCheckBox) + } + + // --- PreferencesPanel --- // + String getPreferencesGroupTitle() { 'Source Saver' } + String getPreferencesPanelTitle() { 'Class file' } + + public void init(Color errorBackgroundColor) {} + + void loadPreferences(Map preferences) { + escapeUnicodeCharactersCheckBox.selected = 'true'.equals(preferences.get(ESCAPE_UNICODE_CHARACTERS)) + omitThisPrefixCheckBox.selected = 'true'.equals(preferences.get(OMIT_THIS_PREFIX)) + realignLineNumbersCheckBox.selected = !'false'.equals(preferences.get(REALIGN_LINE_NUMBERS)) + writeDefaultConstructorCheckBox.selected = 'true'.equals(preferences.get(WRITE_DEFAULT_CONSTRUCTOR)) + writeLineNumbersCheckBox.selected = !'false'.equals(preferences.get(WRITE_LINE_NUMBERS)) + writeMetadataCheckBox.selected = !'false'.equals(preferences.get(WRITE_METADATA)) + } + + void savePreferences(Map preferences) { + preferences.put(ESCAPE_UNICODE_CHARACTERS, Boolean.toString(escapeUnicodeCharactersCheckBox.selected)) + preferences.put(OMIT_THIS_PREFIX, Boolean.toString(omitThisPrefixCheckBox.selected)) + preferences.put(REALIGN_LINE_NUMBERS, Boolean.toString(realignLineNumbersCheckBox.selected)) + preferences.put(WRITE_DEFAULT_CONSTRUCTOR, Boolean.toString(writeDefaultConstructorCheckBox.selected)) + preferences.put(WRITE_LINE_NUMBERS, Boolean.toString(writeLineNumbersCheckBox.selected)) + preferences.put(WRITE_METADATA, Boolean.toString(writeMetadataCheckBox.selected)) + } + + boolean arePreferencesValid() { true } + + void addPreferencesChangeListener(PreferencesPanel.PreferencesPanelChangeListener listener) {} +} diff --git a/services/src/main/groovy/jd/gui/service/preferencespanel/ClassFileViewerPreferencesProvider.groovy b/services/src/main/groovy/jd/gui/service/preferencespanel/ClassFileViewerPreferencesProvider.groovy new file mode 100644 index 00000000..850d7a48 --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/preferencespanel/ClassFileViewerPreferencesProvider.groovy @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.preferencespanel + +import jd.gui.spi.PreferencesPanel + +import javax.swing.JCheckBox +import javax.swing.JPanel +import java.awt.Color +import java.awt.GridLayout + +class ClassFileViewerPreferencesProvider extends JPanel implements PreferencesPanel { + static final String ESCAPE_UNICODE_CHARACTERS = 'ClassFileViewerPreferences.escapeUnicodeCharacters' + static final String OMIT_THIS_PREFIX = 'ClassFileViewerPreferences.omitThisPrefix' + static final String REALIGN_LINE_NUMBERS = 'ClassFileViewerPreferences.realignLineNumbers' + static final String DISPLAY_DEFAULT_CONSTRUCTOR = 'ClassFileViewerPreferences.displayDefaultConstructor' + static final String DISPLAY_LINE_NUMBERS = 'ClassFileViewerPreferences.displayLineNumbers' + + PreferencesPanel.PreferencesPanelChangeListener listener = null + JCheckBox escapeUnicodeCharactersCheckBox + JCheckBox omitThisPrefixCheckBox + JCheckBox realignLineNumbersCheckBox + JCheckBox displayDefaultConstructorCheckBox + JCheckBox displayLineNumbersCheckBox + + ClassFileViewerPreferencesProvider() { + super(new GridLayout(0,1)) + + escapeUnicodeCharactersCheckBox = new JCheckBox('Escape unicode characters') + omitThisPrefixCheckBox = new JCheckBox("Omit the prefix 'this' if possible") + realignLineNumbersCheckBox = new JCheckBox('Realign line numbers') + displayDefaultConstructorCheckBox = new JCheckBox('Display default constructor') + displayLineNumbersCheckBox = new JCheckBox('Display line numbers') + + add(escapeUnicodeCharactersCheckBox) + add(omitThisPrefixCheckBox) + add(realignLineNumbersCheckBox) + add(displayDefaultConstructorCheckBox) + add(displayLineNumbersCheckBox) + } + + // --- PreferencesPanel --- // + String getPreferencesGroupTitle() { 'Viewer' } + String getPreferencesPanelTitle() { 'Class file' } + + public void init(Color errorBackgroundColor) {} + + void loadPreferences(Map preferences) { + escapeUnicodeCharactersCheckBox.selected = !'false'.equals(preferences.get(ESCAPE_UNICODE_CHARACTERS)) + omitThisPrefixCheckBox.selected = 'true'.equals(preferences.get(OMIT_THIS_PREFIX)) + realignLineNumbersCheckBox.selected = 'true'.equals(preferences.get(REALIGN_LINE_NUMBERS)) + displayDefaultConstructorCheckBox.selected = 'true'.equals(preferences.get(DISPLAY_DEFAULT_CONSTRUCTOR)) + displayLineNumbersCheckBox.selected = !'false'.equals(preferences.get(DISPLAY_LINE_NUMBERS)) + } + + void savePreferences(Map preferences) { + preferences.put(ESCAPE_UNICODE_CHARACTERS, Boolean.toString(escapeUnicodeCharactersCheckBox.selected)) + preferences.put(OMIT_THIS_PREFIX, Boolean.toString(omitThisPrefixCheckBox.selected)) + preferences.put(REALIGN_LINE_NUMBERS, Boolean.toString(realignLineNumbersCheckBox.selected)) + preferences.put(DISPLAY_DEFAULT_CONSTRUCTOR, Boolean.toString(displayDefaultConstructorCheckBox.selected)) + preferences.put(DISPLAY_LINE_NUMBERS, Boolean.toString(displayLineNumbersCheckBox.selected)) + } + + boolean arePreferencesValid() { true } + + void addPreferencesChangeListener(PreferencesPanel.PreferencesPanelChangeListener listener) {} +} diff --git a/services/src/main/groovy/jd/gui/service/preferencespanel/DirectoryIndexerPreferencesProvider.groovy b/services/src/main/groovy/jd/gui/service/preferencespanel/DirectoryIndexerPreferencesProvider.groovy new file mode 100644 index 00000000..c37a4d5d --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/preferencespanel/DirectoryIndexerPreferencesProvider.groovy @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.preferencespanel + +import jd.gui.spi.PreferencesPanel + +import javax.swing.JLabel +import javax.swing.JPanel +import javax.swing.JTextField +import javax.swing.event.DocumentEvent +import javax.swing.event.DocumentListener +import java.awt.BorderLayout +import java.awt.Color + +class DirectoryIndexerPreferencesProvider extends JPanel implements PreferencesPanel, DocumentListener { + static final int MAX_VALUE = 30 + static final String MAXIMUM_DEPTH_KEY = 'DirectoryIndexerPreferences.maximumDepth' + + PreferencesPanel.PreferencesPanelChangeListener listener = null + JTextField maximumDepthTextField + Color errorBackgroundColor = Color.RED + Color defaultBackgroundColor + + DirectoryIndexerPreferencesProvider() { + super(new BorderLayout()) + + add(new JLabel('Maximum depth (1..' + MAX_VALUE + '): '), BorderLayout.WEST) + + maximumDepthTextField = new JTextField() + maximumDepthTextField.document.addDocumentListener(this) + add(maximumDepthTextField, BorderLayout.CENTER) + + defaultBackgroundColor = maximumDepthTextField.background + } + + // --- PreferencesPanel --- // + String getPreferencesGroupTitle() { 'Indexer' } + String getPreferencesPanelTitle() { 'Directory exploration' } + + public void init(Color errorBackgroundColor) { + this.errorBackgroundColor = errorBackgroundColor + } + + void loadPreferences(Map preferences) { + maximumDepthTextField.text = preferences.get(MAXIMUM_DEPTH_KEY) ?: '15' + maximumDepthTextField.setCaretPosition(maximumDepthTextField.text.size()) + } + + void savePreferences(Map preferences) { + preferences.put(MAXIMUM_DEPTH_KEY, maximumDepthTextField.text) + } + + boolean arePreferencesValid() { + try { + int i = Integer.valueOf(maximumDepthTextField.text) + return (i > 0) && (i <= MAX_VALUE) + } catch (NumberFormatException ignore) { + return false + } + } + + void addPreferencesChangeListener(PreferencesPanel.PreferencesPanelChangeListener listener) { + this.listener = listener + } + + // --- DocumentListener --- // + void insertUpdate(DocumentEvent e) { onTextChange() } + void removeUpdate(DocumentEvent e) { onTextChange() } + void changedUpdate(DocumentEvent e) { onTextChange() } + + void onTextChange() { + maximumDepthTextField.background = arePreferencesValid() ? defaultBackgroundColor : errorBackgroundColor + listener?.preferencesPanelChanged(this) + } +} diff --git a/services/src/main/groovy/jd/gui/service/sourcesaver/DirectorySourceSaverProvider.groovy b/services/src/main/groovy/jd/gui/service/sourcesaver/DirectorySourceSaverProvider.groovy new file mode 100644 index 00000000..db0a0e74 --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/sourcesaver/DirectorySourceSaverProvider.groovy @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.sourcesaver + +import groovy.transform.CompileStatic +import jd.gui.api.API +import jd.gui.api.model.Container +import jd.gui.spi.SourceSaver + +import java.nio.file.Files +import java.nio.file.Path +import java.util.regex.Pattern + +class DirectorySourceSaverProvider implements SourceSaver { + String[] getTypes() { ['*:dir:*'] } + + Pattern getPathPattern() { null } + + String getSourcePath(Container.Entry entry) { entry.path } + + int getFileCount(API api, Container.Entry entry) { getFileCount(api, entry.children) } + + @CompileStatic + protected int getFileCount(API api, Collection entries) { + int count = 0 + + for (def e : entries) { + count += api.getSourceSaver(e)?.getFileCount(api, e) + } + + return count + } + + void save(API api, SourceSaver.Controller controller, SourceSaver.Listener listener, Path path, Container.Entry entry) { + save(api, controller, listener, path, entry.children) + } + + @CompileStatic + protected void save(API api, SourceSaver.Controller controller, SourceSaver.Listener listener, Path path, Collection entries) { + Files.createDirectories(path) + + for (def e : entries) { + if (controller.isCancelled()) { + break + } + + def saver = api.getSourceSaver(e) + + if (saver) { + def sp = saver.getSourcePath(e) + def p = path.fileSystem.getPath(sp) + saver.save(api, controller, listener, p, e) + } + } + } +} diff --git a/services/src/main/groovy/jd/gui/service/sourcesaver/FileSourceSaverProvider.groovy b/services/src/main/groovy/jd/gui/service/sourcesaver/FileSourceSaverProvider.groovy new file mode 100644 index 00000000..023fe907 --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/sourcesaver/FileSourceSaverProvider.groovy @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.sourcesaver + +import groovy.transform.CompileStatic +import jd.gui.api.API +import jd.gui.api.model.Container +import jd.gui.spi.SourceSaver + +import java.nio.file.Files +import java.nio.file.Path +import java.util.regex.Pattern + +class FileSourceSaverProvider implements SourceSaver { + String[] getTypes() { ['*:file:*'] } + + Pattern getPathPattern() { null } + + String getSourcePath(Container.Entry entry) { entry.path } + + int getFileCount(API api, Container.Entry entry) { 1 } + + @CompileStatic + void save(API api, SourceSaver.Controller controller, SourceSaver.Listener listener, Path path, Container.Entry entry) { + listener.pathSaved(path) + + entry.inputStream.withStream { InputStream is -> + Files.copy(is, path) + } + } +} diff --git a/services/src/main/groovy/jd/gui/service/sourcesaver/PackageSourceSaverProvider.groovy b/services/src/main/groovy/jd/gui/service/sourcesaver/PackageSourceSaverProvider.groovy new file mode 100644 index 00000000..656bd995 --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/sourcesaver/PackageSourceSaverProvider.groovy @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.sourcesaver + +import jd.gui.api.API +import jd.gui.api.model.Container +import jd.gui.spi.SourceSaver +import jd.gui.util.JarContainerEntryUtil + +import java.nio.file.Path + +class PackageSourceSaverProvider extends DirectorySourceSaverProvider { + String[] getTypes() { ['jar:dir:*'] } + + void save(API api, SourceSaver.Controller controller, SourceSaver.Listener listener, Path path, Container.Entry entry) { + save(api, controller, listener, path, JarContainerEntryUtil.removeInnerTypeEntries(entry.children)) + } +} diff --git a/services/src/main/groovy/jd/gui/service/sourcesaver/ZipFileSourceSaverProvider.groovy b/services/src/main/groovy/jd/gui/service/sourcesaver/ZipFileSourceSaverProvider.groovy new file mode 100644 index 00000000..4c643d9f --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/sourcesaver/ZipFileSourceSaverProvider.groovy @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.sourcesaver + +import groovy.transform.CompileStatic +import jd.gui.api.API +import jd.gui.api.model.Container +import jd.gui.spi.SourceSaver + +import java.nio.file.FileSystems +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths + +class ZipFileSourceSaverProvider extends DirectorySourceSaverProvider { + + String[] getTypes() { ['*:file:*.zip', '*:file:*.jar'] } + + String getSourcePath(Container.Entry entry) { + def path = entry.path + return path.substring(0, path.length()-3) + 'src.zip' + } + + @CompileStatic + void save(API api, SourceSaver.Controller controller, SourceSaver.Listener listener, Path path, Container.Entry entry) { + def tmpFile = File.createTempFile('jd-gui.', '.tmp.zip') + tmpFile.delete() + + def env = new HashMap() + env.put('create', 'true') + + def tmpURI = URI.create('jar:' + tmpFile.toURI() + '!/') + def tmpFs = FileSystems.newFileSystem(tmpURI, env); + + super.save(api, controller, listener, tmpFs.getPath('/'), entry) + tmpFs.close() + + def tmpPath = Paths.get(tmpFile.absolutePath) + def srcZipParentPath = path.parent + + if (srcZipParentPath && !Files.exists(srcZipParentPath)) { + Files.createDirectories(srcZipParentPath) + } + + Files.move(tmpPath, path) + } +} diff --git a/services/src/main/groovy/jd/gui/service/treenode/ClassFileTreeNodeFactoryProvider.groovy b/services/src/main/groovy/jd/gui/service/treenode/ClassFileTreeNodeFactoryProvider.groovy new file mode 100644 index 00000000..f0997c7f --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/treenode/ClassFileTreeNodeFactoryProvider.groovy @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.treenode + +import groovy.transform.CompileStatic +import jd.gui.api.API +import jd.gui.api.feature.PageCreator +import jd.gui.api.feature.TreeNodeExpandable +import jd.gui.api.feature.UriGettable +import jd.gui.api.model.Container +import jd.gui.api.model.Type +import jd.gui.spi.TreeNodeFactory +import jd.gui.view.component.ClassFilePage +import jd.gui.view.data.TreeNodeBean + +import javax.swing.* +import javax.swing.tree.DefaultMutableTreeNode +import java.util.regex.Pattern + +class ClassFileTreeNodeFactoryProvider implements TreeNodeFactory { + static final ImageIcon classFileIcon = new ImageIcon(ClassFileTreeNodeFactoryProvider.class.classLoader.getResource('images/classf_obj.png')) + + static { + // Early class loading + try { + new ClassFilePage(null, null) + } catch (Exception ignore) {} + } + + String[] getTypes() { ['*:file:*.class'] } + + Pattern getPathPattern() { null } + + public T make(API api, Container.Entry entry) { + int lastSlashIndex = entry.path.lastIndexOf('/') + def name = entry.path.substring(lastSlashIndex+1) + return new ClassFileTreeNode(entry, new TreeNodeBean(label:name, icon: classFileIcon)) + } + + static abstract class AbstractTreeNode extends DefaultMutableTreeNode implements UriGettable, PageCreator { + Container.Entry entry + URI uri + + AbstractTreeNode(Container.Entry entry, String fragment, Object userObject) { + super(userObject) + this.entry = entry + + if (fragment) { + def uri = entry.uri + this.uri = new URI(uri.scheme, uri.host, uri.path, fragment) + } else { + this.uri = entry.uri + } + } + + URI getUri() { uri } + + public T createPage(API api) { + // Lazy 'tip' initialization + def file = new File(entry.container.root.uri) + def tip = "Location: $file.path" + + entry.inputStream.withStream { is -> + is.skip(4) // Skip magic number + int minorVersion = readUnsignedShort(is) + int majorVersion = readUnsignedShort(is) + + if (majorVersion >= 49) { + tip += "
Java compiler version: ${majorVersion - (49-5)} ($majorVersion.$minorVersion)" + } else if (majorVersion >= 45) { + tip += "
Java compiler version: 1.${majorVersion - (45-1)} ($majorVersion.$minorVersion)" + } + } + + tip += "" + + userObject.tip = tip + + return new ClassFilePage(api, entry) + } + + /** + * @see java.io.DataInputStream#readUnsignedShort() + */ + @CompileStatic + int readUnsignedShort(InputStream is) throws IOException { + int ch1 = is.read() + int ch2 = is.read() + if ((ch1 | ch2) < 0) + throw new EOFException() + return (ch1 << 8) + (ch2 << 0) + } + } + + static class ClassFileTreeNode extends AbstractTreeNode implements TreeNodeExpandable { + boolean initialized + + ClassFileTreeNode(Container.Entry entry, Object userObject) { + this(entry, null, userObject) + } + + ClassFileTreeNode(Container.Entry entry, String fragment, Object userObject) { + super(entry, fragment, userObject) + initialized = false + // Add dummy node + add(new DefaultMutableTreeNode()) + } + + void populateTreeNode(API api) { + if (!initialized) { + removeAllChildren() + // Create type node + def type = api.getTypeFactory(entry).make(api, entry, null) + add(new TypeTreeNode(entry, type, new TreeNodeBean(label: type.displayTypeName, icon: type.icon))) + initialized = true + } + } + } + + static class TypeTreeNode extends AbstractTreeNode implements TreeNodeExpandable { + boolean initialized + Type type + + TypeTreeNode(Container.Entry entry, Type type, Object userObject) { + super(entry, type.name, userObject) + this.initialized = false + this.type = type + // Add dummy node + add(new DefaultMutableTreeNode()) + } + + void populateTreeNode(API api) { + if (!initialized) { + removeAllChildren() + + def sb = new StringBuffer() + def typeAccess = type.flags + def typeName = type.name + def constructorName = type.displayInnerTypeName ?: type.displayTypeName + def isInnerClass = (type.displayInnerTypeName != null) + + // Create inner types + type.innerTypes.sort { t1, t2 -> + t1.name.compareTo(t2.name) + }.each { + add(new TypeTreeNode(entry, it, new TreeNodeBean(label: it.displayInnerTypeName, icon: it.icon))) + } + + // Create fields + type.fields.collect { + sb.setLength(0) + sb.append(it.name).append(' : ') + writeSignature(sb, it.descriptor, it.descriptor.length(), 0, false) + def label = sb.toString() + def fragment = typeName + '-' + it.name + '-' + it.descriptor + return new FieldOrMethodBean(fragment:fragment, label:label, icon:it.icon) + }.sort { f1, f2 -> + f1.label.compareTo(f2.label) + }.each { + add(new FieldOrMethodTreeNode(entry, it.fragment, new TreeNodeBean(label: it.label, icon: it.icon))) + } + + // Create methods + type.methods.collect { + sb.setLength(0) + writeMethodSignature(sb, typeAccess, it.flags, isInnerClass, constructorName, it.name, it.descriptor) + def label = sb.toString() + def fragment = typeName + '-' + it.name + '-' + it.descriptor + return new FieldOrMethodBean(fragment:fragment, label:label, icon:it.icon) + }.sort { m1, m2 -> + m1.label.compareTo(m2.label) + }.each { + add(new FieldOrMethodTreeNode(entry, it.fragment, new TreeNodeBean(label: it.label, icon: it.icon))) + } + + initialized = true + } + } + + int writeSignature(StringBuffer sb, String descriptor, int length, int index, boolean varargsFlag) { + while (true) { + // Print array : '[[?' ou '[L[?;' + int dimensionLength = 0 + + if (descriptor.charAt(index) == '[') { + dimensionLength++; + + while (++index < length) { + if ((descriptor.charAt(index) == 'L') && (index+1 < length) && (descriptor.charAt(index+1) == '[')) { + index++ + length-- + dimensionLength++; + } else if (descriptor.charAt(index) == '[') { + dimensionLength++ + } else { + break + } + } + } + + switch(descriptor.charAt(index)) { + case 'B': + sb.append('byte') + index++ + break + case 'C': + sb.append('char') + index++ + break + case 'D': + sb.append('double') + index++ + break + case 'F': + sb.append('float') + index++ + break + case 'I': + sb.append('int') + index++ + break + case 'J': + sb.append('long') + index++ + break + case 'L': case '.': + int beginIndex = ++index + char c = '.' + + // Search ; or de < + while (index < length) { + c = descriptor.charAt(index) + if ((c == ';') || (c == '<')) + break + index++ + } + + String internalClassName = descriptor.substring(beginIndex, index) + int lastPackageSeparatorIndex = internalClassName.lastIndexOf('/') + + if (lastPackageSeparatorIndex >= 0) { + // Cut package name + internalClassName = internalClassName.substring(lastPackageSeparatorIndex + 1) + } + + sb.append(internalClassName.replace('$', '.')) + + if (c == '<') { + sb.append('<') + index = writeSignature(sb, descriptor, length, index+1, false) + + while (descriptor.charAt(index) != '>') { + sb.append(', ') + index = writeSignature(sb, descriptor, length, index, false) + } + sb.append('>') + + // pass '>' + index++ + } + + // pass ';' + if (descriptor.charAt(index) == ';') + index++ + break + case 'S': + sb.append('short') + index++ + break + case 'T': + int beginIndex = ++index + index = descriptor.substring(beginIndex, length).indexOf(';') + sb.append(descriptor.substring(beginIndex, index)) + index++ + break; + case 'V': + sb.append('void') + index++ + break + case 'Z': + sb.append('boolean') + index++ + break + case '-': + sb.append('? ').append('super').append(' ') + index = writeSignature(sb, descriptor, length, index+1, false) + break; + case '+': + sb.append('? ').append('extends').append(' ') + index = writeSignature(sb, descriptor, length, index+1, false) + break; + case '*': + sb.append('?') + index++ + break + case 'X': case 'Y': + sb.append('int') + index++ + break + default: + throw new RuntimeException('SignatureWriter.WriteSignature: invalid signature "' + descriptor + '"') + } + + if (varargsFlag) + { + if (dimensionLength > 0) + { + while (--dimensionLength > 0) + sb.append('[]') + sb.append('...') + } + } + else + { + while (dimensionLength-- > 0) + sb.append('[]') + } + + + if ((index >= length) || (descriptor.charAt(index) != '.')) + break + + sb.append('.') + } + + return index + } + + void writeMethodSignature( + StringBuffer sb, int typeAccess, int methodAccess, boolean isInnerClass, + String constructorName, String methodName, String descriptor) { + if (methodName.equals('')) { + sb.append('{...}') + } else { + boolean isAConstructor = methodName.equals('') + + if (isAConstructor) { + sb.append(constructorName) + } else { + sb.append(methodName) + } + + // Skip generics + int length = descriptor.length() + int index = 0 + + while ((index < length) && (descriptor.charAt(index) != '(')) + index++ + + if (descriptor.charAt(index) != '(') { + throw RuntimeException('Signature format exception: "' + descriptor + '"'); + } + + sb.append('(') + + // pass '(' + index++ + + if (descriptor.charAt(index) != ')') { + if (isAConstructor && isInnerClass && ((typeAccess & Type.FLAG_STATIC) == 0)) { + // Skip first parameter + int lengthBackup = sb.length() + index = writeSignature(sb, descriptor, length, index, false) + sb.setLength(lengthBackup) + } + + if (descriptor.charAt(index) != ')') { + int varargsParameterIndex + + if ((methodAccess & Type.FLAG_VARARGS) == 0) { + varargsParameterIndex = Integer.MAX_VALUE + } else { + // Count parameters + int indexBackup = index + int lengthBackup = sb.length() + + varargsParameterIndex = -1 + + while (descriptor.charAt(index) != ')') { + index = writeSignature(sb, descriptor, length, index, false) + varargsParameterIndex++ + } + + index = indexBackup + sb.setLength(lengthBackup) + } + + // Write parameters + index = writeSignature(sb, descriptor, length, index, false) + + int parameterIndex = 1 + + while (descriptor.charAt(index) != ')') { + sb.append(', ') + index = writeSignature(sb, descriptor, length, index, (parameterIndex == varargsParameterIndex)) + parameterIndex++ + } + } + } + + if (isAConstructor) { + sb.append(')') + } else { + sb.append(') : ') + writeSignature(sb, descriptor, length, ++index, false) + } + } + } + } + + static class FieldOrMethodTreeNode extends AbstractTreeNode { + FieldOrMethodTreeNode(Container.Entry entry, String fragment, Object userObject) { + super(entry, fragment, userObject) + } + } + + static class FieldOrMethodBean { + String fragment, label + Icon icon + } +} diff --git a/services/src/main/groovy/jd/gui/service/treenode/DirectoryTreeNodeFactoryProvider.groovy b/services/src/main/groovy/jd/gui/service/treenode/DirectoryTreeNodeFactoryProvider.groovy new file mode 100644 index 00000000..1d5e656c --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/treenode/DirectoryTreeNodeFactoryProvider.groovy @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.treenode + +import jd.gui.api.API +import jd.gui.api.feature.TreeNodeExpandable +import jd.gui.api.feature.UriGettable +import jd.gui.api.model.Container +import jd.gui.api.model.Container.Entry +import jd.gui.spi.TreeNodeFactory +import jd.gui.view.data.TreeNodeBean + +import javax.swing.* +import javax.swing.tree.DefaultMutableTreeNode +import java.util.regex.Pattern + +class DirectoryTreeNodeFactoryProvider implements TreeNodeFactory { + static final ImageIcon icon = new ImageIcon(DirectoryTreeNodeFactoryProvider.class.classLoader.getResource('images/folder.gif')) + static final ImageIcon openIcon = new ImageIcon(DirectoryTreeNodeFactoryProvider.class.classLoader.getResource('images/folder_open.png')) + + String[] getTypes() { ['*:dir:*'] } + Pattern getPathPattern() { null } + + public T make(API api, Container.Entry entry) { + int lastSlashIndex = entry.path.lastIndexOf('/') + Entry[] entries = entry.children + + // Aggregate directory names + while (entries.length == 1) { + Entry child = entries[0] + if (child.isDirectory() == false) break + entry = child + entries = entry.children + } + + def label = entry.path.substring(lastSlashIndex+1) + def node = new TreeNode(entry, new TreeNodeBean(label:label, icon:getIcon(), openIcon:getOpenIcon())) + + if (entries.length > 0) { + // Add dummy node + node.add(new DefaultMutableTreeNode()) + } + + return node + } + + ImageIcon getIcon() { icon } + ImageIcon getOpenIcon() { openIcon } + + static class TreeNode extends DefaultMutableTreeNode implements UriGettable, TreeNodeExpandable { + Container.Entry entry + boolean initialized + + TreeNode(Container.Entry entry, Object userObject) { + super(userObject) + this.entry = entry + this.initialized = false + } + + // --- UriGettable --- // + URI getUri() { entry.uri } + + // --- TreeNodeExpandable --- // + void populateTreeNode(API api) { + if (!initialized) { + removeAllChildren() + + Entry[] entries = getChildren() + + while (entries.length == 1) { + Entry child = entries[0] + if (child.isDirectory() == false) break + entries = child.children + } + + for (Entry entry : entries) { + TreeNodeFactory factory = api.getTreeNodeFactory(entry) + if (factory) { + add(factory.make(api, entry)) + } + } + + initialized = true + } + } + + Collection getChildren() { entry.children } + } +} diff --git a/services/src/main/groovy/jd/gui/service/treenode/DtdFileTreeNodeFactoryProvider.groovy b/services/src/main/groovy/jd/gui/service/treenode/DtdFileTreeNodeFactoryProvider.groovy new file mode 100644 index 00000000..8bdc38fa --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/treenode/DtdFileTreeNodeFactoryProvider.groovy @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.treenode + +import jd.gui.api.API +import jd.gui.api.feature.UriGettable +import jd.gui.api.model.Container +import jd.gui.view.data.TreeNodeBean +import org.fife.ui.rsyntaxtextarea.SyntaxConstants + +import javax.swing.* +import javax.swing.tree.DefaultMutableTreeNode + +class DtdFileTreeNodeFactoryProvider extends TextFileTreeNodeFactoryProvider { + static final ImageIcon icon = new ImageIcon(DtdFileTreeNodeFactoryProvider.class.classLoader.getResource('images/dtd_obj.gif')) + + String[] getTypes() { ['*:file:*.dtd'] } + + public T make(API api, Container.Entry entry) { + int lastSlashIndex = entry.path.lastIndexOf('/') + def name = entry.path.substring(lastSlashIndex+1) + return new TreeNode(entry, new TreeNodeBean(label:name, icon:icon, tip:"Location: $entry.uri.path")) + } + + static class TreeNode extends TextFileTreeNodeFactoryProvider.TreeNode { + TreeNode(Container.Entry entry, Object userObject) { + super(entry, userObject) + } + + public T createPage(API api) { + return new TextFileTreeNodeFactoryProvider.Page(entry) { + String getSyntaxStyle() { + SyntaxConstants.SYNTAX_STYLE_DTD + } + } + } + } +} \ No newline at end of file diff --git a/services/src/main/groovy/jd/gui/service/treenode/FileTreeNodeFactoryProvider.groovy b/services/src/main/groovy/jd/gui/service/treenode/FileTreeNodeFactoryProvider.groovy new file mode 100644 index 00000000..ddb2682d --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/treenode/FileTreeNodeFactoryProvider.groovy @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.treenode + +import jd.gui.api.API +import jd.gui.api.feature.UriGettable +import jd.gui.api.model.Container +import jd.gui.spi.TreeNodeFactory +import jd.gui.view.data.TreeNodeBean + +import javax.swing.* +import javax.swing.tree.DefaultMutableTreeNode +import java.util.regex.Pattern + +class FileTreeNodeFactoryProvider implements TreeNodeFactory { + static final ImageIcon icon = new ImageIcon(FileTreeNodeFactoryProvider.class.classLoader.getResource('images/file_plain_obj.png')) + + String[] getTypes() { ['*:file:*'] } + + Pattern getPathPattern() { null } + + public T make(API api, Container.Entry entry) { + int lastSlashIndex = entry.path.lastIndexOf('/') + def name = entry.path.substring(lastSlashIndex+1) + return new TreeNode(entry, new TreeNodeBean(label:name, icon:icon)) + } + + static class TreeNode extends DefaultMutableTreeNode implements UriGettable { + Container.Entry entry + + TreeNode(Container.Entry entry, Object userObject) { + super(userObject) + this.entry = entry + } + + // --- UriGettable --- // + URI getUri() { entry.uri } + } +} diff --git a/services/src/main/groovy/jd/gui/service/treenode/HtmlFileTreeNodeFactoryProvider.groovy b/services/src/main/groovy/jd/gui/service/treenode/HtmlFileTreeNodeFactoryProvider.groovy new file mode 100644 index 00000000..9f44da45 --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/treenode/HtmlFileTreeNodeFactoryProvider.groovy @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.treenode + +import jd.gui.api.API +import jd.gui.api.feature.UriGettable +import jd.gui.api.model.Container +import jd.gui.view.data.TreeNodeBean +import org.fife.ui.rsyntaxtextarea.SyntaxConstants + +import javax.swing.* +import javax.swing.tree.DefaultMutableTreeNode + +class HtmlFileTreeNodeFactoryProvider extends TextFileTreeNodeFactoryProvider { + static final ImageIcon icon = new ImageIcon(HtmlFileTreeNodeFactoryProvider.class.classLoader.getResource('images/html_obj.gif')) + + String[] getTypes() { ['*:file:*.html'] } + + public T make(API api, Container.Entry entry) { + int lastSlashIndex = entry.path.lastIndexOf('/') + def name = entry.path.substring(lastSlashIndex+1) + return new TreeNode(entry, new TreeNodeBean(label:name, icon:icon, tip:"Location: $entry.uri.path")) + } + + static class TreeNode extends TextFileTreeNodeFactoryProvider.TreeNode { + TreeNode(Container.Entry entry, Object userObject) { + super(entry, userObject) + } + + public T createPage(API api) { + return new TextFileTreeNodeFactoryProvider.Page(entry) { + String getSyntaxStyle() { + SyntaxConstants.SYNTAX_STYLE_HTML + } + } + } + } +} \ No newline at end of file diff --git a/services/src/main/groovy/jd/gui/service/treenode/JarFileTreeNodeFactoryProvider.groovy b/services/src/main/groovy/jd/gui/service/treenode/JarFileTreeNodeFactoryProvider.groovy new file mode 100644 index 00000000..a82f4032 --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/treenode/JarFileTreeNodeFactoryProvider.groovy @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.treenode + +import jd.gui.api.API +import jd.gui.api.feature.UriGettable +import jd.gui.api.model.Container +import jd.gui.util.JarContainerEntryUtil +import jd.gui.view.data.TreeNodeBean + +import javax.swing.* +import javax.swing.tree.DefaultMutableTreeNode + +class JarFileTreeNodeFactoryProvider extends ZipFileTreeNodeFactoryProvider { + static final ImageIcon icon = new ImageIcon(JarFileTreeNodeFactoryProvider.class.classLoader.getResource('images/jar_obj.png')) + + String[] getTypes() { ['*:file:*.jar'] } + + public T make(API api, Container.Entry entry) { + int lastSlashIndex = entry.path.lastIndexOf('/') + def name = entry.path.substring(lastSlashIndex+1) + def node = new TreeNode(entry, 'jar', new TreeNodeBean(label:name, icon:icon)) + // Add dummy node + node.add(new DefaultMutableTreeNode()) + return node + } + + static class TreeNode extends ZipFileTreeNodeFactoryProvider.TreeNode { + TreeNode(Container.Entry entry, String containerType, Object userObject) { + super(entry, containerType, userObject) + } + + Collection getChildren() { JarContainerEntryUtil.removeInnerTypeEntries(entry.children) } + } +} diff --git a/services/src/main/groovy/jd/gui/service/treenode/JavascriptFileTreeNodeFactoryProvider.groovy b/services/src/main/groovy/jd/gui/service/treenode/JavascriptFileTreeNodeFactoryProvider.groovy new file mode 100644 index 00000000..c523a4a1 --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/treenode/JavascriptFileTreeNodeFactoryProvider.groovy @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.treenode + +import jd.gui.api.API +import jd.gui.api.feature.UriGettable +import jd.gui.api.model.Container +import jd.gui.view.data.TreeNodeBean +import org.fife.ui.rsyntaxtextarea.SyntaxConstants + +import javax.swing.* +import javax.swing.tree.DefaultMutableTreeNode + +class JavascriptFileTreeNodeFactoryProvider extends TextFileTreeNodeFactoryProvider { + static final ImageIcon icon = new ImageIcon(JavascriptFileTreeNodeFactoryProvider.class.classLoader.getResource('images/js_obj.png')) + + String[] getTypes() { ['*:file:*.js'] } + + public T make(API api, Container.Entry entry) { + int lastSlashIndex = entry.path.lastIndexOf('/') + def name = entry.path.substring(lastSlashIndex+1) + return new TreeNode(entry, new TreeNodeBean(label:name, icon:icon, tip:"Location: $entry.uri.path")) + } + + static class TreeNode extends TextFileTreeNodeFactoryProvider.TreeNode { + TreeNode(Container.Entry entry, Object userObject) { + super(entry, userObject) + } + + public T createPage(API api) { + return new TextFileTreeNodeFactoryProvider.Page(entry) { + String getSyntaxStyle() { + SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT + } + } + } + } +} \ No newline at end of file diff --git a/services/src/main/groovy/jd/gui/service/treenode/ManifestFileTreeNodeFactoryProvider.groovy b/services/src/main/groovy/jd/gui/service/treenode/ManifestFileTreeNodeFactoryProvider.groovy new file mode 100644 index 00000000..6b4d4a8d --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/treenode/ManifestFileTreeNodeFactoryProvider.groovy @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.treenode + +import jd.gui.api.API +import jd.gui.api.feature.PageCreator +import jd.gui.api.feature.UriGettable +import jd.gui.api.model.Container +import jd.gui.view.component.ManifestFilePage +import jd.gui.view.data.TreeNodeBean + +import javax.swing.* +import javax.swing.tree.DefaultMutableTreeNode + +class ManifestFileTreeNodeFactoryProvider extends FileTreeNodeFactoryProvider { + static + final ImageIcon icon = new ImageIcon(ManifestFileTreeNodeFactoryProvider.class.classLoader.getResource('images/manifest_obj.png')) + + String[] getTypes() { ['*:file:META-INF/MANIFEST.MF'] } + + public T make(API api, Container.Entry entry) { + return new TreeNode(entry, new TreeNodeBean(label: 'MANIFEST.MF', icon: icon, tip:"Location: $entry.uri.path")) + } + + static class TreeNode extends FileTreeNodeFactoryProvider.TreeNode implements PageCreator { + TreeNode(Container.Entry entry, Object userObject) { + super(entry, userObject) + } + // --- PageCreator --- // + public T createPage(API api) { + return new ManifestFilePage(api, entry) + } + } +} diff --git a/services/src/main/groovy/jd/gui/service/treenode/MetainfDirectoryTreeNodeFactoryProvider.groovy b/services/src/main/groovy/jd/gui/service/treenode/MetainfDirectoryTreeNodeFactoryProvider.groovy new file mode 100644 index 00000000..767f1524 --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/treenode/MetainfDirectoryTreeNodeFactoryProvider.groovy @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.treenode + +import java.util.regex.Pattern + +class MetainfDirectoryTreeNodeFactoryProvider extends DirectoryTreeNodeFactoryProvider { + Pattern pattern = ~/META-IN(F|F\/.*)/ + + String[] getTypes() { ['jar:dir:*'] } + + Pattern getPathPattern() { pattern } +} diff --git a/services/src/main/groovy/jd/gui/service/treenode/MetainfServiceFileTreeNodeFactoryProvider.groovy b/services/src/main/groovy/jd/gui/service/treenode/MetainfServiceFileTreeNodeFactoryProvider.groovy new file mode 100644 index 00000000..a5ef6cb5 --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/treenode/MetainfServiceFileTreeNodeFactoryProvider.groovy @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.treenode + +import java.util.regex.Pattern + +class MetainfServiceFileTreeNodeFactoryProvider extends TextFileTreeNodeFactoryProvider { + Pattern pattern = ~/META-INF\/services\/[^\/]+/ + + String[] getTypes() { ['*:file:*'] } + + Pattern getPathPattern() { pattern } +} diff --git a/services/src/main/groovy/jd/gui/service/treenode/PackageTreeNodeFactoryProvider.groovy b/services/src/main/groovy/jd/gui/service/treenode/PackageTreeNodeFactoryProvider.groovy new file mode 100644 index 00000000..f97e03b2 --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/treenode/PackageTreeNodeFactoryProvider.groovy @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.treenode + +import jd.gui.api.API +import jd.gui.api.feature.UriGettable +import jd.gui.api.model.Container +import jd.gui.spi.TreeNodeFactory +import jd.gui.util.JarContainerEntryUtil +import jd.gui.view.data.TreeNodeBean + +import javax.swing.* +import javax.swing.tree.DefaultMutableTreeNode +import java.util.regex.Pattern + +class PackageTreeNodeFactoryProvider extends DirectoryTreeNodeFactoryProvider { + static final ImageIcon icon = new ImageIcon(PackageTreeNodeFactoryProvider.class.classLoader.getResource('images/package_obj.png')) + + String[] getTypes() { ['jar:dir:*'] } + + Pattern getPathPattern() { null } + + public T make(API api, Container.Entry entry) { + int lastSlashIndex = entry.path.lastIndexOf('/') + Container.Entry[] entries = entry.children + + // Aggregate directory names + while (entries.length == 1) { + Container.Entry child = entries[0] + if (child.isDirectory() == false) break + entry = child + entries = entry.children + } + + def label = entry.path.substring(lastSlashIndex+1).replace('/', '.') + def node = new TreeNode(entry, new TreeNodeBean(label:label, icon:getIcon(), openIcon:getOpenIcon())) + + if (entries.length > 0) { + // Add dummy node + node.add(new DefaultMutableTreeNode()) + } + + return node + } + + ImageIcon getIcon() { icon } + ImageIcon getOpenIcon() { null } + + static class TreeNode extends DirectoryTreeNodeFactoryProvider.TreeNode { + TreeNode(Container.Entry entry, Object userObject) { + super(entry, userObject) + } + + Collection getChildren() { + return JarContainerEntryUtil.removeInnerTypeEntries(entry.children) + } + } +} diff --git a/services/src/main/groovy/jd/gui/service/treenode/PropertiesFileTreeNodeFactoryProvider.groovy b/services/src/main/groovy/jd/gui/service/treenode/PropertiesFileTreeNodeFactoryProvider.groovy new file mode 100644 index 00000000..48d5f71d --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/treenode/PropertiesFileTreeNodeFactoryProvider.groovy @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.treenode + +import jd.gui.api.API +import jd.gui.api.feature.UriGettable +import jd.gui.api.model.Container +import jd.gui.view.data.TreeNodeBean +import org.fife.ui.rsyntaxtextarea.SyntaxConstants + +import javax.swing.* +import javax.swing.tree.DefaultMutableTreeNode + +class PropertiesFileTreeNodeFactoryProvider extends TextFileTreeNodeFactoryProvider { + static final ImageIcon icon = new ImageIcon(PropertiesFileTreeNodeFactoryProvider.class.classLoader.getResource('images/ascii_obj.png')) + + String[] getTypes() { ['*:file:*.properties'] } + + public T make(API api, Container.Entry entry) { + int lastSlashIndex = entry.path.lastIndexOf('/') + def name = entry.path.substring(lastSlashIndex+1) + return new TreeNode(entry, new TreeNodeBean(label:name, icon:icon, tip:"Location: $entry.uri.path")) + } + + static class TreeNode extends TextFileTreeNodeFactoryProvider.TreeNode { + TreeNode(Container.Entry entry, Object userObject) { + super(entry, userObject) + } + + public T createPage(API api) { + return new TextFileTreeNodeFactoryProvider.Page(entry) { + String getSyntaxStyle() { + SyntaxConstants.SYNTAX_STYLE_PROPERTIES_FILE + } + } + } + } +} \ No newline at end of file diff --git a/services/src/main/groovy/jd/gui/service/treenode/TextFileTreeNodeFactoryProvider.groovy b/services/src/main/groovy/jd/gui/service/treenode/TextFileTreeNodeFactoryProvider.groovy new file mode 100644 index 00000000..2111f0cb --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/treenode/TextFileTreeNodeFactoryProvider.groovy @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.treenode + +import jd.gui.api.API +import jd.gui.api.feature.ContentSavable +import jd.gui.api.feature.PageCreator +import jd.gui.api.feature.UriGettable +import jd.gui.api.model.Container +import jd.gui.view.component.TextPage +import jd.gui.view.data.TreeNodeBean +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea +import org.fife.ui.rsyntaxtextarea.Theme +import org.fife.ui.rtextarea.Gutter + +import javax.swing.* +import javax.swing.tree.DefaultMutableTreeNode + +class TextFileTreeNodeFactoryProvider extends FileTreeNodeFactoryProvider { + static final ImageIcon icon = new ImageIcon(TextFileTreeNodeFactoryProvider.class.classLoader.getResource('images/ascii_obj.png')) + + static { + // Early class loading + new Gutter(new RSyntaxTextArea()) + Theme.load(TextFileTreeNodeFactoryProvider.class.classLoader.getResourceAsStream('rsyntaxtextarea/themes/eclipse.xml')) + } + + String[] getTypes() { ['*:file:*.txt'] } + + public T make(API api, Container.Entry entry) { + int lastSlashIndex = entry.path.lastIndexOf('/') + def name = entry.path.substring(lastSlashIndex+1) + return new TreeNode(entry, new TreeNodeBean(label:name, icon:icon, tip:"Location: $entry.uri.path")) + } + + static class TreeNode extends FileTreeNodeFactoryProvider.TreeNode implements PageCreator { + TreeNode(Container.Entry entry, Object userObject) { + super(entry, userObject) + } + + public T createPage(API api) { + return new Page(entry) + } + } + + static class Page extends TextPage implements UriGettable, ContentSavable { + Container.Entry entry + + Page(Container.Entry entry) { + this.entry = entry + setText(entry.inputStream.text) + } + + // --- UriGettable --- // + URI getUri() { entry.uri } + + // --- SourceSavable --- // + String getFileName() { + def path = entry.path + int index = path.lastIndexOf('/') + return path.substring(index+1) + } + + void save(API api, OutputStream os) { + os << textArea.text + } + } +} \ No newline at end of file diff --git a/services/src/main/groovy/jd/gui/service/treenode/XmlFileTreeNodeFactoryProvider.groovy b/services/src/main/groovy/jd/gui/service/treenode/XmlFileTreeNodeFactoryProvider.groovy new file mode 100644 index 00000000..dbe80d8a --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/treenode/XmlFileTreeNodeFactoryProvider.groovy @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.treenode + +import jd.gui.api.API +import jd.gui.api.feature.UriGettable +import jd.gui.api.model.Container +import jd.gui.view.data.TreeNodeBean +import org.fife.ui.rsyntaxtextarea.SyntaxConstants + +import javax.swing.* +import javax.swing.tree.DefaultMutableTreeNode + +class XmlFileTreeNodeFactoryProvider extends TextFileTreeNodeFactoryProvider { + static final ImageIcon icon = new ImageIcon(XmlFileTreeNodeFactoryProvider.class.classLoader.getResource('images/xml_obj.gif')) + + String[] getTypes() { ['*:file:*.xml', '*:file:*.xsl', '*:file:*.xslt', '*:file:*.xsd'] } + + public T make(API api, Container.Entry entry) { + int lastSlashIndex = entry.path.lastIndexOf('/') + def name = entry.path.substring(lastSlashIndex+1) + return new TreeNode(entry, new TreeNodeBean(label:name, icon:icon, tip:"Location: $entry.uri.path")) + } + + static class TreeNode extends TextFileTreeNodeFactoryProvider.TreeNode { + TreeNode(Container.Entry entry, Object userObject) { + super(entry, userObject) + } + + public T createPage(API api) { + return new TextFileTreeNodeFactoryProvider.Page(entry) { + String getSyntaxStyle() { + SyntaxConstants.SYNTAX_STYLE_PROPERTIES_FILE + } + } + } + } +} \ No newline at end of file diff --git a/services/src/main/groovy/jd/gui/service/treenode/ZipFileTreeNodeFactoryProvider.groovy b/services/src/main/groovy/jd/gui/service/treenode/ZipFileTreeNodeFactoryProvider.groovy new file mode 100644 index 00000000..d1f8579f --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/treenode/ZipFileTreeNodeFactoryProvider.groovy @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.treenode + +import jd.gui.api.API +import jd.gui.api.feature.UriGettable +import jd.gui.api.model.Container +import jd.gui.spi.TreeNodeFactory +import jd.gui.view.data.TreeNodeBean + +import javax.swing.* +import javax.swing.tree.DefaultMutableTreeNode +import java.util.regex.Pattern + +class ZipFileTreeNodeFactoryProvider extends DirectoryTreeNodeFactoryProvider { + static final ImageIcon icon = new ImageIcon(ZipFileTreeNodeFactoryProvider.class.classLoader.getResource('images/zip_obj.png')) + + String[] getTypes() { ['*:file:*.zip'] } + Pattern getPathPattern() { null } + + public T make(API api, Container.Entry entry) { + int lastSlashIndex = entry.path.lastIndexOf('/') + def name = entry.path.substring(lastSlashIndex+1) + def node = new TreeNode(entry, 'generic', new TreeNodeBean(label:name, icon:icon)) + // Add dummy node + node.add(new DefaultMutableTreeNode()) + return node + } + + static class TreeNode extends DirectoryTreeNodeFactoryProvider.TreeNode { + String ct + + TreeNode(Container.Entry entry, String containerType, Object userObject) { + super(entry, userObject) + ct = containerType + } + + // --- TreeNodeExpandable --- // + void populateTreeNode(API api) { + if (!initialized) { + removeAllChildren() + + for (def e : getChildren()) { + TreeNodeFactory factory = api.getTreeNodeFactory(e) + if (factory) { + add(factory.make(api, e)) + } + } + + initialized = true + } + } + } +} diff --git a/services/src/main/groovy/jd/gui/service/uriloader/FileUriLoaderProvider.groovy b/services/src/main/groovy/jd/gui/service/uriloader/FileUriLoaderProvider.groovy new file mode 100644 index 00000000..33181d9c --- /dev/null +++ b/services/src/main/groovy/jd/gui/service/uriloader/FileUriLoaderProvider.groovy @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.uriloader + +import jd.gui.api.API +import jd.gui.spi.UriLoader + +class FileUriLoaderProvider implements UriLoader { + + String[] getSchemes() { ['file'] } + + boolean accept(API api, URI uri) { 'file'.equals(uri.scheme) } + + boolean load(API api, URI uri) { + File file = new File(uri.path) + return api.getFileLoader(file)?.load(api, file) + } +} diff --git a/services/src/main/groovy/jd/gui/util/JarContainerEntryUtil.groovy b/services/src/main/groovy/jd/gui/util/JarContainerEntryUtil.groovy new file mode 100644 index 00000000..b3c9382b --- /dev/null +++ b/services/src/main/groovy/jd/gui/util/JarContainerEntryUtil.groovy @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.util + +import groovyjarjarasm.asm.ClassReader +import groovyjarjarasm.asm.tree.ClassNode +import groovyjarjarasm.asm.tree.InnerClassNode +import jd.gui.api.model.Container + +class JarContainerEntryUtil { + static Collection removeInnerTypeEntries(Collection entries) { + def potentialOuterTypePaths = new HashSet() + def filtredSubEntries + + for (def e : entries) { + if (!e.isDirectory()) { + String p = e.path + + if (p.toLowerCase().endsWith('.class')) { + int lastSeparatorIndex = p.lastIndexOf('/') + int dollarIndex = p.substring(lastSeparatorIndex+1).indexOf('$') + + if (dollarIndex != -1) { + potentialOuterTypePaths.add(p.substring(0, lastSeparatorIndex+1+dollarIndex) + '.class') + } + } + } + } + + if (potentialOuterTypePaths.size() == 0) { + filtredSubEntries = entries + } else { + def innerTypePaths = new HashSet() + + for (def e : entries) { + if (!e.isDirectory() && potentialOuterTypePaths.contains(e.path)) { + populateInnerTypePaths(innerTypePaths, e) + } + } + + filtredSubEntries = new ArrayList() + + for (def e : entries) { + if (!e.isDirectory()) { + String p = e.path + + if (p.toLowerCase().endsWith('.class')) { + int indexDollar = p.lastIndexOf('$') + + if (indexDollar != -1) { + int indexSeparator = p.lastIndexOf('/') + + if (indexDollar > indexSeparator) { + if (innerTypePaths.contains(p)) { + // Inner class found -> Skip + continue + } else { + populateInnerTypePaths(innerTypePaths, e) + + if (innerTypePaths.contains(p)) { + // Inner class found -> Skip + continue + } + } + } + } + } + } + // Valid path + filtredSubEntries.add(e) + } + } + + return filtredSubEntries.sort() + } + + protected static void populateInnerTypePaths(HashSet innerTypePaths, Container.Entry entry) { + def classNode = new ClassNode() + def classReader = entry.inputStream.withStream { InputStream is -> new ClassReader(is) } + def p = entry.path + def prefixPath = p.substring(0, p.length() - classReader.className.length() - 6) + + classReader.accept(classNode, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES) + + for (def obj : classNode.innerClasses) { + def innerClass = obj as InnerClassNode + innerTypePaths.add(prefixPath + innerClass.name + '.class') + } + } +} diff --git a/services/src/main/groovy/jd/gui/view/component/ClassFilePage.groovy b/services/src/main/groovy/jd/gui/view/component/ClassFilePage.groovy new file mode 100644 index 00000000..ed2a44a5 --- /dev/null +++ b/services/src/main/groovy/jd/gui/view/component/ClassFilePage.groovy @@ -0,0 +1,657 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view.component + +import groovy.transform.CompileStatic +import jd.core.Decompiler +import jd.core.loader.Loader +import jd.core.loader.LoaderException +import jd.core.process.DecompilerImpl +import jd.gui.api.API +import jd.gui.api.feature.* +import jd.gui.api.model.Container +import jd.gui.api.model.Indexes +import jd.gui.util.decompiler.ClassFileSourcePrinter +import jd.gui.util.decompiler.ContainerLoader +import jd.gui.util.decompiler.GuiPreferences +import org.fife.ui.rsyntaxtextarea.DocumentRange +import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities +import org.fife.ui.rsyntaxtextarea.SyntaxConstants + +import javax.swing.text.DefaultCaret +import java.awt.Color +import java.awt.Point +import java.util.regex.Pattern + +class ClassFilePage + extends SourcePage + implements UriGettable, ContentSavable, IndexesChangeListener, LineNumberNavigable, FocusedTypeGettable, PreferencesChangeListener { + + protected static final String ESCAPE_UNICODE_CHARACTERS = 'ClassFileViewerPreferences.escapeUnicodeCharacters' + protected static final String OMIT_THIS_PREFIX = 'ClassFileViewerPreferences.omitThisPrefix' + protected static final String REALIGN_LINE_NUMBERS = 'ClassFileViewerPreferences.realignLineNumbers' + protected static final String DISPLAY_DEFAULT_CONSTRUCTOR = 'ClassFileViewerPreferences.displayDefaultConstructor' + protected static final String DISPLAY_LINE_NUMBERS = 'ClassFileViewerPreferences.displayLineNumbers' + + protected static final Decompiler DECOMPILER = new DecompilerImpl() + + protected API api + protected Container.Entry entry + protected Collection collectionOfIndexes + + protected ArrayList references = new ArrayList<>() + protected HashMap declarations = new HashMap<>() + protected TreeMap typeDeclarations = new TreeMap<>() + protected ArrayList strings = new ArrayList<>() + + protected int maximumLineNumber = -1 + + static { + // Early class loading + def internalPath = ClassFilePage.class.name.replace('.', '/') + def preferences = new GuiPreferences() + def loader = new Loader() { + DataInputStream load(String internalTypePath) throws LoaderException { + return new DataInputStream(ClassFilePage.class.classLoader.getResourceAsStream(internalPath + '.class')) + } + boolean canLoad(String internalTypePath) { false } + } + def printer = new ClassFileSourcePrinter() { + boolean isShowLineNumbers() { false } + boolean getRealignmentLineNumber() { false } + boolean isShowPrefixThis() { false } + boolean isUnicodeEscape() { false } + void append(char c) {} + void append(String s) {} + } + DECOMPILER.decompile(preferences, loader, printer, internalPath) + } + + ClassFilePage(API api, Container.Entry entry) { + // Init attributes + this.api = api + this.entry = entry + // Init view + errorForeground = Color.decode(api.preferences.get('JdGuiPreferences.errorBackgroundColor')) + // Display source + decompile(api.preferences) + } + + void decompile(Map preferences) { + try { + // Clear ... + clearHyperlinks() + clearLineNumbers() + declarations.clear() + typeDeclarations.clear() + strings.clear() + + // Init preferences + def p = new GuiPreferences() + p.setUnicodeEscape(getPreferenceValue(preferences, ESCAPE_UNICODE_CHARACTERS, false)) + p.setShowPrefixThis(! getPreferenceValue(preferences, OMIT_THIS_PREFIX, false)); + p.setShowDefaultConstructor(getPreferenceValue(preferences, DISPLAY_DEFAULT_CONSTRUCTOR, false)) + p.setShowLineNumbers(getPreferenceValue(preferences, DISPLAY_LINE_NUMBERS, true)) + p.setRealignmentLineNumber(getPreferenceValue(preferences, REALIGN_LINE_NUMBERS, false)) + + setShowMisalignment(p.realignmentLineNumber) + + // Init loader + def loader = new ContainerLoader(entry) + + // Init printer + def printer = new Printer(p) + + // Decompile class file + DECOMPILER.decompile(p, loader, printer, entry.path) + + setText(printer.toString()) + + // Show hyperlinks + indexesChanged(api.collectionOfIndexes) + } catch (Exception ignore) { + setText('// INTERNAL ERROR //') + ignore.printStackTrace() + } + + maximumLineNumber = getMaximumSourceLineNumber() + } + + String getSyntaxStyle() { SyntaxConstants.SYNTAX_STYLE_JAVA } + + protected boolean isHyperlinkEnabled(HyperlinkPage.HyperlinkData hyperlinkData) { hyperlinkData.reference.enabled } + + protected void openHyperlink(int x, int y, HyperlinkPage.HyperlinkData hyperlinkData) { + if (hyperlinkData.reference.enabled) { + // Save current position in history + def location = textArea.getLocationOnScreen() + int offset = textArea.viewToModel(new Point(x-location.x as int, y-location.y as int)) + def uri = entry.uri + api.addURI(new URI(uri.scheme, uri.authority, uri.path, 'position=' + offset, null)) + + // Open link + def reference = hyperlinkData.reference + def typeName = reference.type + def entries = collectionOfIndexes?.collect { it.getIndex('typeDeclarations')?.get(typeName) }.flatten().grep { it!=null } + def rootUri = entry.container.root.uri.toString() + def sameContainerEntries = entries?.grep { it.uri.toString().startsWith(rootUri) } + def fragment = typeName + + if (reference.name) { + fragment += '-' + reference.name + } + if (reference.descriptor) { + fragment += '-' + reference.descriptor + } + + if (sameContainerEntries) { + api.openURI(x, y, sameContainerEntries, null, fragment) + } else if (entries) { + api.openURI(x, y, entries, null, fragment) + } + } + } + + // --- UriGettable --- // + URI getUri() { entry.uri } + + // --- SourceSavable --- // + String getFileName() { + def path = entry.path + int index = path.lastIndexOf('.') + return path.substring(index+1) + '.java' + } + + void save(API api, OutputStream os) { + os << textArea.text + } + + // --- IndexesChangeListener --- // + @CompileStatic + void indexesChanged(Collection collectionOfIndexes) { + // Update the list of containers + this.collectionOfIndexes = collectionOfIndexes + // Refresh links + boolean refresh = false + + for (def reference : references) { + def typeName = reference.type + boolean enabled + + if (reference.name) { + typeName = searchTypeHavingMember(typeName, reference.name, reference.descriptor, entry) + if (typeName) { + // Replace type with the real type containing the referenced member + reference.type = typeName + enabled = true + } else { + enabled = false + } + } else { + enabled = collectionOfIndexes.find { it.getIndex('typeDeclarations')?.get(typeName) } != null + } + + if (reference.enabled != enabled) { + reference.enabled = enabled + refresh = true + } + } + + if (refresh) { + textArea.repaint() + } + } + + protected String searchTypeHavingMember(String typeName, String name, String descriptor, Container.Entry entry) { + def entries = collectionOfIndexes?.collect { it.getIndex('typeDeclarations')?.get(typeName) }.flatten().grep { it!=null } + def rootUri = entry.container.root.uri.toString() + def sameContainerEntries = entries?.grep { Container.Entry e -> e.uri.toString().startsWith(rootUri) } + + if (sameContainerEntries) { + return searchTypeHavingMember(typeName, name, descriptor, sameContainerEntries) + } else { + return searchTypeHavingMember(typeName, name, descriptor, entries) + } + } + + @CompileStatic + protected String searchTypeHavingMember(String typeName, String name, String descriptor, List entries) { + for (def entry : entries) { + def type = api.getTypeFactory(entry).make(api, entry, null) + + if (type) { + if (descriptor.indexOf('(') == -1) { + // Search a field + for (def field : type.fields) { + if (field.name.equals(name) && field.descriptor.equals(descriptor)) { + // Field found + return typeName + } + } + } else { + // Search a method + for (def method : type.methods) { + if (method.name.equals(name) && method.descriptor.equals(descriptor)) { + // Method found + return typeName + } + } + } + + // Not found -> Search in super type + def typeOwnerName = searchTypeHavingMember(type.superName, name, descriptor, entry) + if (typeOwnerName) { + return typeOwnerName + } + } + } + + return null + } + + // --- LineNumberNavigable --- // + int getMaximumLineNumber() { maximumLineNumber } + + void goToLineNumber(int lineNumber) { + int textAreaLineNumber = getTextAreaLineNumber(lineNumber) + if (textAreaLineNumber > 0) { + textArea.caretPosition = textArea.getLineStartOffset(textAreaLineNumber-1) + } + } + + boolean checkLineNumber(int lineNumber) { lineNumber <= maximumLineNumber } + + // --- UriOpenable --- // + boolean openUri(URI uri) { + List ranges = [] + def fragment = uri.fragment + def query = uri.query + + if (fragment) { + int index = fragment.indexOf('?') + + if (index == -1) { + // Known descriptor ==> Search and high light item + def data = declarations.get(fragment) + if (data) { + ranges.add(new DocumentRange(data.startPosition, data.endPosition)) + } + } else { + // Unknown descriptor ==> Select all and scroll to the first one + def prefix = fragment.substring(0, fragment.lastIndexOf('-' + 1)) + boolean method = (fragment.charAt(index - 1) == '(') + int prefixLength = prefix.size() + + for (def entry : declarations.entrySet()) { + if (entry.key.startsWith(prefix)) { + def flag = (entry.key.charAt(prefixLength) == '(') + if (method == flag) { + ranges.add(new DocumentRange(entry.value.startPosition, entry.value.endPosition)) + } + } + } + } + } + + if (query) { + Map parameters = parseQuery(query) + + if (parameters.containsKey('lineNumber')) { + def lineNumber = parameters.get('lineNumber') + if (lineNumber.isNumber()) { + goToLineNumber(lineNumber.toInteger()) + return true + } + } else if (parameters.containsKey('position')) { + def position = parameters.get('position') + if (position.isNumber()) { + int pos = position.toInteger() + if (textArea.document.length > pos) { + ranges.add(new DocumentRange(pos, pos)) + } + } + } else { + def highlightFlags = parameters.get('highlightFlags') + def highlightPattern = parameters.get('highlightPattern') + + if (highlightFlags && highlightPattern) { + def highlightScope = parameters.get('highlightScope') + def regexp = createRegExp(parameters.get('highlightPattern')) + def pattern = Pattern.compile(regexp + '.*') + + if (highlightFlags.indexOf('s') != -1) { + // Highlight strings + def patternForString = Pattern.compile(regexp) + + for (def data : strings) { + if (!highlightScope || data.owner.equals(highlightScope)) { + def matcher = patternForString.matcher(data.text) + int offset = data.startPosition + + while(matcher.find()) { + ranges.add(new DocumentRange(offset + matcher.start(), offset + matcher.end())) + } + } + } + } + + boolean t = (highlightFlags.indexOf('t') != -1) + boolean f = (highlightFlags.indexOf('f') != -1) + boolean m = (highlightFlags.indexOf('m') != -1) + boolean c = (highlightFlags.indexOf('c') != -1) + + if (highlightFlags.indexOf('d') != -1) { + // Highlight declarations + for (def entry : declarations.entrySet()) { + def declaration = entry.value + + if (!highlightScope || declaration.type.equals(highlightScope)) { + if ((t && declaration.isAType()) || (c && declaration.isAConstructor())) { + matchAndAddDocumentRange(pattern, getMostInnerTypeName(declaration.type), declaration.startPosition, declaration.endPosition, ranges) + } else if ((f && declaration.isAField()) || (m && declaration.isAMethod())) { + matchAndAddDocumentRange(pattern, declaration.name, declaration.startPosition, declaration.endPosition, ranges) + } + } + } + } + + if (highlightFlags.indexOf('r') != -1) { + // Highlight references + for (def hyperlink : hyperlinks.entrySet()) { + ReferenceData reference = hyperlink.reference as ReferenceData + + if (!highlightScope || reference.owner.equals(highlightScope)) { + if ((t && reference.isAType()) || (c && reference.isAConstructor())) { + matchAndAddDocumentRange(pattern, getMostInnerTypeName(reference.type), reference.startPosition, reference.endPosition, ranges) + } else if ((f && reference.isAField()) || (m && reference.isAMethod())) { + matchAndAddDocumentRange(pattern, reference.name, reference.startPosition, reference.endPosition, ranges) + } + } + } + } + } + } + } + + if (ranges) { + textArea.markAllHighlightColor = searchHighlightColor + textArea.highlighter.clearMarkAllHighlights() + textArea.markAll(ranges) + + ranges.sort() + + def first = ranges[0] + RSyntaxUtilities.selectAndPossiblyCenter(textArea, first, false) + textArea.caretPosition = first.startOffset + } + } + + @CompileStatic + void matchAndAddDocumentRange(Pattern pattern, String text, int start, int end, List ranges) { + if (pattern.matcher(text).matches()) { + ranges.add(new DocumentRange(start, end)) + } + } + + @CompileStatic + String getMostInnerTypeName(String typeName) { + int lastPackageSeparatorIndex = typeName.lastIndexOf('/') + 1 + int lastTypeNameSeparatorIndex = typeName.lastIndexOf('$') + 1 + int lastIndex = Math.max(lastPackageSeparatorIndex, lastTypeNameSeparatorIndex) + return typeName.substring(lastIndex) + } + + // --- FocusedTypeGettable --- // + String getFocusedTypeName() { typeDeclarations.floorEntry(textArea.caretPosition)?.value.type } + + Container.Entry getEntry() { entry } + + // --- PreferencesChangeListener --- // + void preferencesChanged(Map preferences) { + def caret = textArea.caret + int updatePolicy = caret.updatePolicy + + caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE); + decompile(preferences) + caret.setUpdatePolicy(updatePolicy) + } + + @CompileStatic + class Printer extends ClassFileSourcePrinter { + protected StringBuffer stringBuffer + protected boolean showLineNumbers + protected boolean realignmentLineNumber + protected boolean showPrefixThis + protected boolean unicodeEscape + protected HashMap referencesCache + + Printer(GuiPreferences preferences) { + this.stringBuffer = new StringBuffer(10*1024) + this.showLineNumbers = preferences.isShowLineNumbers() + this.realignmentLineNumber = preferences.getRealignmentLineNumber() + this.showPrefixThis = preferences.isShowPrefixThis() + this.unicodeEscape = preferences.isUnicodeEscape() + this.referencesCache = new HashMap<>() + } + + boolean isShowLineNumbers() { showLineNumbers } + boolean getRealignmentLineNumber() { realignmentLineNumber } + boolean isShowPrefixThis() { showPrefixThis } + boolean isUnicodeEscape() { unicodeEscape } + + void append(char c) { stringBuffer.append(c) } + void append(String s) { + stringBuffer.append(s) } + + // Manage line number and misalignment + int textAreaLineNumber = 1 + + void start(int maxLineNumber, int majorVersion, int minorVersion) { + super.start(maxLineNumber, majorVersion, minorVersion) + + if (maxLineNumber == 0) { + scrollPane.lineNumbersEnabled = false + } else { + setMaxLineNumber(maxLineNumber) + } + } + void startOfLine(int sourceLineNumber) { + super.startOfLine(sourceLineNumber) + setLineNumber(textAreaLineNumber, sourceLineNumber) + } + void endOfLine() { + super.endOfLine() + textAreaLineNumber++ + } + void extraLine(int count) { + super.extraLine(count) + if (realignmentLineNumber) { + textAreaLineNumber += count + } + } + + // --- Manage strings --- // + void printString(String s, String scopeInternalName) { + strings.add(new StringData(stringBuffer.length(), s.length(), s, scopeInternalName)) + super.printString(s, scopeInternalName) + } + + // --- Manage references --- // + void printTypeImport(String internalName, String name) { + addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, null, null, null))) + super.printTypeImport(internalName, name) + } + + void printType(String internalName, String name, String scopeInternalName) { + addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, null, null, scopeInternalName))) + super.printType(internalName, name, scopeInternalName) + } + + void printField(String internalName, String name, String descriptor, String scopeInternalName) { + addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName))) + super.printField(internalName, name, descriptor, scopeInternalName) + } + void printStaticField(String internalName, String name, String descriptor, String scopeInternalName) { + addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName))) + super.printStaticField(internalName, name, descriptor, scopeInternalName) + } + + void printConstructor(String internalName, String name, String descriptor, String scopeInternalName) { + addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, "", descriptor, scopeInternalName))) + super.printConstructor(internalName, name, descriptor, scopeInternalName) + } + + void printMethod(String internalName, String name, String descriptor, String scopeInternalName) { + addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName))) + super.printMethod(internalName, name, descriptor, scopeInternalName) + } + void printStaticMethod(String internalName, String name, String descriptor, String scopeInternalName) { + addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName))) + super.printStaticMethod(internalName, name, descriptor, scopeInternalName) + } + + ReferenceData newReferenceData(String internalName, String name, String descriptor, String scopeInternalName) { + def key = internalName + '-' + name + '-'+ descriptor + '-' + scopeInternalName + def reference = referencesCache.get(key) + + if (reference == null) { + reference = new ReferenceData(internalName, name, descriptor, scopeInternalName) + referencesCache.put(key, reference) + references.add(reference) + } + + return reference + } + + // --- Manage declarations --- // + void printTypeDeclaration(String internalName, String name) { + def data = new DeclarationData(stringBuffer.length(), name.length(), internalName, null, null) + declarations.put(internalName, data) + typeDeclarations.put(stringBuffer.length(), data) + super.printTypeDeclaration(internalName, name) + } + + void printFieldDeclaration(String internalName, String name, String descriptor) { + declarations.put(internalName + '-' + name + '-' + descriptor, new DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor)) + super.printFieldDeclaration(internalName, name, descriptor) + } + void printStaticFieldDeclaration(String internalName, String name, String descriptor) { + declarations.put(internalName + '-' + name + '-' + descriptor, new DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor)) + super.printStaticFieldDeclaration(internalName, name, descriptor) + } + + void printConstructorDeclaration(String internalName, String name, String descriptor) { + declarations.put(internalName + '--' + descriptor, new DeclarationData(stringBuffer.length(), name.length(), internalName, "", descriptor)) + super.printConstructorDeclaration(internalName, name, descriptor) + } + + void printMethodDeclaration(String internalName, String name, String descriptor) { + declarations.put(internalName + '-' + name + '-' + descriptor, new DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor)) + super.printMethodDeclaration(internalName, name, descriptor) + } + void printStaticMethodDeclaration(String internalName, String name, String descriptor) { + declarations.put(internalName + '-' + name + '-' + descriptor, new DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor)) + super.printStaticMethodDeclaration(internalName, name, descriptor) + } + + String toString() { stringBuffer.toString() } + } + + @CompileStatic + static class StringData { + int startPosition + int endPosition + String text + String owner + + StringData(int startPosition, int length, String text, String owner) { + this.startPosition = startPosition + this.endPosition = startPosition + length + this.text = text + this.owner = owner + } + } + + @CompileStatic + static class DeclarationData { + int startPosition + int endPosition + String type + /** + * Field or method name or null for type + */ + String name + String descriptor + + DeclarationData(int startPosition, int length, String type, String name, String descriptor) { + this.startPosition = startPosition + this.endPosition = startPosition + length + this.type = type + this.name = name + this.descriptor = descriptor + } + + boolean isAType() { name == null } + boolean isAField() { descriptor && descriptor.charAt(0) != '('} + boolean isAMethod() { descriptor && descriptor.charAt(0) == '('} + boolean isAConstructor() { "".equals(name) } + } + + @CompileStatic + static class HyperlinkReferenceData extends HyperlinkPage.HyperlinkData { + ReferenceData reference + + HyperlinkReferenceData(int startPosition, int length, ReferenceData reference) { + super(startPosition, startPosition+length) + this.reference = reference + } + } + + @CompileStatic + static class ReferenceData { + String type + /** + * Field or method name or null for type + */ + String name + /** + * Field or method descriptor or null for type + */ + String descriptor + /** + * Internal type name containing reference or null for "import" statement. + * Used to high light items matching with URI like "file://dir1/dir2/file?highlightPattern=hello&highlightFlags=drtcmfs&highlightScope=type". + */ + String owner + /** + * "Enabled" flag for link of reference + */ + boolean enabled = false + + ReferenceData(String type, String name, String descriptor, String owner) { + this.type = type + this.name = name + this.descriptor = descriptor + this.owner = owner + } + + boolean isAType() { name == null } + boolean isAField() { descriptor && descriptor.charAt(0) != '('} + boolean isAMethod() { descriptor && descriptor.charAt(0) == '('} + boolean isAConstructor() { "".equals(name) } + } + + @CompileStatic + protected static boolean getPreferenceValue(Map preferences, String key, boolean defaultValue) { + String v = preferences.get(key); + + if (v == null) { + return defaultValue; + } else { + return Boolean.valueOf(v); + } + } +} diff --git a/services/src/main/groovy/jd/gui/view/component/HyperlinkPage.groovy b/services/src/main/groovy/jd/gui/view/component/HyperlinkPage.groovy new file mode 100644 index 00000000..be7fb5d8 --- /dev/null +++ b/services/src/main/groovy/jd/gui/view/component/HyperlinkPage.groovy @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view.component + +import groovy.transform.CompileStatic +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea +import org.fife.ui.rsyntaxtextarea.Token + +import java.awt.* +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent +import java.awt.event.MouseWheelEvent + +@CompileStatic +abstract class HyperlinkPage extends TextPage { + protected static final Cursor defaultCursor = Cursor.defaultCursor + protected static final Cursor handCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) + + protected TreeMap hyperlinks = new TreeMap<>() + + HyperlinkPage() { + def listener = new MouseAdapter() { + int lastX = -1 + int lastY = -1 + + void mouseClicked(MouseEvent e) { + if (e.clickCount > 0) { + int offset = textArea.viewToModel(new Point(e.x, e.y)) + if (offset != -1) { + def entry = hyperlinks.floorEntry(offset) + if (entry) { + def entryData = entry.value + if (entryData && (offset < entryData.endPosition) && (offset >= entryData.startPosition) && isHyperlinkEnabled(entryData)) { + openHyperlink(e.getXOnScreen(), e.getYOnScreen(), entryData) + } + } + } + } + } + + void mouseMoved(MouseEvent e) { + if ((e.x != lastX) || (e.y != lastY)) { + lastX = e.x + lastY = e.y + + int offset = textArea.viewToModel(new Point(e.x, e.y)) + if (offset != -1) { + def entry = hyperlinks.floorEntry(offset) + if (entry) { + def entryData = entry.value + if (entryData && (offset < entryData.endPosition) && (offset >= entryData.startPosition) && isHyperlinkEnabled(entryData)) { + textArea.cursor = handCursor + return + } + } + } + + textArea.cursor = defaultCursor + } + } + + void mouseWheelMoved(MouseWheelEvent e) { + mouseMoved(e) + textArea.parent.dispatchEvent(e) + } + } + + textArea.addMouseListener(listener) + textArea.addMouseMotionListener(listener) + textArea.addMouseWheelListener(listener) + } + + protected RSyntaxTextArea newRSyntaxTextArea() { new HyperlinkSyntaxTextArea() } + + void addHyperlink(HyperlinkData hyperlinkData) { + hyperlinks.put(hyperlinkData.startPosition, hyperlinkData) + } + + void clearHyperlinks() { + hyperlinks.clear() + } + + protected abstract boolean isHyperlinkEnabled(HyperlinkData hyperlinkData) + + protected abstract void openHyperlink(int x, int y, HyperlinkData hyperlinkData) + + static class HyperlinkData { + int startPosition + int endPosition + + HyperlinkData(int startPosition, int endPosition) { + this.startPosition = startPosition + this.endPosition = endPosition + } + } + + class HyperlinkSyntaxTextArea extends RSyntaxTextArea { + boolean getUnderlineForToken(Token t) { + def entry = hyperlinks.floorEntry(t.offset) + if (entry) { + def entryData = entry.value + if (entryData && (t.offset < entryData.endPosition) && (t.offset >= entryData.startPosition) && isHyperlinkEnabled(entryData)) { + return true + } + } + return super.getUnderlineForToken(t) + } + } +} diff --git a/services/src/main/groovy/jd/gui/view/component/LogPage.groovy b/services/src/main/groovy/jd/gui/view/component/LogPage.groovy new file mode 100644 index 00000000..3a39f335 --- /dev/null +++ b/services/src/main/groovy/jd/gui/view/component/LogPage.groovy @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view.component + +import jd.gui.api.API +import jd.gui.api.feature.ContentSavable +import jd.gui.api.feature.IndexesChangeListener +import jd.gui.api.feature.UriGettable +import jd.gui.api.model.Indexes + +import java.awt.Point + +class LogPage extends HyperlinkPage implements UriGettable, ContentSavable, IndexesChangeListener { + protected API api + protected URI uri + protected Collection collectionOfIndexes + + LogPage(API api, URI uri, String content) { + this.api = api + this.uri = uri + // Parse + int index = 0 + int eol = content.indexOf('\n') + + while (eol != -1) { + parseLine(content, index, eol) + index = eol + 1 + eol = content.indexOf('\n', index) + } + + parseLine(content, index, content.size()) + // Display + setText(content) + } + + protected void parseLine(String content, int index, int eol) { + int start = content.indexOf('at ', index) + + if ((start != -1) && (start < eol)) { + int leftParenthesisIndex = content.indexOf('(', start) + + if ((leftParenthesisIndex != -1) && (leftParenthesisIndex < eol)) { + addHyperlink(new LogHyperlinkData(start+3, leftParenthesisIndex)) + } + } + } + + protected boolean isHyperlinkEnabled(HyperlinkData hyperlinkData) { hyperlinkData.enabled } + + protected void openHyperlink(int x, int y, HyperlinkData hyperlinkData) { + if (hyperlinkData.enabled) { + // Save current position in history + def location = textArea.getLocationOnScreen() + int offset = textArea.viewToModel(new Point(x-location.x as int, y-location.y as int)) + api.addURI(new URI(uri.scheme, uri.authority, uri.path, 'position=' + offset, null)) + + // Open link + def text = getText() + def typeAndMethodNames = text.substring(hyperlinkData.startPosition, hyperlinkData.endPosition) + int lastDotIndex = typeAndMethodNames.lastIndexOf('.') + def methodName = typeAndMethodNames.substring(lastDotIndex+1) + def typeName = typeAndMethodNames.substring(0, lastDotIndex).replace('.', '/') + def entries = collectionOfIndexes?.collect { it.getIndex('typeDeclarations')?.get(typeName) }.flatten().grep { it!=null } + + int leftParenthesisIndex = hyperlinkData.endPosition + 1 + int rightParenthesisIndex = text.indexOf(')', leftParenthesisIndex) + def lineNumberOrNativeMethodFlag = text.substring(leftParenthesisIndex, rightParenthesisIndex) + + if (lineNumberOrNativeMethodFlag.equals('Native Method')) { + // Example: at java.security.AccessController.doPrivileged(Native Method) + lastDotIndex = typeName.lastIndexOf('/') + def shortTypeName = typeName.substring(lastDotIndex+1) + api.openURI(x, y, entries, null, shortTypeName + '-' + methodName + '-(?)?') + } else { + // Example: at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294) + int colonIndex = lineNumberOrNativeMethodFlag.indexOf(':') + def lineNumber = lineNumberOrNativeMethodFlag.substring(colonIndex+1) + api.openURI(x, y, entries, 'lineNumber=' + lineNumber, null) + } + } + } + + // --- UriGettable --- // + URI getUri() { uri } + + // --- SourceSavable --- // + String getFileName() { + def path = uri.path + int index = path.lastIndexOf('/') + return path.substring(index + 1) + } + + void save(API api, OutputStream os) { + os << textArea.text + } + + // --- IndexesChangeListener --- // + void indexesChanged(Collection collectionOfIndexes) { + // Update the list of containers + this.collectionOfIndexes = collectionOfIndexes + // Refresh links + boolean refresh = false + def text = getText() + + for (def entry : hyperlinks.entrySet()) { + def entryData = entry.value as LogHyperlinkData + def typeAndMethodNames = text.substring(entryData.startPosition, entryData.endPosition) + int lastDotIndex = typeAndMethodNames.lastIndexOf('.') + def typeName = typeAndMethodNames.substring(0, lastDotIndex).replace('.', '/') + boolean enabled = collectionOfIndexes.find { it.getIndex('typeDeclarations')?.get(typeName) } != null + + if (entryData.enabled != enabled) { + entryData.enabled = enabled + refresh = true + } + } + + if (refresh) { + textArea.repaint() + } + } + + static class LogHyperlinkData extends HyperlinkPage.HyperlinkData { + boolean enabled = false + + LogHyperlinkData(int startPosition, int endPosition) { + super(startPosition, endPosition) + } + } +} diff --git a/services/src/main/groovy/jd/gui/view/component/ManifestFilePage.groovy b/services/src/main/groovy/jd/gui/view/component/ManifestFilePage.groovy new file mode 100644 index 00000000..7639dff2 --- /dev/null +++ b/services/src/main/groovy/jd/gui/view/component/ManifestFilePage.groovy @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view.component + +import jd.gui.api.API +import jd.gui.api.feature.ContentSavable +import jd.gui.api.feature.IndexesChangeListener +import jd.gui.api.feature.UriGettable +import jd.gui.api.model.Container +import jd.gui.api.model.Indexes + +import java.awt.Point + +class ManifestFilePage extends HyperlinkPage implements UriGettable, ContentSavable, IndexesChangeListener { + protected API api + protected Container.Entry entry + protected Collection collectionOfIndexes + + ManifestFilePage(API api, Container.Entry entry) { + this.api = api + this.entry = entry + // Load content file + def text = entry.inputStream.text + // Parse hyperlinks. Docs: + // - http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html + // - http://docs.oracle.com/javase/7/docs/api/java/lang/instrument/package-summary.html + int startLineIndex = text.indexOf('Main-Class:') + if (startLineIndex != -1) { + // Example: Main-Class: jd.gui.App + int startIndex = skipSeparators(text, startLineIndex + 'Main-Class:'.size()) + int endIndex = searchEndIndexForValue(text, startLineIndex, startIndex) + def typeName = text.substring(startIndex, endIndex) + int lastDotIndex = typeName.lastIndexOf('.') + def shortTypeName = typeName.substring(lastDotIndex+1) + addHyperlink(new ManifestHyperlinkData(startIndex, endIndex, shortTypeName + '-main-(Ljava/lang/String;)V')) + } + + startLineIndex = text.indexOf('Premain-Class:') + if (startLineIndex != -1) { + // Example: Premain-Class: packge.JavaAgent + int startIndex = skipSeparators(text, startLineIndex + 'Premain-Class:'.size()) + int endIndex = searchEndIndexForValue(text, startLineIndex, startIndex) + def typeName = text.substring(startIndex, endIndex) + int lastDotIndex = typeName.lastIndexOf('.') + def shortTypeName = typeName.substring(lastDotIndex+1) + // Undefined parameters : 2 candidate methods + // http://docs.oracle.com/javase/6/docs/api/java/lang/instrument/package-summary.html + addHyperlink(new ManifestHyperlinkData(startIndex, endIndex, shortTypeName + '-premain-(?)?')) + } + // Display + setText(text) + } + + int skipSeparators(String text, int index) { + int length = text.size() + + while (index < length) { + switch (text.charAt(index)) { + case ' ': case '\t': case '\n': case '\r': + index++ + break + default: + return index + } + } + + return index + } + + int searchEndIndexForValue(String text, int startLineIndex, int startIndex) { + int length = text.size() + int index = startIndex + + while (index < length) { + // MANIFEST.MF Specification: max line length = 72 + // http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html + switch (text.charAt(index)) { + case '\r': + // CR followed by LF ? + if ((index-startLineIndex >= 70) && (index+1 < length) && (text.charAt(index+1) == ' ')) { + // Multiline value + startLineIndex = index+1 + } else if ((index-startLineIndex >= 70) && (index+2 < length) && (text.charAt(index+1) == '\n') && (text.charAt(index+2) == ' ')) { + // Multiline value + index++ + startLineIndex = index+1 + } else { + // (End of file) or (single line value) => return end index + return index + } + break + case '\n': + if ((index-startLineIndex >= 70) && (index+1 < length) && (text.charAt(index+1) == ' ')) { + // Multiline value + startLineIndex = index+1 + } else { + // (End of file) or (single line value) => return end index + return index + } + break + } + index++ + } + + return index + } + + protected boolean isHyperlinkEnabled(HyperlinkData hyperlinkData) { hyperlinkData.enabled } + + protected void openHyperlink(int x, int y, HyperlinkData hyperlinkData) { + if (hyperlinkData.enabled) { + // Save current position in history + def location = textArea.getLocationOnScreen() + int offset = textArea.viewToModel(new Point(x-location.x as int, y-location.y as int)) + def uri = entry.uri + api.addURI(new URI(uri.scheme, uri.authority, uri.path, 'position=' + offset, null)) + + // Open link + def text = getText() + def textLink = getValue(text, hyperlinkData.startPosition, hyperlinkData.endPosition) + def typeName = textLink.replace('.', '/') + def entries = collectionOfIndexes?.collect { it.getIndex('typeDeclarations')?.get(typeName) }.flatten().grep { it!=null } + def rootUri = entry.container.root.uri.toString() + def sameContainerEntries = entries?.grep { it.uri.toString().startsWith(rootUri) } + + if (sameContainerEntries) { + api.openURI(x, y, sameContainerEntries, null, hyperlinkData.fragment) + } else if (entries) { + api.openURI(x, y, entries, null, hyperlinkData.fragment) + } + } + } + + // --- UriGettable --- // + URI getUri() { entry.uri } + + // --- SourceSavable --- // + String getFileName() { + def path = entry.path + int index = path.lastIndexOf('/') + return path.substring(index+1) + } + + void save(API api, OutputStream os) { + os << textArea.text + } + + // --- IndexesChangeListener --- // + void indexesChanged(Collection collectionOfIndexes) { + // Update the list of containers + this.collectionOfIndexes = collectionOfIndexes + // Refresh links + boolean refresh = false + def text = getText() + + for (def entry : hyperlinks.entrySet()) { + def entryData = entry.value as ManifestHyperlinkData + def textLink = getValue(text, entryData.startPosition, entryData.endPosition) + def typeName = textLink.replace('.', '/') + boolean enabled = collectionOfIndexes.find { it.getIndex('typeDeclarations')?.get(typeName) } != null + + if (entryData.enabled != enabled) { + entryData.enabled = enabled + refresh = true + } + } + + if (refresh) { + textArea.repaint() + } + } + + static String getValue(String text, int startPosition, int endPosition) { + return text + // Extract text of link + .substring(startPosition, endPosition) + // Convert multiline value + .replace('\r\n ', '') + .replace('\r ', '') + .replace('\n ', '') + } + + static class ManifestHyperlinkData extends HyperlinkPage.HyperlinkData { + boolean enabled + String fragment + + ManifestHyperlinkData(int startPosition, int endPosition, String fragment) { + super(startPosition, endPosition) + this.enabled = false + this.fragment = fragment + } + } +} + diff --git a/services/src/main/groovy/jd/gui/view/component/SourcePage.groovy b/services/src/main/groovy/jd/gui/view/component/SourcePage.groovy new file mode 100644 index 00000000..7136df25 --- /dev/null +++ b/services/src/main/groovy/jd/gui/view/component/SourcePage.groovy @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view.component + +import groovy.transform.CompileStatic +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea +import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaEditorKit +import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaUI +import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities +import org.fife.ui.rsyntaxtextarea.Token +import org.fife.ui.rsyntaxtextarea.folding.Fold +import org.fife.ui.rtextarea.Gutter +import org.fife.ui.rtextarea.LineNumberList +import org.fife.ui.rtextarea.RTextArea +import org.fife.ui.rtextarea.RTextAreaUI + +import javax.swing.JComponent +import javax.swing.text.EditorKit +import javax.swing.text.JTextComponent +import java.awt.Color +import java.awt.FontMetrics +import java.awt.Graphics +import java.awt.Graphics2D +import java.awt.Insets +import java.awt.Rectangle + +@CompileStatic +abstract class SourcePage extends HyperlinkPage { + + Color errorForeground = Color.RED + boolean showMisalignment = true + + void setErrorForeground(Color color) { + errorForeground = color + } + + void setShowMisalignment(boolean b) { + showMisalignment = b + } + + /** + * Map[textarea line number] = source line number + */ + protected int[] lineNumberMap = null + + void setMaxLineNumber(int maxLineNumber) { + if (maxLineNumber > 0) { + if (lineNumberMap == null) { + lineNumberMap = new int[maxLineNumber * 3 / 2] + } else if (lineNumberMap.length <= maxLineNumber) { + int[] tmp = new int[maxLineNumber * 3 / 2] + System.arraycopy(lineNumberMap, 0, tmp, 0, lineNumberMap.length) + lineNumberMap = tmp + } + } + } + + void setLineNumber(int textAreaLineNumber, int sourceLineNumber) { + if (sourceLineNumber > 0) { + setMaxLineNumber(textAreaLineNumber) + lineNumberMap[textAreaLineNumber] = sourceLineNumber + } + } + + void clearLineNumbers() { + if (lineNumberMap) { + Arrays.fill(lineNumberMap, 0) + } + } + + int getMaximumSourceLineNumber() { + int max = 0 + for (int ln : lineNumberMap) { + if (max < ln) { + max = ln + } + } + return max + } + + int getTextAreaLineNumber(int sourceLineNumber) { + int textAreaLineNumber = 1 + int greatestLowerSourceLineNumber = 0 + int i = lineNumberMap.length + + while (i-- > 0) { + int sln = lineNumberMap[i] + if (sln <= sourceLineNumber) { + if (greatestLowerSourceLineNumber < sln) { + greatestLowerSourceLineNumber = sln + textAreaLineNumber = lineNumberMap[i] + } + } + } + + return textAreaLineNumber + } + + protected RSyntaxTextArea newRSyntaxTextArea() { new SourceSyntaxTextArea() } + + @CompileStatic + class SourceSyntaxTextArea extends RSyntaxTextArea { + /** + * @see HyperlinkPage.HyperlinkSyntaxTextArea#getUnderlineForToken(org.fife.ui.rsyntaxtextarea.Token) + */ + boolean getUnderlineForToken(Token t) { + def entry = hyperlinks.floorEntry(t.offset) + if (entry) { + def data = entry.value + if (data && (t.offset < data.endPosition) && (t.offset >= data.startPosition) && isHyperlinkEnabled(data)) { + return true + } + } + return super.getUnderlineForToken(t) + } + + protected RTextAreaUI createRTextAreaUI() { new SourceSyntaxTextAreaUI(this) } + } + + /** + * A lot of code to replace the default LineNumberList... + */ + @CompileStatic + class SourceSyntaxTextAreaUI extends RSyntaxTextAreaUI { + SourceSyntaxTextAreaUI(JComponent rSyntaxTextArea) { super(rSyntaxTextArea) } + EditorKit getEditorKit(JTextComponent tc) { new SourceSyntaxTextAreaEditorKit() } + Rectangle getVisibleEditorRect() { super.getVisibleEditorRect() } + } + + @CompileStatic + class SourceSyntaxTextAreaEditorKit extends RSyntaxTextAreaEditorKit { + LineNumberList createLineNumberList(RTextArea textArea) { new SourceLineNumberList(textArea) } + } + + /** + * Why 'LineNumberList' is so unexpandable ? Too many private fields & methods and too many package scope. + */ + @CompileStatic + class SourceLineNumberList extends LineNumberList { + protected RTextArea rTextArea + protected Map aaHints + protected Rectangle visibleRect + protected Insets textAreaInsets + + SourceLineNumberList(RTextArea textArea) { + super(textArea, null) + this.rTextArea = textArea + } + + @Override + protected void init() { + super.init() + visibleRect = new Rectangle() + aaHints = RSyntaxUtilities.getDesktopAntiAliasHints(); + textAreaInsets = null + } + + /** + * @see org.fife.ui.rtextarea.LineNumberList#paintComponent(java.awt.Graphics) + */ + @Override + protected void paintComponent(Graphics g) { + visibleRect = g.getClipBounds(visibleRect) + + if (visibleRect == null) { + visibleRect = getVisibleRect() + } + if (visibleRect == null) { + return + } + + int cellWidth = getPreferredSize().@width + int cellHeight = rTextArea.lineHeight + int ascent = rTextArea.maxAscent + def fm = ((RSyntaxTextArea)rTextArea).foldManager + int RHS_BORDER_WIDTH = rhsBorderWidth + def metrics = g.fontMetrics + int rhs = width - RHS_BORDER_WIDTH + + if (parent instanceof Gutter) { // Should always be true + g.setColor(parent.background) + } else { + g.setColor(background) + } + + g.fillRect(0, visibleRect.@y, cellWidth, visibleRect.@height) + g.setFont(font) + + if (aaHints) { + ((Graphics2D)g).addRenderingHints(aaHints) + } + + if (rTextArea.lineWrap) { + def ui = (SourceSyntaxTextAreaUI)rTextArea.getUI() + def v = ui.getRootView(rTextArea).getView(0) + def root = rTextArea.document.defaultRootElement + int lineCount = root.elementCount + int topPosition = rTextArea.viewToModel(visibleRect.location) + int topLine = root.getElementIndex(topPosition) + def visibleEditorRect = ui.visibleEditorRect + def r = LineNumberList.getChildViewBounds(v, topLine, visibleEditorRect) + int y = r.@y + + int visibleBottom = visibleRect.@y + visibleRect.@height + + // Keep painting lines until our y-coordinate is past the visible + // end of the text area. + + while (y < visibleBottom) { + r = getChildViewBounds(v, topLine, visibleEditorRect) + + // Paint the line number. + paintLineNumber(g, metrics, rhs, y+ascent, topLine + 1) + + // The next possible y-coordinate is just after the last line + // painted. + y += r.@height + + // Update topLine (we're actually using it for our "current line" + // variable now). + if (fm) { + Fold fold = fm.getFoldForLine(topLine) + if (fold?.isCollapsed()) { + topLine += fold.collapsedLineCount + } + } + + if (++topLine >= lineCount) { + break + } + } + } else { + textAreaInsets = rTextArea.getInsets(textAreaInsets) + + if (visibleRect.@y < textAreaInsets.@top) { + visibleRect.@height -= (textAreaInsets.@top - visibleRect.@y) + visibleRect.@y = textAreaInsets.@top + } + + int topLine = (int) (visibleRect.@y - textAreaInsets.@top) / cellHeight + int actualTopY = topLine * cellHeight + textAreaInsets.top + int y = actualTopY + ascent + + // Get the actual first line to paint, taking into account folding. + topLine += fm.getHiddenLineCountAbove(topLine, true) + + // Paint line numbers + g.setColor(foreground) + + int line = topLine + 1 + + while ((y < visibleRect.@y + visibleRect.@height + ascent) && (line <= rTextArea.lineCount)) { + paintLineNumber(g, metrics, rhs, y, line) + + y += cellHeight + + if (fm != null) { + Fold fold = fm.getFoldForLine(line - 1) + // Skip to next line to paint, taking extra care for lines with + // block ends and begins together, e.g. "} else {" + while (fold?.isCollapsed()) { + int hiddenLineCount = fold.lineCount + if (hiddenLineCount == 0) { + // Fold parser identified a 0-line fold region... This + // is really a bug, but we'll handle it gracefully. + break + } + line += hiddenLineCount + fold = fm.getFoldForLine(line - 1) + } + } + + line++ + } + } + } + + protected void paintLineNumber(Graphics g, FontMetrics metrics, int x, int y, int lineNumber) { + int sourceLineNumber = lineNumberMap ? lineNumberMap[lineNumber] : lineNumber + + if (sourceLineNumber != 0) { + String number = Integer.toString(sourceLineNumber) + int strWidth = metrics.stringWidth(number) + g.setColor(showMisalignment && (lineNumber != sourceLineNumber) ? errorForeground : foreground) + g.drawString(number, x-strWidth, y) + } + } + + int getRhsBorderWidth() { ((RSyntaxTextArea)rTextArea).isCodeFoldingEnabled() ? 0 : 4 } + } +} diff --git a/services/src/main/groovy/jd/gui/view/component/TextPage.groovy b/services/src/main/groovy/jd/gui/view/component/TextPage.groovy new file mode 100644 index 00000000..c9c7dbc2 --- /dev/null +++ b/services/src/main/groovy/jd/gui/view/component/TextPage.groovy @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view.component + +import groovy.transform.CompileStatic +import jd.gui.api.feature.ContentCopyable +import jd.gui.api.feature.ContentSearchable +import jd.gui.api.feature.ContentSelectable +import jd.gui.api.feature.LineNumberNavigable +import jd.gui.api.feature.UriOpenable +import org.fife.ui.rsyntaxtextarea.DocumentRange +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea +import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities +import org.fife.ui.rsyntaxtextarea.SyntaxConstants +import org.fife.ui.rsyntaxtextarea.Theme +import org.fife.ui.rtextarea.RTextScrollPane +import org.fife.ui.rtextarea.SearchContext +import org.fife.ui.rtextarea.SearchEngine + +import javax.swing.* +import java.awt.* +import java.awt.datatransfer.StringSelection +import java.awt.event.KeyEvent +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent + +@CompileStatic +class TextPage extends JPanel implements ContentCopyable, ContentSelectable, LineNumberNavigable, ContentSearchable, UriOpenable { + protected static final ImageIcon collapsedIcon = new ImageIcon(TextPage.class.classLoader.getResource('images/plus.png')) + protected static final ImageIcon expandedIcon = new ImageIcon(TextPage.class.classLoader.getResource('images/minus.png')) + + protected static final Color doubleClickHighlightColor = Color.GREEN + protected static final Color searchHighlightColor = Color.YELLOW + + protected RSyntaxTextArea textArea + protected RTextScrollPane scrollPane + + TextPage() { + super(new BorderLayout()) + + textArea = newRSyntaxTextArea() + textArea.setSyntaxEditingStyle(getSyntaxStyle()) + textArea.setCodeFoldingEnabled(true); + textArea.setAntiAliasingEnabled(true); + textArea.caretPosition = 0 + textArea.editable = false + textArea.dropTarget = null + textArea.popupMenu = null + textArea.addMouseListener(new MouseAdapter() { + void mouseClicked(MouseEvent e) { + if (e.clickCount == 2) { + textArea.markAllHighlightColor = doubleClickHighlightColor + + int selectionStart = textArea.selectionStart + int selectionEnd = textArea.selectionEnd + + SearchEngine.find(textArea, newSearchContext(textArea.selectedText, true, true, true, false)) + + textArea.select(selectionStart, selectionEnd) + } + } + }) + + def ctrlA = KeyStroke.getKeyStroke(KeyEvent.VK_A, Toolkit.defaultToolkit.menuShortcutKeyMask) + def ctrlC = KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.defaultToolkit.menuShortcutKeyMask) + def ctrlV = KeyStroke.getKeyStroke(KeyEvent.VK_V, Toolkit.defaultToolkit.menuShortcutKeyMask) + def inputMap = textArea.inputMap + inputMap.put(ctrlA, 'none') + inputMap.put(ctrlC, 'none') + inputMap.put(ctrlV, 'none') + + def theme = Theme.load(getClass().classLoader.getResourceAsStream('rsyntaxtextarea/themes/eclipse.xml')) + theme.apply(textArea) + + scrollPane = new RTextScrollPane(textArea) + scrollPane.foldIndicatorEnabled = true + scrollPane.font = textArea.font + + def gutter = scrollPane.gutter + gutter.setFoldIcons(collapsedIcon, expandedIcon) + gutter.foldIndicatorForeground = gutter.borderColor + + add(scrollPane, BorderLayout.CENTER) + //add(new ErrorStrip(rTextArea), BorderLayout.LINE_END) + } + + protected RSyntaxTextArea newRSyntaxTextArea() { new RSyntaxTextArea() } + + String getText() { textArea.text } + + void setText(String text) { + textArea.text = text + textArea.caretPosition = 0 + } + + String getSyntaxStyle() { SyntaxConstants.SYNTAX_STYLE_NONE } + + // --- ContentCopyable --- // + void copy() { + if (textArea.selectionStart == textArea.selectionEnd) { + toolkit.systemClipboard.setContents(new StringSelection(''), null) + } else { + textArea.copyAsRtf() + } + } + + // --- ContentSelectable --- // + void selectAll() { + textArea.selectAll() + } + + // --- LineNumberNavigable --- // + int getMaximumLineNumber() { + return textArea.getLineOfOffset(textArea.document.length) + } + + void goToLineNumber(int lineNumber) { + textArea.caretPosition = textArea.getLineStartOffset(lineNumber-1) + } + + boolean checkLineNumber(int lineNumber) { true } + + // --- ContentSearchable --- // + boolean highlightText(String text, boolean caseSensitive) { + if (text.length() > 1) { + textArea.markAllHighlightColor = searchHighlightColor + textArea.caretPosition = textArea.selectionStart + + def context = newSearchContext(text, caseSensitive, false, true, false) + def result = SearchEngine.find(textArea, context) + + if (!result.wasFound()) { + textArea.caretPosition = 0 + result = SearchEngine.find(textArea, context) + } + + return result.wasFound() + } else { + return true + } + } + + void findNext(String text, boolean caseSensitive) { + if (text.length() > 1) { + textArea.markAllHighlightColor = searchHighlightColor + + def context = newSearchContext(text, caseSensitive, false, true, false) + def result = SearchEngine.find(textArea, context) + + if (!result.wasFound()) { + textArea.caretPosition = 0 + SearchEngine.find(textArea, context) + } + } + } + + void findPrevious(String text, boolean caseSensitive) { + if (text.length() > 1) { + textArea.markAllHighlightColor = searchHighlightColor + + def context = newSearchContext(text, caseSensitive, false, false, false) + def result = SearchEngine.find(textArea, context) + + if (!result.wasFound()) { + textArea.caretPosition = textArea.document.length + SearchEngine.find(textArea, context) + } + } + } + + protected SearchContext newSearchContext( + String searchFor, boolean matchCase, boolean wholeWord, boolean searchForward, boolean regexp) { + def context = new SearchContext(searchFor, matchCase) + context.markAll = true + context.wholeWord = wholeWord + context.searchForward = searchForward + context.regularExpression = regexp + return context + } + + // --- UriOpenable --- // + boolean openUri(URI uri) { + def query = uri.query + + if (query) { + Map parameters = parseQuery(query) + + if (parameters.containsKey('lineNumber')) { + def lineNumber = parameters.get('lineNumber') + if (lineNumber.isNumber()) { + goToLineNumber(lineNumber.toInteger()) + return true + } + } else if (parameters.containsKey('position')) { + def position = parameters.get('position') + if (position.isNumber()) { + int pos = position.toInteger() + if (textArea.document.length > pos) { + RSyntaxUtilities.selectAndPossiblyCenter(textArea, new DocumentRange(pos, pos), false) + return true + } + } + } else if (parameters.containsKey('highlightFlags')) { + def highlightFlags = parameters.get('highlightFlags') + + if ((highlightFlags.indexOf('s') != -1) && parameters.containsKey('highlightPattern')) { + textArea.markAllHighlightColor = searchHighlightColor + textArea.caretPosition = 0 + + // Highlight all + def searchFor = createRegExp(parameters.get('highlightPattern')) + def context = newSearchContext(searchFor, true, false, true, true) + def result = SearchEngine.find(textArea, context) + + if (result.matchRange) { + textArea.caretPosition = result.matchRange.startOffset + } + + return true + } + } + } + + return false + } + + protected Map parseQuery(String query) { + Map parameters = [:] + + // Parse parameters + for (def param : query.split('&')) { + int index = param.indexOf('=') + + if (index == -1) { + parameters.put(URLDecoder.decode(param, 'UTF-8'), '') + } else { + def key = param.substring(0, index) + def value = param.substring(index+1) + parameters.put(URLDecoder.decode(key, 'UTF-8'), URLDecoder.decode(value, 'UTF-8')) + } + } + + return parameters + } + + /** + * Create a simple regular expression + * + * Rules: + * '*' matchTypeEntries 0 ou N characters + * '?' matchTypeEntries 1 character + */ + static String createRegExp(String pattern) { + int patternLength = pattern.length() + def sbPattern = new StringBuffer(patternLength * 2) + + for (int i = 0; i < patternLength; i++) { + char c = pattern.charAt(i) + + if (c == '*') { + sbPattern.append('.*') + } else if (c == '?') { + sbPattern.append('.') + } else if (c == '.') { + sbPattern.append('\\.') + } else { + sbPattern.append(c) + } + } + + return sbPattern.toString() + } +} diff --git a/services/src/main/groovy/jd/gui/view/data/TreeNodeBean.groovy b/services/src/main/groovy/jd/gui/view/data/TreeNodeBean.groovy new file mode 100644 index 00000000..9c45123f --- /dev/null +++ b/services/src/main/groovy/jd/gui/view/data/TreeNodeBean.groovy @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.view.data + +import jd.gui.api.model.TreeNodeData + +import javax.swing.* + +class TreeNodeBean implements TreeNodeData { + String label + String tip + Icon icon + Icon openIcon +} diff --git a/services/src/main/java/jd/gui/service/indexer/ClassFileIndexerProvider.java b/services/src/main/java/jd/gui/service/indexer/ClassFileIndexerProvider.java new file mode 100644 index 00000000..4bff429e --- /dev/null +++ b/services/src/main/java/jd/gui/service/indexer/ClassFileIndexerProvider.java @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.indexer; + +import groovyjarjarasm.asm.*; +import groovyjarjarasm.asm.signature.SignatureReader; +import groovyjarjarasm.asm.signature.SignatureVisitor; +import jd.gui.api.API; +import jd.gui.api.model.Container; +import jd.gui.api.model.Indexes; +import jd.gui.spi.Indexer; + +import java.io.IOException; +import java.io.InputStream; +import java.util.*; +import java.util.regex.Pattern; + +/** + * Unsafe thread implementation of class file indexer. + */ +public class ClassFileIndexerProvider implements Indexer { + protected Set typeDeclarationSet = new HashSet<>(); + protected Set constructorDeclarationSet = new HashSet<>(); + protected Set methodDeclarationSet = new HashSet<>(); + protected Set fieldDeclarationSet = new HashSet<>(); + protected Set typeReferenceSet = new HashSet<>(); + protected Set constructorReferenceSet = new HashSet<>(); + protected Set methodReferenceSet = new HashSet<>(); + protected Set fieldReferenceSet = new HashSet<>(); + protected Set stringSet = new HashSet<>(); + protected Set superTypeNameSet = new HashSet<>(); + protected Set descriptorSet = new HashSet<>(); + + protected ClassIndexer classIndexer = new ClassIndexer( + typeDeclarationSet, constructorDeclarationSet, methodDeclarationSet, + fieldDeclarationSet, typeReferenceSet, superTypeNameSet, descriptorSet); + protected SignatureIndexer signatureIndexer = new SignatureIndexer(typeReferenceSet); + + protected String[] types = new String[] { "*:file:*.class" }; + + public String[] getTypes() { return types; } + + public Pattern getPathPattern() { return null; } + + /** + * Index format : @see jd.gui.spi.Indexer + */ + @SuppressWarnings("unchecked") + public void index(API api, Container.Entry entry, Indexes indexes) { + // Cleaning sets... + typeDeclarationSet.clear(); + constructorDeclarationSet.clear(); + methodDeclarationSet.clear(); + fieldDeclarationSet.clear(); + typeReferenceSet.clear(); + constructorReferenceSet.clear(); + methodReferenceSet.clear(); + fieldReferenceSet.clear(); + stringSet.clear(); + superTypeNameSet.clear(); + descriptorSet.clear(); + + InputStream inputStream = null; + + try { + // Index field, method, interfaces & super type + ClassReader classReader = new ClassReader(inputStream = entry.getInputStream()); + classReader.accept(classIndexer, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + + // Index descriptors + for (String descriptor : descriptorSet) { + new SignatureReader(descriptor).accept(signatureIndexer); + } + + // Index references + char[] buffer = new char[classReader.getMaxStringLength()]; + + for (int i=classReader.getItemCount()-1; i>0; i--) { + int startIndex = classReader.getItem(i); + + if (startIndex != 0) { + int tag = classReader.readByte(startIndex-1); + + switch (tag) { + case 7: // CONSTANT_Class + String className = classReader.readUTF8(startIndex, buffer); + if (className.startsWith("[")) { + new SignatureReader(className).acceptType(signatureIndexer); + } else { + typeReferenceSet.add(className); + } + break; + case 8: // CONSTANT_String + String str = classReader.readUTF8(startIndex, buffer); + stringSet.add(str); + break; + case 9: // CONSTANT_Fieldref + int nameAndTypeItem = classReader.readUnsignedShort(startIndex+2); + int nameAndTypeIndex = classReader.getItem(nameAndTypeItem); + tag = classReader.readByte(nameAndTypeIndex-1); + if (tag == 12) { // CONSTANT_NameAndType + String fieldName = classReader.readUTF8(nameAndTypeIndex, buffer); + fieldReferenceSet.add(fieldName); + } + break; + case 10: // CONSTANT_Methodref: + case 11: // CONSTANT_InterfaceMethodref: + nameAndTypeItem = classReader.readUnsignedShort(startIndex+2); + nameAndTypeIndex = classReader.getItem(nameAndTypeItem); + tag = classReader.readByte(nameAndTypeIndex-1); + if (tag == 12) { // CONSTANT_NameAndType + String methodName = classReader.readUTF8(nameAndTypeIndex, buffer); + if ("".equals(methodName)) { + int classItem = classReader.readUnsignedShort(startIndex); + int classIndex = classReader.getItem(classItem); + className = classReader.readUTF8(classIndex, buffer); + constructorReferenceSet.add(className); + } else { + methodReferenceSet.add(methodName); + } + } + break; + } + } + } + + String typeName = classIndexer.name; + + // Append sets to indexes + addToIndex(indexes, "typeDeclarations", typeDeclarationSet, entry); + addToIndex(indexes, "constructorDeclarations", constructorDeclarationSet, entry); + addToIndex(indexes, "methodDeclarations", methodDeclarationSet, entry); + addToIndex(indexes, "fieldDeclarations", fieldDeclarationSet, entry); + addToIndex(indexes, "typeReferences", typeReferenceSet, entry); + addToIndex(indexes, "constructorReferences", constructorReferenceSet, entry); + addToIndex(indexes, "methodReferences", methodReferenceSet, entry); + addToIndex(indexes, "fieldReferences", fieldReferenceSet, entry); + addToIndex(indexes, "strings", stringSet, entry); + + // Populate map [super type name : [sub type name]] + if (superTypeNameSet.size() > 0) { + Map index = indexes.getIndex("subTypeNames"); + + for (String superTypeName : superTypeNameSet) { + index.get(superTypeName).add(typeName); + } + } + + } catch (Exception ignore) { + } finally { + if (inputStream != null) { + try { inputStream.close(); } catch (IOException ignore) {} + } + } + } + + @SuppressWarnings("unchecked") + protected static void addToIndex(Indexes indexes, String indexName, Set set, Container.Entry entry) { + if (set.size() > 0) { + Map index = indexes.getIndex(indexName); + + for (String key : set) { + index.get(key).add(entry); + } + } + } + + protected static class ClassIndexer extends ClassVisitor { + protected Set typeDeclarationSet; + protected Set constructorDeclarationSet; + protected Set methodDeclarationSet; + protected Set fieldDeclarationSet; + protected Set typeReferenceSet; + protected Set superTypeNameSet; + protected Set descriptorSet; + + protected AnnotationIndexer annotationIndexer; + protected FieldIndexer fieldIndexer; + protected MethodIndexer methodIndexer; + + protected String name; + + public ClassIndexer( + Set typeDeclarationSet, Set constructorDeclarationSet, + Set methodDeclarationSet, Set fieldDeclarationSet, + Set typeReferenceSet, Set superTypeNameSet, Set descriptorSet) { + super(Opcodes.ASM5); + + this.typeDeclarationSet = typeDeclarationSet; + this.constructorDeclarationSet = constructorDeclarationSet; + this.methodDeclarationSet = methodDeclarationSet; + this.fieldDeclarationSet = fieldDeclarationSet; + this.typeReferenceSet = typeReferenceSet; + this.superTypeNameSet = superTypeNameSet; + this.descriptorSet = descriptorSet; + + this.annotationIndexer = new AnnotationIndexer(descriptorSet); + this.fieldIndexer = new FieldIndexer(descriptorSet, annotationIndexer); + this.methodIndexer = new MethodIndexer(descriptorSet, annotationIndexer); + } + + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + this.name = name; + typeDeclarationSet.add(name); + superTypeNameSet.add(superName); + + if (interfaces != null) { + for (int i=interfaces.length-1; i>=0; i--) { + superTypeNameSet.add(interfaces[i]); + } + } + } + + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + descriptorSet.add(desc); + return annotationIndexer; + } + + public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { + descriptorSet.add(desc); + return annotationIndexer; + } + + public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { + fieldDeclarationSet.add(name); + descriptorSet.add(signature==null ? desc : signature); + return fieldIndexer; + } + + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + if ("".equals(name)) { + constructorDeclarationSet.add(this.name); + } else if (! "".equals(name)) { + methodDeclarationSet.add(name); + } + + descriptorSet.add(signature==null ? desc : signature); + + if (exceptions != null) { + for (int i=exceptions.length-1; i>=0; i--) { + typeReferenceSet.add(exceptions[i]); + } + } + return methodIndexer; + } + } + + protected static class SignatureIndexer extends SignatureVisitor { + protected Set typeReferenceSet; + + SignatureIndexer(Set typeReferenceSet) { + super(Opcodes.ASM5); + this.typeReferenceSet = typeReferenceSet; + } + + public void visitClassType(String name) { + typeReferenceSet.add(name); + } + } + + protected static class AnnotationIndexer extends AnnotationVisitor { + protected Set descriptorSet; + + public AnnotationIndexer(Set descriptorSet) { + super(Opcodes.ASM5); + this.descriptorSet = descriptorSet; + } + + public void visitEnum(String name, String desc, String value) { + descriptorSet.add(desc); + } + + public AnnotationVisitor visitAnnotation(String name, String desc) { + descriptorSet.add(desc); + return this; + } + } + + protected static class FieldIndexer extends FieldVisitor { + protected Set descriptorSet; + protected AnnotationIndexer annotationIndexer; + + public FieldIndexer(Set descriptorSet, AnnotationIndexer annotationInexer) { + super(Opcodes.ASM5); + this.descriptorSet = descriptorSet; + this.annotationIndexer = annotationInexer; + } + + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + descriptorSet.add(desc); + return annotationIndexer; + } + + public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { + descriptorSet.add(desc); + return annotationIndexer; + } + } + + protected static class MethodIndexer extends MethodVisitor { + protected Set descriptorSet; + protected AnnotationIndexer annotationIndexer; + + public MethodIndexer(Set descriptorSet, AnnotationIndexer annotationIndexer) { + super(Opcodes.ASM5); + this.descriptorSet = descriptorSet; + this.annotationIndexer = annotationIndexer; + } + + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + descriptorSet.add(desc); + return annotationIndexer; + } + + public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { + descriptorSet.add(desc); + return annotationIndexer; + } + + public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { + descriptorSet.add(desc); + return annotationIndexer; + } + } +} diff --git a/services/src/main/java/jd/gui/service/sourcesaver/ClassFileSourceSaverProvider.java b/services/src/main/java/jd/gui/service/sourcesaver/ClassFileSourceSaverProvider.java new file mode 100644 index 00000000..abaa4436 --- /dev/null +++ b/services/src/main/java/jd/gui/service/sourcesaver/ClassFileSourceSaverProvider.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.sourcesaver; + +import groovy.transform.CompileStatic; +import jd.core.CoreConstants; +import jd.core.Decompiler; +import jd.core.process.DecompilerImpl; +import jd.gui.api.API; +import jd.gui.api.model.Container; +import jd.gui.util.decompiler.ContainerLoader; +import jd.gui.util.decompiler.GuiPreferences; +import jd.gui.spi.SourceSaver; +import jd.gui.util.decompiler.PlainTextPrinter; + +import java.io.*; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; +import java.util.regex.Pattern; + +public class ClassFileSourceSaverProvider implements SourceSaver { + protected static final String ESCAPE_UNICODE_CHARACTERS = "ClassFileSaverPreferences.escapeUnicodeCharacters"; + protected static final String OMIT_THIS_PREFIX = "ClassFileSaverPreferences.omitThisPrefix"; + protected static final String WRITE_DEFAULT_CONSTRUCTOR = "ClassFileSaverPreferences.writeDefaultConstructor"; + protected static final String REALIGN_LINE_NUMBERS = "ClassFileSaverPreferences.realignLineNumbers"; + protected static final String WRITE_LINE_NUMBERS = "ClassFileSaverPreferences.writeLineNumbers"; + protected static final String WRITE_METADATA = "ClassFileSaverPreferences.writeMetadata"; + + protected static final String[] TYPES = new String[] { "*:file:*.class" }; + protected static final Decompiler DECOMPILER = new DecompilerImpl(); + + protected GuiPreferences preferences = new GuiPreferences(); + protected ContainerLoader loader = new ContainerLoader(); + protected PlainTextPrinter printer = new PlainTextPrinter(); + protected ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + public String[] getTypes() { return TYPES; } + + public Pattern getPathPattern() { return null; } + + public String getSourcePath(Container.Entry entry) { + String path = entry.getPath(); + return path.substring(0, path.length()-6) + ".java"; + } + + public int getFileCount(API api, Container.Entry entry) { + if (entry.getPath().indexOf('$') == -1) { + return 1; + } else { + return 0; + } + } + + public void save(API api, Controller controller, Listener listener, Path path, Container.Entry entry) { + try { + // Call listener + if (path.toString().indexOf('$') == -1) { + listener.pathSaved(path); + } + // Init preferences + Map p = api.getPreferences(); + preferences.setUnicodeEscape(getPreferenceValue(p, ESCAPE_UNICODE_CHARACTERS, false)); + preferences.setShowPrefixThis(! getPreferenceValue(p, OMIT_THIS_PREFIX, false)); + preferences.setShowDefaultConstructor(getPreferenceValue(p, WRITE_DEFAULT_CONSTRUCTOR, false)); + preferences.setRealignmentLineNumber(getPreferenceValue(p, REALIGN_LINE_NUMBERS, true)); + preferences.setShowLineNumbers(getPreferenceValue(p, WRITE_LINE_NUMBERS, true)); + + // Init loader + loader.setEntry(entry); + + // Init printer + baos.reset(); + PrintStream ps = new PrintStream(baos); + printer.setPrintStream(ps); + printer.setPreferences(preferences); + + // Decompile class file + DECOMPILER.decompile(preferences, loader, printer, entry.getPath()); + + // Metadata + if (getPreferenceValue(p, WRITE_METADATA, true)) { + // Add location + ps.print("\n\n/* Location: "); + ps.print(new File(entry.getUri()).getPath()); + // Add Java compiler version + int majorVersion = printer.getMajorVersion(); + + if (majorVersion >= 45) { + ps.print("\n * Java compiler version: "); + + if (majorVersion >= 49) { + ps.print(majorVersion - (49 - 5)); + } else { + ps.print(majorVersion - (45 - 1)); + } + + ps.print(" ("); + ps.print(majorVersion); + ps.print('.'); + ps.print(printer.getMinorVersion()); + ps.print(')'); + } + // Add JD-Core version + ps.print("\n * JD-Core Version: "); + ps.print(CoreConstants.JD_CORE_VERSION); + ps.print("\n */"); + } + + try (OutputStream os = Files.newOutputStream(path)) { + baos.writeTo(os); + } catch (IOException ignore) { + } + } catch (Exception ignore) { + try (BufferedWriter writer = Files.newBufferedWriter(path, Charset.defaultCharset())) { + writer.write("// INTERNAL ERROR //"); + } catch (IOException ignoreAgain) { + } + } + } + + @CompileStatic + protected static boolean getPreferenceValue(Map preferences, String key, boolean defaultValue) { + String v = preferences.get(key); + + if (v == null) { + return defaultValue; + } else { + return Boolean.valueOf(v); + } + } +} diff --git a/services/src/main/java/jd/gui/service/type/ClassFileTypeFactoryProvider.java b/services/src/main/java/jd/gui/service/type/ClassFileTypeFactoryProvider.java new file mode 100644 index 00000000..4dd048ab --- /dev/null +++ b/services/src/main/java/jd/gui/service/type/ClassFileTypeFactoryProvider.java @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.service.type; + +import groovyjarjarasm.asm.ClassReader; +import groovyjarjarasm.asm.Opcodes; +import groovyjarjarasm.asm.tree.ClassNode; +import groovyjarjarasm.asm.tree.FieldNode; +import groovyjarjarasm.asm.tree.InnerClassNode; +import groovyjarjarasm.asm.tree.MethodNode; +import jd.gui.api.API; +import jd.gui.api.model.Container; +import jd.gui.api.model.Type; +import jd.gui.spi.TypeFactory; + +import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +public class ClassFileTypeFactoryProvider implements TypeFactory { + + static { + // Early class loading + JavaType.class.getName(); + } + + protected String[] types = new String[] { "*:file:*.class" }; + + public String[] getTypes() { return types; } + + public Pattern getPathPattern() { return null; } + + public Type make(API api, Container.Entry entry, String fragment) { + try (InputStream is = entry.getInputStream()) { + ClassReader classReader = new ClassReader(is); + + if ((fragment != null) && (fragment.length() > 0)) { + // Search type name in fragment. URI format : see jd.gui.api.feature.UriOpener + int index = fragment.indexOf('-'); + if (index != -1) { + // Keep type name only + fragment = fragment.substring(0, index); + } + + if (! classReader.getClassName().equals(fragment)) { + // Search entry for type name + String entryTypePath = classReader.getClassName() + ".class"; + String fragmentTypePath = fragment + ".class"; + + while (true) { + if (entry.getPath().endsWith(entryTypePath)) { + // Entry path ends with the internal class name + String pathToFound = entry.getPath().substring(0, entry.getPath().length() - entryTypePath.length()) + fragmentTypePath; + Container.Entry entryFound = null; + + for (Container.Entry e : entry.getParent().getChildren()) { + if (e.getPath().equals(pathToFound)) { + entryFound = e; + break; + } + } + + if (entryFound == null) + return null; + + entry = entryFound; + + try (InputStream is2 = entry.getInputStream()) { + classReader = new ClassReader(is2); + } catch (IOException ignore) { + return null; + } + break; + } + + // Truncated path ? Cut first package name and retry + int firstPackageSeparatorIndex = entryTypePath.indexOf('/'); + if (firstPackageSeparatorIndex == -1) { + // Nothing to cut -> Stop + return null; + } + + entryTypePath = entryTypePath.substring(firstPackageSeparatorIndex+1); + fragmentTypePath = fragmentTypePath.substring(fragmentTypePath.indexOf('/')+1); + } + } + } + + return new JavaType(entry, classReader); + } catch (IOException ignore) { + return null; + } + } + + static class JavaType implements Type { + ClassNode classNode; + Container.Entry entry; + int access; + String name; + String shortName; + String superName; + String outerName; + + String displayTypeName; + String displayInnerTypeName; + String displayPackageName; + + List innerTypes; + List fields; + List methods; + + @SuppressWarnings("unchecked") + JavaType(Container.Entry entry, ClassReader classReader) { + this.classNode = new ClassNode(); + this.entry = entry; + + classReader.accept(classNode, ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES); + + this.access = classNode.access; + this.name = classNode.name; + + this.superName = ((access & Opcodes.ACC_INTERFACE) != 0) && "java/lang/Object".equals(classNode.superName) ? null : classNode.superName; + this.outerName = null; + this.displayInnerTypeName = null; + + int indexDollar = name.lastIndexOf('$'); + + if (indexDollar != -1) { + int indexSeparator = name.lastIndexOf('/'); + if (indexDollar > indexSeparator) { + for (final InnerClassNode innerClassNode : (List)classNode.innerClasses) { + if (name.equals(innerClassNode.name)) { + // Inner class path found + if (innerClassNode.outerName != null) { + this.outerName = innerClassNode.outerName; + this.displayInnerTypeName = this.name.substring(this.outerName.length() + 1); + } + } + } + } + } + + int lastPackageSeparatorIndex = name.lastIndexOf('/'); + + if (lastPackageSeparatorIndex == -1) { + this.displayPackageName = ""; + this.shortName = this.name; + this.displayTypeName = (this.outerName != null) ? null : this.shortName; + } else { + this.displayPackageName = this.name.substring(0, lastPackageSeparatorIndex).replace('/', '.'); + this.shortName = this.name.substring(lastPackageSeparatorIndex+1); + this.displayTypeName = (this.outerName != null) ? null : this.shortName; + } + + this.innerTypes = null; + this.fields = null; + this.methods = null; + } + + public int getFlags() { return access; } + public String getName() { return name; } + public String getShortName() { return shortName; } + public String getSuperName() { return superName; } + public String getOuterName() { return outerName; } + + public Container.Entry getOuterEntry() { return (outerName==null) ? null : getEntry(outerName); } + + public String getDisplayPackageName() { return displayPackageName; } + + public String getDisplayTypeName() { + if (displayTypeName == null) { + displayTypeName = getDisplayTypeName(outerName, displayPackageName.length()) + '.' + displayInnerTypeName; + } + return displayTypeName; + } + + @SuppressWarnings("unchecked") + protected String getDisplayTypeName(String name, int packageLength) { + int indexDollar = name.lastIndexOf('$'); + + if (indexDollar > packageLength) { + Container.Entry outerEntry = getEntry(name); + + if (outerEntry != null) { + try (InputStream is = outerEntry.getInputStream()) { + ClassReader classReader = new ClassReader(is); + ClassNode classNode = new ClassNode(); + classReader.accept(classNode, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + + for (final InnerClassNode innerClassNode : (List)classNode.innerClasses) { + if (name.equals(innerClassNode.name)) { + // Inner class path found => Recursive call + return getDisplayTypeName(innerClassNode.outerName, packageLength) + '.' + innerClassNode.innerName; + } + } + } catch (IOException ignore) { + } + } + } + + return packageLength > 0 ? name.substring(packageLength+1) : name; + } + + public String getDisplayInnerTypeName() { return displayInnerTypeName; } + public Icon getIcon() { return getIcon(access); } + + @SuppressWarnings("unchecked") + public List getInnerTypes() { + if (innerTypes == null) { + innerTypes = new ArrayList<>(classNode.innerClasses.size()); + + for (final InnerClassNode innerClassNode : (List)classNode.innerClasses) { + if (((innerClassNode.access & (Opcodes.ACC_SYNTHETIC|Opcodes.ACC_BRIDGE)) == 0) && this.name.equals(innerClassNode.outerName)) { + Container.Entry innerEntry = getEntry(innerClassNode.name); + + if (innerEntry != null) { + try (InputStream is = innerEntry.getInputStream()) { + ClassReader classReader = new ClassReader(is); + innerTypes.add(new JavaType(innerEntry, classReader)); + } catch (IOException ignore) { + } + } + } + } + } + return innerTypes; + } + + protected Container.Entry getEntry(String typeName) { + String pathToFound = typeName + ".class"; + + for (Container.Entry e : entry.getParent().getChildren()) { + if (e.getPath().equals(pathToFound)) { + return e; + } + } + + return null; + } + + @SuppressWarnings("unchecked") + public List getFields() { + if (fields == null) { + fields = new ArrayList<>(classNode.fields.size()); + + for (final FieldNode fieldNode : (List)classNode.fields) { + if ((fieldNode.access & (Opcodes.ACC_SYNTHETIC|Opcodes.ACC_ENUM)) == 0) { + fields.add(new Type.Field() { + public int getFlags() { return fieldNode.access; } + public String getName() { return fieldNode.name; } + public String getDescriptor() { return fieldNode.desc; } + public Icon getIcon() { return fieldIcons[accessToIndex(fieldNode.access)]; } + }); + } + } + } + return fields; + } + + @SuppressWarnings("unchecked") + public List getMethods() { + if (methods == null) { + methods = new ArrayList<>(classNode.methods.size()); + + for (final MethodNode methodNode : (List)classNode.methods) { + if ((methodNode.access & (Opcodes.ACC_SYNTHETIC|Opcodes.ACC_ENUM|Opcodes.ACC_BRIDGE)) == 0) { + methods.add(new Type.Method() { + public int getFlags() { return methodNode.access; } + public String getName() { return methodNode.name; } + public String getDescriptor() { return methodNode.desc; } + public Icon getIcon() { return methodIcons[accessToIndex(methodNode.access)]; } + }); + } + } + } + return methods; + } + + protected static ImageIcon getIcon(int access) { + if ((access & Opcodes.ACC_ANNOTATION) != 0) + return annotationIcon; + else if ((access & Opcodes.ACC_INTERFACE) != 0) + return interfaceIcons[accessToIndex(access)]; + else if ((access & Opcodes.ACC_ENUM) != 0) + return enumIcon; + else + return classIcons[accessToIndex(access)]; + } + + protected static int accessToIndex(int access) { + int index = 0; + + if ((access & Opcodes.ACC_STATIC) != 0) + index += 4; + + if ((access & Opcodes.ACC_FINAL) != 0) + index += 8; + + if ((access & Opcodes.ACC_ABSTRACT) != 0) + index += 16; + + if ((access & Opcodes.ACC_PUBLIC) != 0) + return index + 1; + else if ((access & Opcodes.ACC_PROTECTED) != 0) + return index + 2; + else if ((access & Opcodes.ACC_PRIVATE) != 0) + return index + 3; + else + return index; + } + + // Graphic stuff ... + protected static ImageIcon mergeIcons(ImageIcon background, ImageIcon overlay, int x, int y) { + int w = background.getIconWidth(); + int h = background.getIconHeight(); + BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + + if (x + overlay.getIconWidth() > w) + x = w - overlay.getIconWidth(); + if (y + overlay.getIconHeight() > h) + y = h - overlay.getIconHeight(); + + Graphics2D g2 = image.createGraphics(); + g2.drawImage(background.getImage(), 0, 0, null); + g2.drawImage(overlay.getImage(), x, y, null); + g2.dispose(); + + return new ImageIcon(image); + } + + protected static ImageIcon[] mergeIcons(ImageIcon[] backgrounds, ImageIcon overlay, int x, int y) { + int length = backgrounds.length; + ImageIcon[] result = new ImageIcon[length*2]; + + // Copy source icons + System.arraycopy(backgrounds, 0, result, 0, length); + + // Add overlays + for (int i=0; i 0) + this.indentationCount--; + } + + public void startOfLine(int lineNumber) { + for (int i=0; i 0) { + append(NEWLINE); + } + } + } + + public void startOfComment() {} + public void endOfComment() {} + + public void startOfJavadoc() {} + public void endOfJavadoc() {} + + public void startOfXdoclet() {} + public void endOfXdoclet() {} + + public void startOfError() {} + public void endOfError() {} + + public void startOfImportStatements() {} + public void endOfImportStatements() {} + + public void startOfTypeDeclaration(String internalPath) {} + public void endOfTypeDeclaration() {} + + public void startOfAnnotationName() {} + public void endOfAnnotationName() {} + + public void startOfOptionalPrefix() { + if (isShowPrefixThis() == false) + this.display = false; + } + + public void endOfOptionalPrefix() { + this.display = true; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // + + public void debugStartOfLayoutBlock() {} + public void debugEndOfLayoutBlock() {} + + public void debugStartOfSeparatorLayoutBlock() {} + public void debugEndOfSeparatorLayoutBlock(int min, int value, int max) {} + + public void debugStartOfStatementsBlockLayoutBlock() {} + public void debugEndOfStatementsBlockLayoutBlock(int min, int value, int max) {} + + public void debugStartOfInstructionBlockLayoutBlock() {} + public void debugEndOfInstructionBlockLayoutBlock() {} + + public void debugStartOfCommentDeprecatedLayoutBlock() {} + public void debugEndOfCommentDeprecatedLayoutBlock() {} + + public void debugMarker(String marker) {} + + public void debugStartOfCaseBlockLayoutBlock() {} + public void debugEndOfCaseBlockLayoutBlock() {} + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // + + protected void printEscape(String s) { + if (isUnicodeEscape()) { + int length = s.length(); + + for (int i=0; i> 3))); + append((char) ('0' + (c & 0x7))); + } else if (c > 127) { + // Write octal format + append("\\u"); + + int z = (c >> 12); + append((char) ((z <= 9) ? ('0' + z) : (('A' - 10) + z))); + z = ((c >> 8) & 0xF); + append((char) ((z <= 9) ? ('0' + z) : (('A' - 10) + z))); + z = ((c >> 4) & 0xF); + append((char) ((z <= 9) ? ('0' + z) : (('A' - 10) + z))); + z = (c & 0xF); + append((char) ((z <= 9) ? ('0' + z) : (('A' - 10) + z))); + } else { + append(c); + } + } + } else { + append(s); + } + } +} diff --git a/services/src/main/java/jd/gui/util/decompiler/ContainerLoader.java b/services/src/main/java/jd/gui/util/decompiler/ContainerLoader.java new file mode 100644 index 00000000..4d87d333 --- /dev/null +++ b/services/src/main/java/jd/gui/util/decompiler/ContainerLoader.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.util.decompiler; + +import jd.core.loader.Loader; +import jd.core.loader.LoaderException; +import jd.gui.api.model.Container; + +import java.io.DataInputStream; + +public class ContainerLoader implements Loader { + protected Container.Entry entry; + + public ContainerLoader() { this.entry = null; } + public ContainerLoader(Container.Entry entry) { + this.entry = entry; + } + + protected Container.Entry getEntry(String internalPath) { + for (Container.Entry e : entry.getParent().getChildren()) { + if (e.getPath().equals(internalPath)) { + return e; + } + } + return null; + } + + public void setEntry(Container.Entry e) { this.entry = e; } + + // --- Loader --- // + public DataInputStream load(String internalPath) throws LoaderException { + return new DataInputStream(getEntry(internalPath).getInputStream()); + } + + public boolean canLoad(String internalPath) { + return getEntry(internalPath) != null; + } +} diff --git a/services/src/main/java/jd/gui/util/decompiler/GuiPreferences.java b/services/src/main/java/jd/gui/util/decompiler/GuiPreferences.java new file mode 100644 index 00000000..abe99cf6 --- /dev/null +++ b/services/src/main/java/jd/gui/util/decompiler/GuiPreferences.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.util.decompiler; + +import jd.core.preferences.Preferences; + +public class GuiPreferences extends Preferences +{ + protected boolean showPrefixThis; + protected boolean unicodeEscape; + protected boolean showLineNumbers; + + public GuiPreferences() + { + this.showPrefixThis = true; + this.unicodeEscape = false; + this.showLineNumbers = true; + } + + public GuiPreferences( + boolean showDefaultConstructor, boolean realignmentLineNumber, + boolean showPrefixThis, boolean unicodeEscape, boolean showLineNumbers) + { + super(showDefaultConstructor, realignmentLineNumber); + this.showPrefixThis = showPrefixThis; + this.unicodeEscape = unicodeEscape; + this.showLineNumbers = showLineNumbers; + } + + public void setShowDefaultConstructor(boolean b) { showDefaultConstructor = b; } + public void setRealignmentLineNumber(boolean b) { realignmentLineNumber=b; } + public void setShowPrefixThis(boolean b) { showPrefixThis = b; } + public void setUnicodeEscape(boolean b) { unicodeEscape=b; } + public void setShowLineNumbers(boolean b) { showLineNumbers=b; } + + public boolean isShowPrefixThis() { return showPrefixThis; } + public boolean isUnicodeEscape() { return unicodeEscape; } + public boolean isShowLineNumbers() { return showLineNumbers; } +} diff --git a/services/src/main/java/jd/gui/util/decompiler/PlainTextPrinter.java b/services/src/main/java/jd/gui/util/decompiler/PlainTextPrinter.java new file mode 100644 index 00000000..5ce5fb43 --- /dev/null +++ b/services/src/main/java/jd/gui/util/decompiler/PlainTextPrinter.java @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2008-2015 Emmanuel Dupuy + * This program is made available under the terms of the GPLv3 License. + */ + +package jd.gui.util.decompiler; + +import java.io.PrintStream; + +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.printer.Printer; + +public class PlainTextPrinter implements Printer { + protected static final String TAB = " "; + protected static final String NEWLINE = "\n"; + + protected GuiPreferences preferences = null; + protected PrintStream printStream = null; + protected int maxLineNumber = 0; + protected int majorVersion = 0; + protected int minorVersion = 0; + protected int digitCount = 0; + + protected String lineNumberBeginPrefix; + protected String lineNumberEndPrefix; + protected String unknownLineNumberPrefix; + protected int indentationCount; + protected boolean display; + + public void setPreferences(GuiPreferences preferences) { this.preferences = preferences; } + public void setPrintStream(PrintStream printStream) { this.printStream = printStream; } + + public int getMajorVersion() { return majorVersion; } + public int getMinorVersion() { return minorVersion; } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // + + public void print(byte b) { this.printStream.append(String.valueOf(b)); } + public void print(int i) { this.printStream.append(String.valueOf(i)); } + + public void print(char c) { + if (this.display) + this.printStream.append(String.valueOf(c)); + } + + public void print(String s) { + if (this.display) + printEscape(s); + } + + public void printNumeric(String s) { this.printStream.append(s); } + + public void printString(String s, String scopeInternalName) { this.printStream.append(s); } + + public void printKeyword(String s) { + if (this.display) + this.printStream.append(s); + } + + public void printJavaWord(String s) { this.printStream.append(s); } + + public void printType(String internalName, String name, String scopeInternalName) { + if (this.display) + printEscape(name); + } + + public void printTypeDeclaration(String internalName, String name) + { + printEscape(name); + } + + public void printTypeImport(String internalName, String name) + { + printEscape(name); + } + + public void printField(String internalName, String name, String descriptor, String scopeInternalName) { + printEscape(name); + } + public void printFieldDeclaration(String internalName, String name, String descriptor) { + printEscape(name); + } + + public void printStaticField(String internalName, String name, String descriptor, String scopeInternalName) { + printEscape(name); + } + public void printStaticFieldDeclaration(String internalName, String name, String descriptor) { + printEscape(name); + } + + public void printConstructor(String internalName, String name, String descriptor, String scopeInternalName) { + printEscape(name); + } + public void printConstructorDeclaration(String internalName, String name, String descriptor) { + printEscape(name); + } + + public void printStaticConstructorDeclaration(String internalName, String name) { + this.printStream.append(name); + } + + public void printMethod(String internalName, String name, String descriptor, String scopeInternalName) { + printEscape(name); + } + public void printMethodDeclaration(String internalName, String name, String descriptor) { + printEscape(name); + } + + public void printStaticMethod(String internalName, String name, String descriptor, String scopeInternalName) { + printEscape(name); + } + public void printStaticMethodDeclaration(String internalName, String name, String descriptor) { + printEscape(name); + } + + public void start(int maxLineNumber, int majorVersion, int minorVersion) { + this.majorVersion = majorVersion; + this.minorVersion = minorVersion; + this.indentationCount = 0; + this.display = true; + + if (this.preferences.isShowLineNumbers()) { + this.maxLineNumber = maxLineNumber; + + if (maxLineNumber > 0) { + this.digitCount = 1; + this.unknownLineNumberPrefix = " "; + int maximum = 9; + + while (maximum < maxLineNumber) { + this.digitCount++; + this.unknownLineNumberPrefix += ' '; + maximum = maximum*10 + 9; + } + + this.lineNumberBeginPrefix = "/* "; + this.lineNumberEndPrefix = " */ "; + } else { + this.unknownLineNumberPrefix = ""; + this.lineNumberBeginPrefix = ""; + this.lineNumberEndPrefix = ""; + } + } else { + this.maxLineNumber = 0; + this.unknownLineNumberPrefix = ""; + this.lineNumberBeginPrefix = ""; + this.lineNumberEndPrefix = ""; + } + } + + public void end() {} + + public void indent() { + this.indentationCount++; + } + public void desindent() { + if (this.indentationCount > 0) + this.indentationCount--; + } + + public void startOfLine(int lineNumber) { + if (this.maxLineNumber > 0) + { + this.printStream.append(this.lineNumberBeginPrefix); + + if (lineNumber == Instruction.UNKNOWN_LINE_NUMBER) { + this.printStream.append(this.unknownLineNumberPrefix); + } else { + int left = 0; + + left = printDigit(5, lineNumber, 10000, left); + left = printDigit(4, lineNumber, 1000, left); + left = printDigit(3, lineNumber, 100, left); + left = printDigit(2, lineNumber, 10, left); + this.printStream.append((char)('0' + (lineNumber-left))); + } + + this.printStream.append(this.lineNumberEndPrefix); + } + + for (int i=0; i 0) { + if (this.maxLineNumber > 0) { + this.printStream.append(this.lineNumberBeginPrefix); + this.printStream.append(this.unknownLineNumberPrefix); + this.printStream.append(this.lineNumberEndPrefix); + } + + this.printStream.append(NEWLINE); + } + } + } + + public void startOfComment() {} + public void endOfComment() {} + + public void startOfJavadoc() {} + public void endOfJavadoc() {} + + public void startOfXdoclet() {} + public void endOfXdoclet() {} + + public void startOfError() {} + public void endOfError() {} + + public void startOfImportStatements() {} + public void endOfImportStatements() {} + + public void startOfTypeDeclaration(String internalPath) {} + public void endOfTypeDeclaration() {} + + public void startOfAnnotationName() {} + public void endOfAnnotationName() {} + + public void startOfOptionalPrefix() { + if (this.preferences.isShowPrefixThis() == false) + this.display = false; + } + + public void endOfOptionalPrefix() + { + this.display = true; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // + + public void debugStartOfLayoutBlock() {} + public void debugEndOfLayoutBlock() {} + + public void debugStartOfSeparatorLayoutBlock() {} + public void debugEndOfSeparatorLayoutBlock(int min, int value, int max) {} + + public void debugStartOfStatementsBlockLayoutBlock() {} + public void debugEndOfStatementsBlockLayoutBlock(int min, int value, int max) {} + + public void debugStartOfInstructionBlockLayoutBlock() {} + public void debugEndOfInstructionBlockLayoutBlock() {} + + public void debugStartOfCommentDeprecatedLayoutBlock() {} + public void debugEndOfCommentDeprecatedLayoutBlock() {} + + public void debugMarker(String marker) {} + + public void debugStartOfCaseBlockLayoutBlock() {} + public void debugEndOfCaseBlockLayoutBlock() {} + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // + + protected void printEscape(String s) { + if (this.preferences.isUnicodeEscape()) { + int length = s.length(); + + for (int i=0; i> 3))); + this.printStream.append((char)('0' + (c & 0x7))); + } else if (c > 127) { + // Write octal format + this.printStream.append("\\u"); + + int z = (c >> 12); + this.printStream.append((char)((z <= 9) ? ('0' + z) : (('A' - 10) + z))); + z = ((c >> 8) & 0xF); + this.printStream.append((char)((z <= 9) ? ('0' + z) : (('A' - 10) + z))); + z = ((c >> 4) & 0xF); + this.printStream.append((char)((z <= 9) ? ('0' + z) : (('A' - 10) + z))); + z = (c & 0xF); + this.printStream.append((char)((z <= 9) ? ('0' + z) : (('A' - 10) + z))); + } else { + this.printStream.append(c); + } + } + } else { + this.printStream.append(s); + } + } + + protected int printDigit(int dcv, int lineNumber, int divisor, int left) { + if (this.digitCount >= dcv) { + if (lineNumber < divisor) { + this.printStream.append(' '); + } else { + int e = (lineNumber-left) / divisor; + this.printStream.append((char)('0' + e)); + left += e*divisor; + } + } + + return left; + } +} diff --git a/services/src/main/resources/META-INF/services/jd.gui.spi.ContainerFactory b/services/src/main/resources/META-INF/services/jd.gui.spi.ContainerFactory new file mode 100644 index 00000000..09008cf8 --- /dev/null +++ b/services/src/main/resources/META-INF/services/jd.gui.spi.ContainerFactory @@ -0,0 +1,2 @@ +jd.gui.service.container.JarContainerFactoryProvider +jd.gui.service.container.GenericContainerFactoryProvider diff --git a/services/src/main/resources/META-INF/services/jd.gui.spi.FileLoader b/services/src/main/resources/META-INF/services/jd.gui.spi.FileLoader new file mode 100644 index 00000000..98254020 --- /dev/null +++ b/services/src/main/resources/META-INF/services/jd.gui.spi.FileLoader @@ -0,0 +1,4 @@ +jd.gui.service.fileloader.ClassFileLoaderProvider +jd.gui.service.fileloader.JarFileLoaderProvider +jd.gui.service.fileloader.LogFileLoaderProvider +jd.gui.service.fileloader.ZipFileLoaderProvider diff --git a/services/src/main/resources/META-INF/services/jd.gui.spi.Indexer b/services/src/main/resources/META-INF/services/jd.gui.spi.Indexer new file mode 100644 index 00000000..c8d5c7c9 --- /dev/null +++ b/services/src/main/resources/META-INF/services/jd.gui.spi.Indexer @@ -0,0 +1,5 @@ +jd.gui.service.indexer.DirectoryIndexerProvider +jd.gui.service.indexer.ClassFileIndexerProvider +jd.gui.service.indexer.MetainfServiceFileIndexerProvider +jd.gui.service.indexer.TextFileIndexerProvider +jd.gui.service.indexer.ZipFileIndexerProvider diff --git a/services/src/main/resources/META-INF/services/jd.gui.spi.PasteHandler b/services/src/main/resources/META-INF/services/jd.gui.spi.PasteHandler new file mode 100644 index 00000000..78128628 --- /dev/null +++ b/services/src/main/resources/META-INF/services/jd.gui.spi.PasteHandler @@ -0,0 +1 @@ +jd.gui.service.pastehandler.LogPasteHandler diff --git a/services/src/main/resources/META-INF/services/jd.gui.spi.PreferencesPanel b/services/src/main/resources/META-INF/services/jd.gui.spi.PreferencesPanel new file mode 100644 index 00000000..ab309cae --- /dev/null +++ b/services/src/main/resources/META-INF/services/jd.gui.spi.PreferencesPanel @@ -0,0 +1,3 @@ +jd.gui.service.preferencespanel.DirectoryIndexerPreferencesProvider +jd.gui.service.preferencespanel.ClassFileSaverPreferencesProvider +jd.gui.service.preferencespanel.ClassFileViewerPreferencesProvider diff --git a/services/src/main/resources/META-INF/services/jd.gui.spi.SourceSaver b/services/src/main/resources/META-INF/services/jd.gui.spi.SourceSaver new file mode 100644 index 00000000..372e8f01 --- /dev/null +++ b/services/src/main/resources/META-INF/services/jd.gui.spi.SourceSaver @@ -0,0 +1,5 @@ +jd.gui.service.sourcesaver.ClassFileSourceSaverProvider +jd.gui.service.sourcesaver.DirectorySourceSaverProvider +jd.gui.service.sourcesaver.FileSourceSaverProvider +jd.gui.service.sourcesaver.PackageSourceSaverProvider +jd.gui.service.sourcesaver.ZipFileSourceSaverProvider diff --git a/services/src/main/resources/META-INF/services/jd.gui.spi.TreeNodeFactory b/services/src/main/resources/META-INF/services/jd.gui.spi.TreeNodeFactory new file mode 100644 index 00000000..f8a68fb0 --- /dev/null +++ b/services/src/main/resources/META-INF/services/jd.gui.spi.TreeNodeFactory @@ -0,0 +1,17 @@ +jd.gui.service.treenode.ClassFileTreeNodeFactoryProvider +jd.gui.service.treenode.DirectoryTreeNodeFactoryProvider +jd.gui.service.treenode.DtdFileTreeNodeFactoryProvider +jd.gui.service.treenode.FileTreeNodeFactoryProvider +jd.gui.service.treenode.HtmlFileTreeNodeFactoryProvider +jd.gui.service.treenode.JarFileTreeNodeFactoryProvider +#jd.gui.service.treenode.JavaFileTreeNodeFactoryProvider +jd.gui.service.treenode.JavascriptFileTreeNodeFactoryProvider +#jd.gui.service.treenode.JspFileTreeNodeFactoryProvider +jd.gui.service.treenode.ManifestFileTreeNodeFactoryProvider +jd.gui.service.treenode.MetainfDirectoryTreeNodeFactoryProvider +jd.gui.service.treenode.MetainfServiceFileTreeNodeFactoryProvider +jd.gui.service.treenode.PackageTreeNodeFactoryProvider +jd.gui.service.treenode.PropertiesFileTreeNodeFactoryProvider +jd.gui.service.treenode.TextFileTreeNodeFactoryProvider +jd.gui.service.treenode.XmlFileTreeNodeFactoryProvider +jd.gui.service.treenode.ZipFileTreeNodeFactoryProvider diff --git a/services/src/main/resources/META-INF/services/jd.gui.spi.TypeFactory b/services/src/main/resources/META-INF/services/jd.gui.spi.TypeFactory new file mode 100644 index 00000000..d2563e77 --- /dev/null +++ b/services/src/main/resources/META-INF/services/jd.gui.spi.TypeFactory @@ -0,0 +1 @@ +jd.gui.service.type.ClassFileTypeFactoryProvider diff --git a/services/src/main/resources/META-INF/services/jd.gui.spi.UriLoader b/services/src/main/resources/META-INF/services/jd.gui.spi.UriLoader new file mode 100644 index 00000000..5963a405 --- /dev/null +++ b/services/src/main/resources/META-INF/services/jd.gui.spi.UriLoader @@ -0,0 +1 @@ +jd.gui.service.uriloader.FileUriLoaderProvider diff --git a/services/src/main/resources/images/abstract_ovr.png b/services/src/main/resources/images/abstract_ovr.png new file mode 100644 index 0000000000000000000000000000000000000000..658b8fde5f54835615deda6e1c66dc50c1e5142d GIT binary patch literal 187 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)H!VDyjYyB_%0HK04TZfHCsE7VlN5u3x*0xc{95Kg&32(-Cfwl5<6Z4Ih+L^k;OpT1B~5HX4?T7 znw~C>Asp9}J-9i%6Ffo#ScTTC2~g^2)ND{xFi~hwG%zt}P&6?yVPIH(lw(Tn@pw6) OCI(MeKbLh*2~7Zr<2UdC literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/annotation_obj.png b/services/src/main/resources/images/annotation_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..38d5eab5af468ffd1394dd7c2b29c40649e7558a GIT binary patch literal 3021 zcmb_e`9BkmA0D|GIX|s@P>vkgm>iLEEtEFPZILtA-1|7@CTE)DidD`J6FKH+m?Pv$ zQe;SEnB3PKHSF8xfA~JH*YiBD=a={U_5Ajvn!}BOJm+};007X`#OU51Kl>lK&iqk% zWdRESfCu7bXlQO~XebpBTDhi@${ z9rm}+O?zwwA5KLSHh}>$2uU!6J(pD~|MCw`tk#%KqVZ_`34kLkmZcn^Vz*M+p}+Y~ zPX?m-7q)eP`}pxJAB)Lxhx^YJL`4D<@uk|b0{|F!&`U$ZweR%)x&$8*DNEZ>yHwsM zlLoq#nh&{c-W%kCLoNPW7$r7^9A0;mK=o2zSWFF~RS#3bB9fj;yYw3OvV-o!%TxRx z+p3v99~Rv~1)`zJ`TT%1nPy(C>M%ik%JW_UevIHw5Fnt81ks}LiUknasD>?NWe@jS z0(V$j!FMwJynR0wMFc^!v{>VcZ)W8TEH5)~0<-l9fT zm?{|D(ACWuq>cia*L#^-+qHYP=Lb@kwy#}B8WB8)NMtQ!TR6HV7T;YO9L}svWvZ+r z>|gj~%I_Bf)Q7lCz8A4BF5iePIm;pxZa%X=$Dkz$uv77Wm21~)9Tu{mFlqu)k1|J| zFvORI&Y5{|{{lVsq55!-#sXwmLTl2anCu&04b zFNF(;G~^THpvE6v6g0WgZLA@cXmagda-)=k2_%RYq+gyHD$kb|UsB44Y?en@a-}8S zHuTjKEmcGsBR2>VbfcW)^b14lJHA#_EIxVErEEZA7H=-X)CXz1v|Pt9|D zNlBmI**afWoqx_YtZk-B1C)yfOQ^+ydWK!z{Dg)37sjBowLJ!5eetCa&HZPSDoU%C6sT>TcVT&Z4A3 zkqBLsRRk)^uXz97bL%q2X+@$4uP8!()+RoOp2M0mq42l$szrg7HS)k5ZZ%sQi43<- zETUr&Uwyyod)HsAgNZotHffWrYH& z5%^+msV=0cPft%_OZUCjLN#(VSngv4x&*?3> z1u?4i%E6?=cioZpsi?l5Zr7Ln;fThHx66K?oFVRzT$@tLFi(}}nhiZHi=04KYA-zc z$=Hr+jdY$9?TCn!tQof-L`}_e9+Qs`j&ye^JBU5z4S?_uNpsQdtD{#{H0v}|ghWKg zMd)&q*GMu)`YC=XDrGvB(5ui!RSbAoz4|KJEobNTepOAf(xc!W9qBs3VnLu_L)CZd zEeBl*FG0Jr*BWnm+?^<>@)4bod!s8X3wocf4SIs(f9#ib+C_JrQ1x&nyS#RNXbY~6 zs$NDLhkzo|T>BN4%zCHa=k~$-rrvL);?qJ?AQ^?U)&Qjzi12k`Zy}n{iBN_NSSC@n zNp9g;X%=F~Ei9G%N+c({Iy=rXVLX03^D4fv-AgUfKiW_`yF;$sLQnL>Y@hp|L{wra z=m2B|@>erdLp(I~*dhKV?l*+GAr?u?k?s6VxTYE%8|Bd8&7atc{iX{=K-CMan%?N) zIjxRC*RjtZAAL;4#|)?qDt(M-mqp*P=?FS4Kdyfxfx`33@Eo!Cd_%weiZ=FL_S>3s z?r>$|5Q*#EJ}^1h5==79?meXgdh(iDmH4t=hjHi19sbSkb?V0X>5V#uXC=l9zA`B> zr@P@!Cw3Dl5v2!?$`7m^8#3w;B>%GRijv??+NlHMre&YaY-Lc5_Z#civq;_0*eIv% zqJ?+4=a&jf3J#M=$(s|{@n(t_B}cMPd_?QG@kV3Ep-&&>36KW}14?FW9Xja_IPx{e`+qeXZ6x@`DBAV@*tjhSA7aJeDRvTc%#r_SXha1c&T|z1uEsu z7X4^r@9>CmayRT*U={)Qx~;0~WAB%5LzFrHEJ92nF{5Ds-!_up-2e6iWpn>m`{!@F zM~wa7$9umR6U!@;KUbFy=zEOcf8PFoF~Ka<`E!v4a}RC-(4$R0{1akLjr1+gjXn7^ z$ltBP$2R)Z*~hM+TSi2fkL{FsAx_T7fZ8=f8_Y$!M#HArX=@f6U@p^l#xsun^qOHr z&H1wgZcy&7R+tMxWr00sW literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/ascii_obj.png b/services/src/main/resources/images/ascii_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..4e9dc3802a41589f1c0ac74a6654e36f6cb80d0f GIT binary patch literal 713 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47#jk7LR>$8{r%(TpX93L?>_zd z^!4}8Uw?l5{2f=eIIV6)R@0i?mbHZ)8;d(P)lAw^H+fgjg2Nxa{BE4Sr)Adu&UptX zEbZ z?0U1=_2$!REFPTb-_&KWuETIuoAH%R8CN!C-r8GpbyMd5|NnuW8ls>%TT&h9bf=Oa zzhIz8C<6>GVxU-NU`+CMcd7T-U-%Tr;VkfoEC$jZVC;4>+YZQ>;_2cTB5^tP)N8Ru z2a&dilFvUEE;$_F(8dNPA5^uUWz_P;us~L~-N>)*ml<=PT)&ElN+c2D*>I M)78&qol`;+0Bn;cG5`Po literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/class_default_obj.png b/services/src/main/resources/images/class_default_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..078a1647ed305d9821b2bc1740fb142ca4be6c55 GIT binary patch literal 3275 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 F{{xPAHo^b^ literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/class_obj.png b/services/src/main/resources/images/class_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..b58c84c7a70d81829070b4030a156d17f7567b8c GIT binary patch literal 3147 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 literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/class_private_obj.png b/services/src/main/resources/images/class_private_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..ab2298525ea090030036b5b95ff4c428a5ef999a GIT binary patch literal 3273 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 P|F@T^A=IEz50Ugg`~eSo literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/class_protected_obj.png b/services/src/main/resources/images/class_protected_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..678aa329aa1b9123a74c303615fe1d536062f50b GIT binary patch literal 3275 zcmb_eXFD4T0}ZWFgc@7qf)Y5 z<^TX2%v)F2)JRuXBrrI@!yDxe02mHD%ST&SOz`7AcA+s9ALKrRF}YAV>;Y8d#$}{{ z2eZICKrhEbR5C&9J~uamURF7lp{l~LG1=v&6v2th@T#ecTq=R!ra%55Dk5TgY3X>N zYi`eu={0@l~g8DvH+hLsG%| zDMhdcrhUOK8TO0+DU0TxLJn`Z3EB72O3bH*Q1Zvg;gLyMVlI6KeN5ng;5EqsPiz#8 z3Wq_v_CY8GToETA71GYG(iqN-PcH1^;tb{94F&{OlVK{$?EHbG%QW4N>S~Yuj-Xw} zS5V_je;>aO<&nV(xhjlt6`HwugNrSzQ0bvM6URG%C!QC7gM<85D@E;#?dyac4S9opB0{2#fv&a=EdLSPf8)hKSAZCc6E4Qb>gd#4l4x%(m#9E zi@+goY0A^~r%(9IeG)A4#-!_<>ukMKTkBfOLP?>`p}7Z^t483)wDvSShrPt3<)&f1 zB6&8QPvvA&o2Rl*G4I6Rsep99R$!341ii5U!uc537Chxnsvy~tEJ>bj241WW@ymL~ zm3gD^(Il_!0x4LKU5_ov)#!cB8}X3f)ZmO@!491cs}8l`?WNT{|GkvG&Ly=)Vd-+d z0}vyh0*Le0KW2qi)wiZ^k@(m_2&q}?_`HKW#=LRq8&+%P#gMBTiNuHDj;b?CG78`s z@Rku>2NE&Czu5oTmY;f>kS+|ljh%fMZ8N8%>Dc{%p2UE1@_wzP;w0C^*ENQb4)C7& z?5vwpk?Wk~+%iw#{xCQo^^wr~GqJfQ=<%-qg5v^0f?vW&;!uLi#NEWYaJeX~=)$Ka zpkJXuq0 zwrjd+(#n@#hY~`~JyU%}+uxV(t+*_ZW|t^3w6%G=pVQkC z3;Z;z)uTy=8TFB_sp$UR9@l3B5s22>mn;4sonh{WrRh07_h#DCsOdPWtvY(n~Iis8%ov80k>>~E*8UWrO!ls~|+oQMTl$(^3dH6tM zd~F7>V+HqgfC z#ub!77&tQ3bwGN_q;L9dem}f_>g{F zBo=b2auK_3;VG0-zPzW6Pva~S#^T4aZ{u6LycMGYVsurXQYE^~wLs@4hgbehv`?%8 zAAv2w0gAec2oEFAUD9vTVGG&~u}EHt>f&t6Xd|jw%c4WJeqw45+pd=b<*&a|_CXEL zsZfVpzkK@e_(KXlc2IFh=0jwcILg?X8hlZ6*8E(^9?uS8J7MbmhI;uGW#G5szdh$n zb){z@5;uB$^(6F`^n_Dw-%d~!&g*FniO-tVPL2OI=G^Mpplx28-fTMcstfgouTBch zsc*U;ka|cHkyS^IvX87BTQZvv<0dQzrGpG zAMK}Ub2d62Ff|v`yQaVLa2@Y(={?H`rz(ddc?q+==l9~<#C9V^QI1a`6s-~*z6d?t zTI{Nhgl&6%FNqDgc#%U7o}Zvu z@4d*NI3B%<9FINP#V;!Fha?6p%?U*hgioAmY@GK+EwgOkQZq5aof;9b7;+Y+Y3KU! z?Vs5kj9Z*(P7bL2(xIVQqW=&Sp06Xqz<+7o?YfMNjJ=px2!9r! zs?d&9libvlTph0}Y?D|LO3J6?8K8A=GCS%Fzc_~FQ8r-Zs*`YN3D# Z1AyW$2CHAllKbCQMtbo3L>;I2{{r{fA+i7f literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/classf_obj.png b/services/src/main/resources/images/classf_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..6393f818c17da3e6cdc1494871fbdfde2543dfad GIT binary patch literal 522 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMffdHQnS8=1*_wT=-ICuBZep7+YZQ>=jq}YB5^tO>~+3F20W|*)^i!1xODF}@BMz}f4yX0@ItRU zzXhIq6gp_OcDxc_usd;f{e$Q!dORBbtC_DV`gZTV%5ZIh?DL!3BF=MMm~d&@U(d^- z%*!<0lkfJ{J=&e;f8Bk_(k%0@4eBxxj~c@dKW5@7V$)f^x$XC)wh0P34~v&7s&zzH z%(eK?q422c_}Rj?UEF`YCHJ&ia0{|54T|@gA^Gpedc9bnOBp;}{an^LB{Ts5iAomz literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/constr_ovr.png b/services/src/main/resources/images/constr_ovr.png new file mode 100644 index 0000000000000000000000000000000000000000..65964a92e80022db7a4b51b90f2209825a651123 GIT binary patch literal 180 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)H!VDyjYyB_zLiQ$MF*A~uJMrEL422WQ% Jmvv4FO#truIXVCU literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/dtd_obj.gif b/services/src/main/resources/images/dtd_obj.gif new file mode 100644 index 0000000000000000000000000000000000000000..64ee53610764262cefb2d4a93b813bf095e0e8ed GIT binary patch literal 351 zcmZ?wbhEHb6krfwxXQrr>Fe*Gzy7S*bM?uapKm|?y7T<|{g*!;zWVX%!_Q~$er8YD z^Wp37uRnf&|M^=ZXFX2kksm$$q~G>}PXJ>l|6#GawSSutX{ z4LBdsvnK?U`Yo?^DC_8&X n_9AvsS24ELYu1Rl3bAh5yjk2;M37%#=PrH`VV{G}jttfS0yTcV literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/enum_obj.png b/services/src/main/resources/images/enum_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..a9ecedf31e57a5d992db3d3f30e24c2befc78e18 GIT binary patch literal 3043 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 literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/field_default_obj.png b/services/src/main/resources/images/field_default_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..becfe6b118bd7f5ec63412bee50aa6ff2ef72b31 GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFP2=EDUbu3>W+_p;~W{za?0=4Yr zIt42{nm2DadH+8c09By_8JTXN5LZc%Uob=skYw0&M&~?GlrhQM-GyIb7sE{;hqJ&V zvKUBvfU(=jY&#%B*VDx@gyVYh3{F;_BStn0doq&(+%mIOTM{oOa;Ew4XK=6^t7&R# ePE0W3U|^_^_sE}m|GykiBZH@_pUXO@geCxhNkORq literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/field_private_obj.png b/services/src/main/resources/images/field_private_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..d3fa87ddd889b2ba20378660b660e65ee4f8e090 GIT binary patch literal 177 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPGa2=EDUz2W5lxV+(c$Atf202GFR zTyu-9Ko)CBkY6xJhT-=%zF?pLW0JSK3%gii$7>*mv%n*=7)X17vD?XPJ0L^R)5S4_ z<9c#IBNJPYBoB{{0NY~4DF<_SgbkA%gPpgWWY~OCZp*aa`;>u-89ZJ6T-G@yGywop C!88^C literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/field_protected_obj.png b/services/src/main/resources/images/field_protected_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..dc80489bc455b63fa58d6373c3a5f37a72cf49a0 GIT binary patch literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFP2=EDU-8V;L_YC#jGu79%%Wv*g z+SIGGyiR6SqwK0CxpnOd|L#rucRuGo7yxwu!MB5XSwM=fB*-rqA`T@PTo2qi0hD1( z@^*LOm)ON{6UgB#@Q5r1(jH*!b~4)z$k6q4aSY+Op1gybmFI|2#ljwL?gcz6gLfqy uyK0-h&A}yY{INU#c=6t=KI8l*FFO^GI+ZBxvX^Js literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/field_public_obj.png b/services/src/main/resources/images/field_public_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..40a5ef1c8e99b56f5a241662542972610ea853ef GIT binary patch literal 221 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFP2=EDU6=?G{nUUeLu%veH{D~*l z$#n)5ZY=HG(fA(>fU3}dSbDQ9P>8D}$S)Y821qh&I-_$QD9V`R?e4-av5Vm*ki%Kv z5m^kRJ;2!QWVRiUVc_ZF7{YNqc?KsdkBiZq5QQGiN3HV`jveVS^E60ya*_^N&^o+Z zgPjOoRPbaC7GM`HtOxNXs0G-B4T$c}kBOr0;=~OYc#urO$Gn+|5fS)j#l^#MJ^4xN z4;JPt=rVZekdEb+p{i3d6n9^I?-Uhb#1XI!YHBpQ(4s5s(`hNo5`Z57P~`x1t2SR? zm&`=1L2dy=y8ljZ^xmI0bG?W}F>pZTk!w02vlm3wZOzF8$k7708h{vk05$^*@R0c| zpsPUu0DTrP&_Yf=3-X+Uszns}+8CCBn^+aVVqm*k228>SVE+BicL4?f<|L@;a3hO+ P00000NkvXXu0mjfhMj*& literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/final_ovr.png b/services/src/main/resources/images/final_ovr.png new file mode 100644 index 0000000000000000000000000000000000000000..f20a9c1e81cac70dd7d1e05a041a6d5f9246b1d9 GIT binary patch literal 122 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)H#0(@ovUsNgDV_kI5ZA?1v^A2Z1=lb6|Ns97 zC9lswamJD$zhDN3XE)M-92rj+#}JO|$p*6zC;V+c_=}-=CUeJ@v;>261||ldy(}+8 Td@QyC)iHRw`njxgN@xNAg{&kp literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/folder.gif b/services/src/main/resources/images/folder.gif new file mode 100644 index 0000000000000000000000000000000000000000..42e027c933103acb0bc3a6889b1ee253bdfa4657 GIT binary patch literal 219 zcmZ?wbhEHb6krfwIKsg2=fjTwU(ft}x$*zUL!a)i`2TwI|EEj--|GB-f7+YNbN*i} z{eQLg>4}NkYYq1|o9u5f+1+4#yxaU}r`gdi^F!@s8_V^#R2r-=)!$xYw6WY^bAj4_ zFkpZI#h)yU3=A?1Iv@d%oeZoI3hI3+ne)<@xV>1B`(fEuK?V+&Lu+13upU?-aN>~% z+leJYmV$v?7gmUP30m^pSR?jZz)|4A1_>U)M7|eWr0xntihbB2lP8!e@?(!&ykzXZ OhQ@l`mR1!-25SJE4`R#! literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/folder_open.png b/services/src/main/resources/images/folder_open.png new file mode 100644 index 0000000000000000000000000000000000000000..9759da4e201ada7fdd227639be4fc236daf3e2f5 GIT binary patch literal 310 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJdx@v7EBj4G0R}D3ChfORfI^%F z9+AZi404A+m@)4{sU1*|CEd~2k%3`jKlh(RRvZtd^mBq)$GTM z86R#;cyOTN#)g8mIVwQY4tJaRtrl$nn$K7gBP{sX|~qoWsG%}CwD(~e015aB{YAxe?@`!vkHmjInNf#bEGk> x-703iFf*gaQ8~zY=?1Yo0gHsnnMH1HPZl@c##+D1w+G}Q22WQ%mvv4FO#riXdr<%Y literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/generate_class.png b/services/src/main/resources/images/generate_class.png new file mode 100644 index 0000000000000000000000000000000000000000..904ee07a3cd8212435265f0d16e166f4e58041e4 GIT binary patch literal 297 zcmV+^0oMMBP)h>&v%!3!NPNjh&^>7heh6bvN#`?y3cJnp! vy)I%)Ljoq=Z95LXzPOSJqN>B0FaED@`tD4iQ7B9E00000NkvXXu0mjfhDdvk literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/generate_int.png b/services/src/main/resources/images/generate_int.png new file mode 100644 index 0000000000000000000000000000000000000000..82a5d80665642c87d2e0cf8380d2a49af83fbe88 GIT binary patch literal 2918 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 KDooBoK>#}%3&N-X literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/int_default_obj.png b/services/src/main/resources/images/int_default_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..35241b0056bb9b32cba04376525af914bd48415d GIT binary patch literal 3272 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 literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/int_obj.png b/services/src/main/resources/images/int_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..745cdea526147bfa77d6284b8dbf4a3c43d5c026 GIT binary patch literal 3254 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 Ov74JfZ&Vq%#s44dC-6}K literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/int_private_obj.png b/services/src/main/resources/images/int_private_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..f36c8b5f8f6650012ec8a7701dcea3e2cd26eeee GIT binary patch literal 3271 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 Hu0mjfaz#K$ literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/java_obj.png b/services/src/main/resources/images/java_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..dceae72198d63ea160d4a81e76d62e981479b90f GIT binary patch literal 738 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47#jk7LR>$5{{8vu@3$X+efa$A z>-XP3fBm`t;>W|6KOVpS`Q-JF=WlPK>KYaQ1{pX)=KYl-W_2coIA8$VWdjIA3+fP5UC+vCl?#IgyKRY{#TTGTTn=EKDo!?|SryhvRrq!4~IMKhU%V2$n z;hJ`%m955CHf3DdlzD4!&DBkr|Ns97`g(AJ`=R@G0bS->666;QbSKpS!{sc&2B5)= zN#5=*^&a~Rp8`3Y1s;*bK-vS0-A-oP0U3)tT^vIsF2|mDDb^Su(fUw$;zyO`0n500 zPfV$trupuF)tsl@TPwcbs+arnhx;OXV7!I;y}Ql)F${;?1rB;mOFbUq|L`r>hQ!F$ zriBvO4YG>5Ts+R(7^+3i2d-Ffj4>gqf2(H7?4!yDd<06ksv_qz>zEwhNE!D zdoO2X&04>djX~LOQ?BQ#qNR2RSe_ROCF^u0Gwgr8%hu}rXU4iJ#>e$Q_lbZ literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/js_obj.png b/services/src/main/resources/images/js_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..6f6fa6ac4a5cef5779cb10ad95cee6992e010bd2 GIT binary patch literal 406 zcmV;H0crk;P)5XOJ^z(&x*PSDaaU}+&DsYL9pEX2ZK6;V(uQYfTUkQg7m*jOlvjYm*W`(Twn z!NwP8?y@^$kr)$lr-BZAu*1%NGvCY({L!3N=k7eK-vy6MZaUwx-JNGOj7%)jy1M)5u~lx)7B!JT#3gckBFASqbHGyZ3Opb2eEP@M8JO6iSKhcjS=LyB znz$XZB7smq6jWg_z1n85(y1YWas?4ENfM0l5b9agp?Ut)Un*pXUPEd&NrJk(KZhNYxX8}} zP<;s-(@GqphZX&Cfo#%05Ougb+5g23y8N4c0D?-(Ci8`CBme*a07*qoM6N<$f}qo} AAOHXW literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/manifest_obj.png b/services/src/main/resources/images/manifest_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..8ec970c19736b7c5948251f729bf125db42847cc GIT binary patch literal 463 zcmV;=0WkiFP)Px$iAh93R5;76lRZyVQ4ofo*>!gf8yePTVWj|+TkaK>U{9hIzkrHv{{a8METOjA z&{9~D&_N}MF;Wmd0u2d9(1O^gg^BK-Gh=aX@ZNAQjZSisGs&FieP<>I{xKw->}<5{ zzT)MzW4V{My&l`|fy+H-J6+2YD5Vo`#RAoOgX!q`9hVt^GeM2qQ>{0s)Ei7ii@bR? zXZZjxygm6u-0c&0`&@nf0l?njB`^CmmbbGW_Zry0P|1WVYpN}2tWE1Wm>Pp_#} z$^fXsPzwOwhXR21bdz^y*9?co`}5B{n`wp`4NmhNXbGR(7orJ{E^qj7@rCa{f6<9r z!GXb`7$B$*J;XEPs2Z=g5143-(i|HNb5g@wsbC9EPy(R-u*&S?M|`~bMki|Bwr1WK zxPmnftaMxGy)geY*q(pVLX+t_6e002ovPDHLk FV1hey(dPgF literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/methdef_obj.png b/services/src/main/resources/images/methdef_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..a4131b9ba8d0d96217e1ec6431866c65731b4164 GIT binary patch literal 290 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}LV!<*Ye?fZ$MW?-ZM%ZocFCnI zR!(1HS-!!tVuL`;9HF?mqVe;@66Q-LFOW%DB$K*GCS{>a>O#5H#Y!1V)v}kX=PdvK z|3AKg)5dlFr(S+0_F(<)<#B^a7u?G*I3qN@3DD)tSg(+^)f6PgAm3`|aF8lI5V z`Q#h((KqI6S;GlQt>=@wPdeM2bhkTcXZ3AT-}8iouQfGqo16dt{}0qnBxqc5wh^dQ zs3gcQ7^o2yFg)77UkE76nB?v5BG1YzuouYTEbxdd2GSm2>~=ES4#=?gba4!kxV-h8 zB^QGN59`Gp$8_D^*GCF=^G|CE-j|gTchP=@y2Hd+Mw7tMOor2jF54K)tu7ic%rBRl d;Mc#LyWk0b^C1bIr$D0^JYD@<);T3K0RXKNUHSk3 literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/methpro_obj.png b/services/src/main/resources/images/methpro_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..3e4c0d7853c1b6980cde9e8f8a46770b3192959e GIT binary patch literal 299 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}LV!<*>;F$1{=b~~|JB6plU4W4 z(bzphefLcD|IcQuYnR{LtF)7B|(0{K=l}aLHlOyE1&|#ByV>Yc~)M5y+96Ufk$L9koEv$x0Bg+ zK!&rYi(`ny<+P^f#mw3`gjI0jEwKbLh*2~7awsAp~f literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/methpub_obj.png b/services/src/main/resources/images/methpub_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..30041952863fbb9fbbe0e9cc3e9e1c3dfd9b7aad GIT binary patch literal 325 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}LV!<*D|3SfYon)ZPnh1+1m`(9 zzKe@f*0mOH>&@TTRl0qG{qzL;8S!4TQ^S@Q#IGtzT2)ZEv8-@oY0LhWroBxq`&yc| z)_3e|?AX!RxubE$u?f@ncC0=>bM^TdTQ1H0|NlSGlKe^g{{boak|4iepa>qoa8|Mm z+hKJO$xC^VF0*z1|%O$WD@{VjKx9jP7LeL$-D%KdAc};NL=o{ zVCZ!?fT7``{VW%4R%ed@V-F4$Q>BvfD;v#UTJC8T7byJ5)TigyC9zd$eRt5On%bqA z9GoWa(mu}L|I(a6%=PBJ`nrj}EIY6KnCC3jt`c}4ul~3JQ25?m`{dl)Ee{#@J)h*= zDsbN<^z6--oW~AdcDKIF`trk!{i*%>Z!BxiO#9_ix|2W_tJ9zA&_t zFTHT|s_D)vGxj}Cm^$n9?b&=m_FVUi4K7=xESvsCXM6LuRjTcUC)|WsO+tG`g2S@< q_U=qu`pm;{>B_808V7!yUmkDyGWkzxi)$UwuMD29elF{r5}E)=Ieaky literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/package_obj.png b/services/src/main/resources/images/package_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..922c43547b5bc0641964422a5f86e0258586feef GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!cYsfb>;M1%-(Fny^yI?*O@>FC zjc)Iscd$zL`py~qOSKM`YhT|neS5CP?n13|tGibwC{GTRUze=9G)8Gbq~fATrQ-{l z3T?#a6+~3}JN*2(JJxJ!0?=5-k|4ie28U-i(tw;SPZ!6Kid((?H@O-VL|8B96nox& z_xAsO6MptZa!uzBD=_!nFxg*jb1pZ2dgHXDS8IHkd_)%8_KGJg>9{t-vB5)dl6)B} z)9*-^kgZ0a*EY>#Y7Kv8Z56CjUb67U1>uCn1=+D|caF!$?Pll?XYGqRVQB%hmBG{1 K&t;ucLK6Vs-e~#& literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/plus.png b/services/src/main/resources/images/plus.png new file mode 100644 index 0000000000000000000000000000000000000000..744f799aed376a400f0ecdf4de7f947ecb180903 GIT binary patch literal 311 zcmV-70m%M|P)Px#@kvBMR2b8Z(7j5-Pyog8e?sqVu1NF2&7e~dqNE7j9CXt~aBy+)0bG0z-@+FV zaq$HleF7nnK*&^w#F(@t28Gr^8*uYXzv;j^20*iDS4lP{PIHQ~#@7x}7_hsujlH>H z7|o(xJw3l5EJ+Y-;cJhgtjP0MzPeA25BD*XY>KcX(PWIWU5*Y;QMOAo86zx7l1(w= zG)H=xs#{WZOMu?e)5K}cpeSqPp5prCjCC%5eRFqDQPvE6?I7Bk+s6k0uFfxdS8o-* zb}*wbVA#!30+je^T6@^diNb(C>(pq3>)X5+4Ii^vzs~s2Pv7keYSR=uYF+>U002ov JPDHLkV1kuZg>nD@ literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/static_ovr.png b/services/src/main/resources/images/static_ovr.png new file mode 100644 index 0000000000000000000000000000000000000000..3c721da2fda6f19318db3cbdfdbc2f2de1572fbc GIT binary patch literal 129 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)H!VDyjYyB_iZVbAgZ z|Nrx-RjLA|7)yfuf*Bm1-ADs+6g*uVLpZJ{Cm4#9B_s$IvIy!qFr6taZ0XeGvNUL5 ZV2BE3k$>!%c@LMpq?ebR?AS3d>y^mfRJVSQlQr zHMMF*OykMOiY@Ox{Rn73m)Ni}uWLigoZTz-TwA#Lba8F>zH^VSJ^pg<`R7Nkzk4}}eA1?#rAHd3Z$5MT?WG5wEs-{P@kc*B^hl^;|r5{pIVA-`{=y@$u`=&)fZ`nuDnAHH(f{k&=6n$wS87w)@Sz4t=@p$kqM&SdR4 zley(s|FO%{_8(6;d@=RVx#XRPW-eMBeffItsncg4J=$^b;P;xxaDObhUFk@_#>^@aOsBja`Zx zfT&yX_uc0AFK_<+^XvJ=wST_9|NQjgkEd5l{C$7^{Q3X?e}+*&#}H8b$->CM(8{0# zvJ;di7&tC7aEopVUcTU=z@ zHa-Q`Dvidb_Nh`vUKI?HjZNK>=6~)~6f`-pb_?rGsYpERHBrr@M~8Dm08@vcS_+5d zqNV%_dI4-2JsTFWa`O7D_~WR&qI-%w1B+LOA`^4BW*XC6&CgFyu`x2KzX;f<)FPyx za;(Kud08W4qv)!Jj}w(UCaXt3*pRq^p~Fe0_}-S2lTtkT9a&^V0yb|r+%A&UaiF1q Yp^?c-Q`Bwa1P1PxH+FEdvM^W!08Y(!=>Px# literal 0 HcmV?d00001 diff --git a/services/src/main/resources/images/xml_obj.gif b/services/src/main/resources/images/xml_obj.gif new file mode 100644 index 0000000000000000000000000000000000000000..4083e21e64b30efdb50ff05fd8fdaa670cc13c69 GIT binary patch literal 357 zcmV-r0h<0tNk%w1VGsZi0M!5h`1$G-OdC_vGyM?D6-3n6iPGvC!Y}(&6&a;PKJm@Y3P& z)#LNg-|pAt^w{O}*W~lr=Jes~_T%jK>+$%;*Xir=_wMuf@%8!h_WAVo`1knvn5ntZ z-|W)h?7hs`@%8xg_W0J}=hxxqxWU2q`T64K-s9)r{{8Rp?bh(@*6!=r_VCjF`QrBP z(){hY{qxWK^3S@LCeFBT`{9uM=cBQTA+U-eu!|x4-Glx7`uh6%-sJ6hN%*(`0004W zQchC35CLX>Q7Jur z9Vsz>W{3cjqJ|ikgt(ZRA`?`Ft{{iHrihBNE>s1JxxAu)f{>EDIn)d`8#`+=RZ}Z_ z8>lV9CZ29i&W BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/services/src/main/resources/rsyntaxtextarea/themes/eclipse.xml b/services/src/main/resources/rsyntaxtextarea/themes/eclipse.xml new file mode 100644 index 00000000..200d7a19 --- /dev/null +++ b/services/src/main/resources/rsyntaxtextarea/themes/eclipse.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +