mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-24 22:00:55 +00:00
Initial version based on previous work. (Version alpha 7)
This commit is contained in:
Generated
+24
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<option name="DEFAULT_COMPILER" value="Javac" />
|
||||
<resourceExtensions>
|
||||
<entry name=".+\.(properties|xml|html|dtd|tld)" />
|
||||
<entry name=".+\.(gif|png|jpeg|jpg)" />
|
||||
</resourceExtensions>
|
||||
<wildcardResourcePatterns>
|
||||
<entry name="?*.properties" />
|
||||
<entry name="?*.xml" />
|
||||
<entry name="?*.gif" />
|
||||
<entry name="?*.png" />
|
||||
<entry name="?*.jpeg" />
|
||||
<entry name="?*.jpg" />
|
||||
<entry name="?*.html" />
|
||||
<entry name="?*.dtd" />
|
||||
<entry name="?*.tld" />
|
||||
<entry name="?*.ftl" />
|
||||
</wildcardResourcePatterns>
|
||||
<annotationProcessing enabled="false" useClasspath="true" />
|
||||
</component>
|
||||
</project>
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<component name="CopyrightManager">
|
||||
<settings default="">
|
||||
<module2copyright />
|
||||
</settings>
|
||||
</component>
|
||||
Generated
+5
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
|
||||
</project>
|
||||
|
||||
Generated
+11
@@ -0,0 +1,11 @@
|
||||
<component name="libraryTable">
|
||||
<library name="lib1">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/commons-codec-1.3.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/lib/jsyntaxpane-0.9.5.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/lib/jpproxy.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
Generated
+11
@@ -0,0 +1,11 @@
|
||||
<component name="libraryTable">
|
||||
<library name="testlib">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/testlib/junit-4.8.2.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/testlib/emma_ant.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/testlib/emma.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
Generated
+30
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DependencyValidationManager">
|
||||
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
|
||||
</component>
|
||||
<component name="JavadocGenerationManager">
|
||||
<option name="OUTPUT_DIRECTORY" />
|
||||
<option name="OPTION_SCOPE" value="protected" />
|
||||
<option name="OPTION_HIERARCHY" value="true" />
|
||||
<option name="OPTION_NAVIGATOR" value="true" />
|
||||
<option name="OPTION_INDEX" value="true" />
|
||||
<option name="OPTION_SEPARATE_INDEX" value="true" />
|
||||
<option name="OPTION_DOCUMENT_TAG_USE" value="false" />
|
||||
<option name="OPTION_DOCUMENT_TAG_AUTHOR" value="false" />
|
||||
<option name="OPTION_DOCUMENT_TAG_VERSION" value="false" />
|
||||
<option name="OPTION_DOCUMENT_TAG_DEPRECATED" value="true" />
|
||||
<option name="OPTION_DEPRECATED_LIST" value="true" />
|
||||
<option name="OTHER_OPTIONS" value="" />
|
||||
<option name="HEAP_SIZE" />
|
||||
<option name="LOCALE" />
|
||||
<option name="OPEN_IN_BROWSER" value="true" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_5" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
<component name="SvnBranchConfigurationManager">
|
||||
<option name="mySupportsUserInfoFilter" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
|
||||
Generated
+9
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/Trunk.iml" filepath="$PROJECT_DIR$/Trunk.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
|
||||
Generated
+125
@@ -0,0 +1,125 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Palette2">
|
||||
<group name="Swing">
|
||||
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||
</item>
|
||||
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||
<initial-values>
|
||||
<property name="text" value="Button" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="RadioButton" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="CheckBox" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="Label" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||
<preferred-size width="-1" height="20" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||
</item>
|
||||
</group>
|
||||
</component>
|
||||
</project>
|
||||
|
||||
Generated
+7
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="hg4idea" />
|
||||
</component>
|
||||
</project>
|
||||
|
||||
Generated
+379
@@ -0,0 +1,379 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" readonly="true" id="2a5649cc-c63c-4e40-abcf-b08a0b6d3714" name="Default" comment="" />
|
||||
<ignored path=".idea/workspace.xml" />
|
||||
<ignored path="trunk.iws" />
|
||||
<option name="TRACKING_ENABLED" value="true" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="ChangesViewManager" flattened_view="true" show_ignored="false" />
|
||||
<component name="CreatePatchCommitExecutor">
|
||||
<option name="PATCH_PATH" value="" />
|
||||
<option name="REVERSE_PATCH" value="false" />
|
||||
</component>
|
||||
<component name="DaemonCodeAnalyzer">
|
||||
<disable_hints />
|
||||
</component>
|
||||
<component name="DebuggerManager">
|
||||
<breakpoint_any>
|
||||
<breakpoint>
|
||||
<option name="NOTIFY_CAUGHT" value="true" />
|
||||
<option name="NOTIFY_UNCAUGHT" value="true" />
|
||||
<option name="ENABLED" value="false" />
|
||||
<option name="LOG_ENABLED" value="false" />
|
||||
<option name="LOG_EXPRESSION_ENABLED" value="false" />
|
||||
<option name="SUSPEND_POLICY" value="SuspendAll" />
|
||||
<option name="COUNT_FILTER_ENABLED" value="false" />
|
||||
<option name="COUNT_FILTER" value="0" />
|
||||
<option name="CONDITION_ENABLED" value="false" />
|
||||
<option name="CLASS_FILTERS_ENABLED" value="false" />
|
||||
<option name="INSTANCE_FILTERS_ENABLED" value="false" />
|
||||
<option name="CONDITION" value="" />
|
||||
<option name="LOG_MESSAGE" value="" />
|
||||
</breakpoint>
|
||||
<breakpoint>
|
||||
<option name="NOTIFY_CAUGHT" value="true" />
|
||||
<option name="NOTIFY_UNCAUGHT" value="true" />
|
||||
<option name="ENABLED" value="false" />
|
||||
<option name="LOG_ENABLED" value="false" />
|
||||
<option name="LOG_EXPRESSION_ENABLED" value="false" />
|
||||
<option name="SUSPEND_POLICY" value="SuspendAll" />
|
||||
<option name="COUNT_FILTER_ENABLED" value="false" />
|
||||
<option name="COUNT_FILTER" value="0" />
|
||||
<option name="CONDITION_ENABLED" value="false" />
|
||||
<option name="CLASS_FILTERS_ENABLED" value="false" />
|
||||
<option name="INSTANCE_FILTERS_ENABLED" value="false" />
|
||||
<option name="CONDITION" value="" />
|
||||
<option name="LOG_MESSAGE" value="" />
|
||||
</breakpoint>
|
||||
</breakpoint_any>
|
||||
<breakpoint_rules />
|
||||
<ui_properties />
|
||||
</component>
|
||||
<component name="FavoritesManager">
|
||||
<favorites_list name="trunk" />
|
||||
</component>
|
||||
<component name="FindManager">
|
||||
<FindUsagesManager>
|
||||
<setting name="OPEN_NEW_TAB" value="false" />
|
||||
</FindUsagesManager>
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="GIT_EXECUTABLE" value="git.exe" />
|
||||
<option name="CHECKOUT_INCLUDE_TAGS" value="false" />
|
||||
</component>
|
||||
<component name="ModuleEditorState">
|
||||
<option name="LAST_EDITED_MODULE_NAME" />
|
||||
<option name="LAST_EDITED_TAB_NAME" />
|
||||
</component>
|
||||
<component name="ProjectInspectionProfilesVisibleTreeState">
|
||||
<entry key="Project Default">
|
||||
<profile-state />
|
||||
</entry>
|
||||
</component>
|
||||
<component name="ProjectLevelVcsManager">
|
||||
<OptionsSetting value="true" id="Add" />
|
||||
<OptionsSetting value="true" id="Remove" />
|
||||
<OptionsSetting value="true" id="Checkout" />
|
||||
<OptionsSetting value="true" id="Update" />
|
||||
<OptionsSetting value="true" id="Status" />
|
||||
<OptionsSetting value="true" id="Edit" />
|
||||
<ConfirmationsSetting value="2" id="Add" />
|
||||
<ConfirmationsSetting value="0" id="Remove" />
|
||||
</component>
|
||||
<component name="ProjectReloadState">
|
||||
<option name="STATE" value="0" />
|
||||
</component>
|
||||
<component name="ProjectView">
|
||||
<navigator currentView="ProjectPane" proportions="" version="1" splitterProportion="0.5">
|
||||
<flattenPackages />
|
||||
<showMembers />
|
||||
<showModules />
|
||||
<showLibraryContents />
|
||||
<hideEmptyPackages />
|
||||
<abbreviatePackageNames />
|
||||
<autoscrollToSource />
|
||||
<autoscrollFromSource />
|
||||
<sortByType />
|
||||
</navigator>
|
||||
<panes>
|
||||
<pane id="Favorites" />
|
||||
<pane id="Scope" />
|
||||
<pane id="PackagesPane" />
|
||||
<pane id="ProjectPane">
|
||||
<subPane>
|
||||
<PATH>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="trunk" />
|
||||
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||
</PATH_ELEMENT>
|
||||
</PATH>
|
||||
<PATH>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="trunk" />
|
||||
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||
</PATH_ELEMENT>
|
||||
<PATH_ELEMENT>
|
||||
<option name="myItemId" value="trunk" />
|
||||
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
|
||||
</PATH_ELEMENT>
|
||||
</PATH>
|
||||
</subPane>
|
||||
</pane>
|
||||
</panes>
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="project.structure.last.edited" value="Project" />
|
||||
<property name="GoToFile.includeJavaFiles" value="false" />
|
||||
<property name="project.structure.proportion" value="0.0" />
|
||||
<property name="options.splitter.main.proportions" value="0.3" />
|
||||
<property name="MemberChooser.sorted" value="false" />
|
||||
<property name="options.lastSelected" value="preferences.pluginManager" />
|
||||
<property name="project.structure.side.proportion" value="0.2" />
|
||||
<property name="MemberChooser.copyJavadoc" value="false" />
|
||||
<property name="GoToClass.toSaveIncludeLibraries" value="false" />
|
||||
<property name="MemberChooser.showClasses" value="true" />
|
||||
<property name="GoToClass.includeLibraries" value="false" />
|
||||
<property name="options.splitter.details.proportions" value="0.2" />
|
||||
<property name="options.searchVisible" value="true" />
|
||||
</component>
|
||||
<component name="RunManager">
|
||||
<configuration default="true" type="Remote" factoryName="Remote">
|
||||
<option name="USE_SOCKET_TRANSPORT" value="true" />
|
||||
<option name="SERVER_MODE" value="false" />
|
||||
<option name="SHMEM_ADDRESS" value="javadebug" />
|
||||
<option name="HOST" value="localhost" />
|
||||
<option name="PORT" value="5005" />
|
||||
<method>
|
||||
<option name="AntTarget" enabled="false" />
|
||||
<option name="BuildArtifacts" enabled="false" />
|
||||
<option name="Maven.BeforeRunTask" enabled="false" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration default="true" type="TestNG" factoryName="TestNG">
|
||||
<extension name="snapshooter" />
|
||||
<module name="" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
<option name="SUITE_NAME" />
|
||||
<option name="PACKAGE_NAME" />
|
||||
<option name="MAIN_CLASS_NAME" />
|
||||
<option name="METHOD_NAME" />
|
||||
<option name="GROUP_NAME" />
|
||||
<option name="TEST_OBJECT" value="CLASS" />
|
||||
<option name="VM_PARAMETERS" />
|
||||
<option name="PARAMETERS" />
|
||||
<option name="WORKING_DIRECTORY" />
|
||||
<option name="OUTPUT_DIRECTORY" />
|
||||
<option name="ANNOTATION_TYPE" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<option name="TEST_SEARCH_SCOPE">
|
||||
<value defaultName="moduleWithDependencies" />
|
||||
</option>
|
||||
<option name="USE_DEFAULT_REPORTERS" value="false" />
|
||||
<option name="PROPERTIES_FILE" />
|
||||
<envs />
|
||||
<properties />
|
||||
<listeners />
|
||||
<method>
|
||||
<option name="AntTarget" enabled="false" />
|
||||
<option name="BuildArtifacts" enabled="false" />
|
||||
<option name="Make" enabled="true" />
|
||||
<option name="Maven.BeforeRunTask" enabled="false" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration default="true" type="Applet" factoryName="Applet">
|
||||
<module name="" />
|
||||
<option name="MAIN_CLASS_NAME" />
|
||||
<option name="HTML_FILE_NAME" />
|
||||
<option name="HTML_USED" value="false" />
|
||||
<option name="WIDTH" value="400" />
|
||||
<option name="HEIGHT" value="300" />
|
||||
<option name="POLICY_FILE" value="$APPLICATION_HOME_DIR$/bin/appletviewer.policy" />
|
||||
<option name="VM_PARAMETERS" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
<method>
|
||||
<option name="AntTarget" enabled="false" />
|
||||
<option name="BuildArtifacts" enabled="false" />
|
||||
<option name="Make" enabled="true" />
|
||||
<option name="Maven.BeforeRunTask" enabled="false" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration default="true" type="Application" factoryName="Application">
|
||||
<extension name="snapshooter" />
|
||||
<option name="MAIN_CLASS_NAME" />
|
||||
<option name="VM_PARAMETERS" />
|
||||
<option name="PROGRAM_PARAMETERS" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
<option name="ENABLE_SWING_INSPECTOR" value="false" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<module name="" />
|
||||
<envs />
|
||||
<method>
|
||||
<option name="AntTarget" enabled="false" />
|
||||
<option name="BuildArtifacts" enabled="false" />
|
||||
<option name="Make" enabled="true" />
|
||||
<option name="Maven.BeforeRunTask" enabled="false" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration default="true" type="JUnit" factoryName="JUnit">
|
||||
<extension name="snapshooter" />
|
||||
<module name="" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
<option name="PACKAGE_NAME" />
|
||||
<option name="MAIN_CLASS_NAME" />
|
||||
<option name="METHOD_NAME" />
|
||||
<option name="TEST_OBJECT" value="class" />
|
||||
<option name="VM_PARAMETERS" />
|
||||
<option name="PARAMETERS" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<option name="TEST_SEARCH_SCOPE">
|
||||
<value defaultName="moduleWithDependencies" />
|
||||
</option>
|
||||
<envs />
|
||||
<method>
|
||||
<option name="AntTarget" enabled="false" />
|
||||
<option name="BuildArtifacts" enabled="false" />
|
||||
<option name="Make" enabled="true" />
|
||||
<option name="Maven.BeforeRunTask" enabled="false" />
|
||||
</method>
|
||||
</configuration>
|
||||
<list size="0" />
|
||||
<configuration name="<template>" type="WebApp" default="true" selected="false">
|
||||
<Host>localhost</Host>
|
||||
<Port>5050</Port>
|
||||
</configuration>
|
||||
</component>
|
||||
<component name="ShelveChangesManager" show_recycled="false" />
|
||||
<component name="SvnConfiguration" maxAnnotateRevisions="500">
|
||||
<option name="USER" value="" />
|
||||
<option name="PASSWORD" value="" />
|
||||
<option name="LAST_MERGED_REVISION" />
|
||||
<option name="UPDATE_RUN_STATUS" value="false" />
|
||||
<option name="MERGE_DRY_RUN" value="false" />
|
||||
<option name="MERGE_DIFF_USE_ANCESTRY" value="true" />
|
||||
<option name="UPDATE_LOCK_ON_DEMAND" value="false" />
|
||||
<option name="IGNORE_SPACES_IN_MERGE" value="false" />
|
||||
<option name="DETECT_NESTED_COPIES" value="false" />
|
||||
<option name="CHECK_NESTED_FOR_QUICK_MERGE" value="false" />
|
||||
<option name="IGNORE_SPACES_IN_ANNOTATE" value="true" />
|
||||
<option name="SHOW_MERGE_SOURCES_IN_ANNOTATE" value="true" />
|
||||
<configuration useDefault="true">C:\Users\JPEXS\AppData\Roaming\Subversion</configuration>
|
||||
<myIsUseDefaultProxy>false</myIsUseDefaultProxy>
|
||||
<supportedVersion>125</supportedVersion>
|
||||
</component>
|
||||
<component name="ToolWindowManager">
|
||||
<frame x="-8" y="-8" width="1382" height="744" extended-state="6" />
|
||||
<editor active="false" />
|
||||
<layout>
|
||||
<window_info id="Changes" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Palette" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32876712" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="true" content_ui="tabs" />
|
||||
<window_info id="Maven Projects" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.33282673" sideWeight="0.65924656" order="0" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Dependency Viewer" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
|
||||
</layout>
|
||||
</component>
|
||||
<component name="VcsManagerConfiguration">
|
||||
<option name="OFFER_MOVE_TO_ANOTHER_CHANGELIST_ON_PARTIAL_COMMIT" value="true" />
|
||||
<option name="CHECK_CODE_SMELLS_BEFORE_PROJECT_COMMIT" value="true" />
|
||||
<option name="PERFORM_UPDATE_IN_BACKGROUND" value="true" />
|
||||
<option name="PERFORM_COMMIT_IN_BACKGROUND" value="true" />
|
||||
<option name="PERFORM_EDIT_IN_BACKGROUND" value="true" />
|
||||
<option name="PERFORM_CHECKOUT_IN_BACKGROUND" value="true" />
|
||||
<option name="PERFORM_ADD_REMOVE_IN_BACKGROUND" value="true" />
|
||||
<option name="PERFORM_ROLLBACK_IN_BACKGROUND" value="false" />
|
||||
<option name="CHECK_LOCALLY_CHANGED_CONFLICTS_IN_BACKGROUND" value="true" />
|
||||
<option name="ENABLE_BACKGROUND_PROCESSES" value="false" />
|
||||
<option name="CHANGED_ON_SERVER_INTERVAL" value="60" />
|
||||
<option name="FORCE_NON_EMPTY_COMMENT" value="false" />
|
||||
<option name="LAST_COMMIT_MESSAGE" />
|
||||
<option name="MAKE_NEW_CHANGELIST_ACTIVE" value="true" />
|
||||
<option name="OPTIMIZE_IMPORTS_BEFORE_PROJECT_COMMIT" value="false" />
|
||||
<option name="CHECK_FILES_UP_TO_DATE_BEFORE_COMMIT" value="false" />
|
||||
<option name="REFORMAT_BEFORE_PROJECT_COMMIT" value="false" />
|
||||
<option name="REFORMAT_BEFORE_FILE_COMMIT" value="false" />
|
||||
<option name="FILE_HISTORY_DIALOG_COMMENTS_SPLITTER_PROPORTION" value="0.8" />
|
||||
<option name="FILE_HISTORY_DIALOG_SPLITTER_PROPORTION" value="0.5" />
|
||||
<option name="ACTIVE_VCS_NAME" />
|
||||
<option name="UPDATE_GROUP_BY_PACKAGES" value="false" />
|
||||
<option name="UPDATE_GROUP_BY_CHANGELIST" value="false" />
|
||||
<option name="SHOW_FILE_HISTORY_AS_TREE" value="false" />
|
||||
<option name="FILE_HISTORY_SPLITTER_PROPORTION" value="0.6" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager />
|
||||
</component>
|
||||
<component name="masterDetails">
|
||||
<states>
|
||||
<state key="ArtifactsStructureConfigurable.UI">
|
||||
<UIState>
|
||||
<splitter-proportions>
|
||||
<SplitterProportionsDataImpl>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</SplitterProportionsDataImpl>
|
||||
</splitter-proportions>
|
||||
<settings />
|
||||
</UIState>
|
||||
</state>
|
||||
<state key="Copyright.UI">
|
||||
<UIState>
|
||||
<splitter-proportions>
|
||||
<SplitterProportionsDataImpl />
|
||||
</splitter-proportions>
|
||||
</UIState>
|
||||
</state>
|
||||
<state key="ProjectJDKs.UI">
|
||||
<UIState>
|
||||
<splitter-proportions>
|
||||
<SplitterProportionsDataImpl>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</SplitterProportionsDataImpl>
|
||||
</splitter-proportions>
|
||||
<last-edited>1.6</last-edited>
|
||||
</UIState>
|
||||
</state>
|
||||
<state key="ScopeChooserConfigurable.UI">
|
||||
<UIState>
|
||||
<splitter-proportions>
|
||||
<SplitterProportionsDataImpl />
|
||||
</splitter-proportions>
|
||||
<settings />
|
||||
</UIState>
|
||||
</state>
|
||||
</states>
|
||||
</component>
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="testlib" level="project" />
|
||||
<orderEntry type="library" name="lib1" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project name="ASDec" default="build" basedir=".">
|
||||
<description>Builds project ASDec.</description>
|
||||
|
||||
|
||||
<import file="buildconfig.xml"/>
|
||||
<property name="DISTLIBRARIESFULLDIR" value="${DISTRIBUTIONDIR}/${DISTLIBRARIESDIR}"/>
|
||||
<property name="JAVADOCFULLDIR" value="${DISTRIBUTIONDIR}/${JAVADOCDIR}"/>
|
||||
<patternset id="compiler.resources">
|
||||
<include name="**/?*.properties"/>
|
||||
<include name="**/?*.bin"/>
|
||||
<include name="**/?*.xml"/>
|
||||
<include name="**/?*.txt"/>
|
||||
<include name="**/?*.gif"/>
|
||||
<include name="**/?*.png"/>
|
||||
<include name="**/?*.jpeg"/>
|
||||
<include name="**/?*.jpg"/>
|
||||
<include name="**/?*.html"/>
|
||||
<include name="**/?*.dtd"/>
|
||||
<include name="**/?*.tld"/>
|
||||
<include name="**/?*.mid"/>
|
||||
<include name="**/?*.wav"/>
|
||||
</patternset>
|
||||
|
||||
<path id="emma.lib">
|
||||
<pathelement location="${TESTLIBDIR}/emma.jar"/>
|
||||
<pathelement location="${TESTLIBDIR}/emma_ant.jar"/>
|
||||
</path>
|
||||
<taskdef resource="emma_ant.properties" classpathref="emma.lib"/>
|
||||
|
||||
<target name="coverage.instrumentation">
|
||||
<mkdir dir="${INSTRDIR}"/>
|
||||
<mkdir dir="${COVERAGEDIR}"/>
|
||||
<emma>
|
||||
<instr instrpath="${COMPILEDIR}" destdir="${INSTRDIR}" metadatafile="${COVERAGEDIR}/metadata.emma"
|
||||
mode="copy"></instr>
|
||||
</emma>
|
||||
<copy todir="${INSTRDIR}">
|
||||
<fileset dir="${SOURCEDIR}">
|
||||
<patternset refid="compiler.resources"/>
|
||||
<type type="file"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<target name="compile">
|
||||
<delete dir="${COMPILEDIR}"/>
|
||||
<mkdir dir="${COMPILEDIR}"/>
|
||||
<javac srcdir="${SOURCEDIR}" destdir="${COMPILEDIR}" includes="**/*.java" target="1.6" debug="true"
|
||||
debuglevel="lines,vars,source">
|
||||
<classpath>
|
||||
<fileset dir="${LIBRARIESDIR}" includes="**/*.jar"/>
|
||||
</classpath>
|
||||
</javac>
|
||||
<copy todir="${COMPILEDIR}">
|
||||
<fileset dir="${SOURCEDIR}">
|
||||
<patternset refid="compiler.resources"/>
|
||||
<type type="file"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<target name="test" depends="clean,compile">
|
||||
<delete dir="${TESTRESULTSDIR}"/>
|
||||
<mkdir dir="${TESTRESULTSDIR}"/>
|
||||
<mkdir dir="${TESTRESULTSDIR}/raw/"/>
|
||||
<delete dir="${COMPILETESTSDIR}"/>
|
||||
<mkdir dir="${COMPILETESTSDIR}"/>
|
||||
<javac srcdir="${TESTDIR}" destdir="${COMPILETESTSDIR}" includes="**/*.java" target="1.6">
|
||||
<classpath>
|
||||
<pathelement path="${COMPILEDIR}"/>
|
||||
<fileset dir="${LIBRARIESDIR}" includes="**/*.jar"/>
|
||||
<fileset dir="${TESTLIBDIR}" includes="**/*.jar"/>
|
||||
</classpath>
|
||||
</javac>
|
||||
<antcall target="coverage.instrumentation"/>
|
||||
<junit printsummary="yes" haltonfailure="yes" showoutput="yes">
|
||||
<classpath>
|
||||
<pathelement path="${INSTRDIR}"/>
|
||||
<pathelement path="${COMPILEDIR}"/>
|
||||
<pathelement path="${COMPILETESTSDIR}"/>
|
||||
<fileset dir="${LIBRARIESDIR}" includes="**/*.jar"/>
|
||||
<fileset dir="${TESTLIBDIR}" includes="**/*.jar"/>
|
||||
</classpath>
|
||||
<jvmarg value="-Demma.coverage.out.file=${COVERAGEDIR}/coverage.emma"/>
|
||||
<jvmarg value="-Demma.coverage.out.merge=true"/>
|
||||
<batchtest fork="yes" todir="${TESTRESULTSDIR}/raw/">
|
||||
<formatter type="xml"/>
|
||||
<fileset dir="${TESTDIR}">
|
||||
<include name="**/*.java"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</junit>
|
||||
<!-- JUnit report -->
|
||||
<junitreport todir="${TESTRESULTSDIR}">
|
||||
<fileset dir="${TESTRESULTSDIR}/raw/">
|
||||
<include name="TEST-*.xml"/>
|
||||
</fileset>
|
||||
<report format="frames" todir="${TESTRESULTSDIR}\html\"/>
|
||||
</junitreport>
|
||||
<!-- Coverage report -->
|
||||
<mkdir dir="${COVERAGERESULTSDIR}"/>
|
||||
<emma>
|
||||
<report sourcepath="${SOURCEDIR}" depth="method">
|
||||
<fileset dir="${COVERAGEDIR}">
|
||||
<include name="*.emma"/>
|
||||
</fileset>
|
||||
<html outfile="${COVERAGERESULTSDIR}/index.html"/>
|
||||
</report>
|
||||
</emma>
|
||||
</target>
|
||||
<target name="build" depends="clean,compile">
|
||||
<mkdir dir="${DISTRIBUTIONDIR}"/>
|
||||
<delete dir="${DISTLIBRARIESFULLDIR}"/>
|
||||
<mkdir dir="${DISTLIBRARIESFULLDIR}"/>
|
||||
<copy todir="${DISTLIBRARIESFULLDIR}">
|
||||
<fileset dir="${LIBRARIESDIR}" includes="**/*.jar"/>
|
||||
</copy>
|
||||
<pathconvert pathsep=" " property="manifestClassPath">
|
||||
<fileset dir="${DISTRIBUTIONDIR}" includes="${DISTLIBRARIESDIR}/**/*.*"/>
|
||||
<chainedmapper>
|
||||
<flattenmapper/>
|
||||
<globmapper from="*" to="${DISTLIBRARIESDIR}/*"/>
|
||||
</chainedmapper>
|
||||
</pathconvert>
|
||||
|
||||
<jar destfile="${DISTRIBUTIONDIR}/${JARFILENAME}.jar" basedir="${COMPILEDIR}">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="${MAINCLASS}"/>
|
||||
<attribute name="Class-Path" value="${manifestClassPath}"/>
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="run" depends="build">
|
||||
<java jar="${DISTRIBUTIONDIR}/${JARFILENAME}.jar" fork="true"/>
|
||||
</target>
|
||||
|
||||
|
||||
<target name="javadoc">
|
||||
<mkdir dir="${JAVADOCFULLDIR}"/>
|
||||
<javadoc sourcepath="${SOURCEDIR}" destdir="${JAVADOCFULLDIR}" windowtitle="${PROJECTNAME}"
|
||||
useexternalfile="yes">
|
||||
<fileset dir="${SOURCEDIR}" includes="**/*.java"/>
|
||||
<classpath>
|
||||
<fileset dir="${LIBRARIESDIR}" includes="**/*.jar"/>
|
||||
</classpath>
|
||||
</javadoc>
|
||||
</target>
|
||||
<target name="clean">
|
||||
<delete dir="${DISTRIBUTIONDIR}"/>
|
||||
<delete dir="${COMPILETESTSDIR}"/>
|
||||
<delete dir="${COMPILEDIR}"/>
|
||||
<delete dir="${COVERAGEDIR}"/>
|
||||
<delete dir="${TESTRESULTSDIR}"/>
|
||||
</target>
|
||||
</project>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project name="buildconfig" basedir=".">
|
||||
<property name="PROJECTNAME" value="ASDec"/>
|
||||
<property name="JARFILENAME" value="ASDec"/>
|
||||
|
||||
<property name="MAINCLASS" value="com.jpexs.asdec.Main"/>
|
||||
<property name="SOURCEDIR" value="src"/>
|
||||
<property name="TESTDIR" value="test"/>
|
||||
<property name="TESTLIBDIR" value="testlib"/>
|
||||
<property name="TESTRESULTSDIR" value="reports/tests"/>
|
||||
<property name="COVERAGERESULTSDIR" value="reports/coverage"/>
|
||||
<property name="DISTRIBUTIONDIR" value="dist"/>
|
||||
<property name="COMPILEDIR" value="build/classes"/>
|
||||
<property name="INSTRDIR" value="build/instr-classes"/>
|
||||
<property name="COVERAGEDIR" value="coverage"/>
|
||||
<property name="COMPILETESTSDIR" value="build/test"/>
|
||||
<property name="LIBRARIESDIR" value="lib"/>
|
||||
|
||||
<property name="DISTLIBRARIESDIR" value="lib"/>
|
||||
<property name="JAVADOCDIR" value="javadoc"/>
|
||||
|
||||
</project>
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,158 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="32px"
|
||||
height="32px"
|
||||
id="svg3747"
|
||||
version="1.1"
|
||||
inkscape:version="0.47 r22583"
|
||||
sodipodi:docname="exit.svg"
|
||||
inkscape:export-filename="D:\Dokumenty\Programovani\JavaSE\ASDec\trunk\src\com\jpexs\asdec\gui\graphics\exit.png"
|
||||
inkscape:export-xdpi="67.5"
|
||||
inkscape:export-ydpi="67.5">
|
||||
<defs
|
||||
id="defs3749">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4467">
|
||||
<stop
|
||||
style="stop-color:#800000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4469" />
|
||||
<stop
|
||||
style="stop-color:#800000;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop4471" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3759">
|
||||
<stop
|
||||
style="stop-color:#800000;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3761" />
|
||||
<stop
|
||||
id="stop4475"
|
||||
offset="0.37543982"
|
||||
style="stop-color:#ff0000;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-color:#ff8080;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3763" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 16 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="32 : 16 : 1"
|
||||
inkscape:persp3d-origin="16 : 10.666667 : 1"
|
||||
id="perspective3755" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3759"
|
||||
id="linearGradient3765"
|
||||
x1="22.329529"
|
||||
y1="30.178116"
|
||||
x2="5.0009823"
|
||||
y2="-3.0961745"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4467"
|
||||
id="linearGradient4473"
|
||||
x1="14.89753"
|
||||
y1="10.143032"
|
||||
x2="17.088352"
|
||||
y2="10.143032"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3759"
|
||||
id="linearGradient4487"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="22.329529"
|
||||
y1="30.178116"
|
||||
x2="5.0009823"
|
||||
y2="-3.0961745" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4467"
|
||||
id="linearGradient4489"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="14.89753"
|
||||
y1="10.143032"
|
||||
x2="17.088352"
|
||||
y2="10.143032" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="7.9180417"
|
||||
inkscape:cx="10.294595"
|
||||
inkscape:cy="14.189262"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="706"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata3752">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<g
|
||||
id="g4481"
|
||||
transform="matrix(1.2221431,0,0,1.2209925,-3.4418725,-2.5725064)">
|
||||
<path
|
||||
transform="translate(0.4465162,-1.875368)"
|
||||
d="m 28.041218,17.086359 c 0,6.954235 -5.637522,12.591757 -12.591757,12.591757 -6.9542353,0 -12.5917568,-5.637522 -12.5917568,-12.591757 0,-6.954235 5.6375215,-12.5917568 12.5917568,-12.5917568 6.954235,0 12.591757,5.6375218 12.591757,12.5917568 z"
|
||||
sodipodi:ry="12.591757"
|
||||
sodipodi:rx="12.591757"
|
||||
sodipodi:cy="17.086359"
|
||||
sodipodi:cx="15.449461"
|
||||
id="path3757"
|
||||
style="fill:url(#linearGradient4487);fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
sodipodi:type="arc" />
|
||||
<g
|
||||
id="g4477">
|
||||
<path
|
||||
style="fill:none;stroke:#ffffff;stroke-width:1.97675169;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:none"
|
||||
d="M 12.335984,9.4761523 C 3.8629521,11.527676 7.8865799,23.34708 16.151487,23.255321 24.416394,23.163562 27.25709,11.391233 19.470495,9.4825232"
|
||||
id="path3767"
|
||||
sodipodi:nodetypes="czs" />
|
||||
<path
|
||||
style="fill:url(#linearGradient4489);stroke:#ffffff;stroke-width:2.19082189;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
d="m 15.992941,13.908267 0,-7.5304694"
|
||||
id="path3773" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.2 KiB |
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 52 KiB |
@@ -0,0 +1,289 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="300"
|
||||
height="50"
|
||||
id="svg2"
|
||||
inkscape:label="Pozadí"
|
||||
version="1.1"
|
||||
inkscape:version="0.47 r22583"
|
||||
sodipodi:docname="logo.svg"
|
||||
inkscape:export-filename="D:\Dokumenty\Programovani\JavaSE\ASDec\trunk\src\com\jpexs\asdec\gui\graphics\logo.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
id="defs3">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3589">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3591" />
|
||||
<stop
|
||||
style="stop-color:#666666;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3593" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
id="perspective9" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3589"
|
||||
id="linearGradient3595"
|
||||
x1="150"
|
||||
y1="1052.3622"
|
||||
x2="150"
|
||||
y2="1002.3622"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<inkscape:perspective
|
||||
id="perspective3609"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3635"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3660"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3685"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<filter
|
||||
inkscape:collect="always"
|
||||
id="filter3706">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.83384766"
|
||||
id="feGaussianBlur3708" />
|
||||
</filter>
|
||||
<inkscape:perspective
|
||||
id="perspective3718"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<filter
|
||||
inkscape:collect="always"
|
||||
id="filter3747"
|
||||
x="-0.021163422"
|
||||
width="1.0423268"
|
||||
y="-0.12042073"
|
||||
height="1.2408415">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="1.157168"
|
||||
id="feGaussianBlur3749" />
|
||||
</filter>
|
||||
<filter
|
||||
inkscape:collect="always"
|
||||
id="filter3801"
|
||||
x="-0.021163422"
|
||||
width="1.0423268"
|
||||
y="-0.12042073"
|
||||
height="1.2408415">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="1.157168"
|
||||
id="feGaussianBlur3803" />
|
||||
</filter>
|
||||
<filter
|
||||
inkscape:collect="always"
|
||||
id="filter3823"
|
||||
x="-0.021163422"
|
||||
width="1.0423268"
|
||||
y="-0.12042073"
|
||||
height="1.2408415">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="1.157168"
|
||||
id="feGaussianBlur3825" />
|
||||
</filter>
|
||||
<inkscape:perspective
|
||||
id="perspective3835"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3860"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<filter
|
||||
inkscape:collect="always"
|
||||
id="filter3901">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.73429527"
|
||||
id="feGaussianBlur3903" />
|
||||
</filter>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.98994949"
|
||||
inkscape:cx="71.849745"
|
||||
inkscape:cy="-90.235669"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer2"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="706"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata6">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Vrstva 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1002.3622)"
|
||||
sodipodi:insensitive="true">
|
||||
<rect
|
||||
style="fill:url(#linearGradient3595);fill-opacity:1;stroke:none"
|
||||
id="rect2815"
|
||||
width="300"
|
||||
height="50"
|
||||
x="0"
|
||||
y="1002.3622" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="164.76456"
|
||||
y="1030.4779"
|
||||
id="text3597-1"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3599-7"
|
||||
x="164.76456"
|
||||
y="1030.4779"
|
||||
style="font-size:28px" /></text>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="text">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:46.96638107px;font-style:normal;font-weight:normal;fill:#676767;fill-opacity:1;stroke:none;filter:url(#filter3901);font-family:Bitstream Vera Sans"
|
||||
x="7.5546227"
|
||||
y="37.095638"
|
||||
id="text3597-2-5"
|
||||
transform="matrix(0.86402136,0,0,0.90956581,8.7270607,1.1366504)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3599-45-1"
|
||||
x="7.5546227"
|
||||
y="37.095638"
|
||||
style="font-size:28.17983055px;fill:#676767;fill-opacity:1;font-family:Verdana;-inkscape-font-specification:Verdana">JP</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;fill:#595959;fill-opacity:1;stroke:none;filter:url(#filter3706);font-family:Bitstream Vera Sans"
|
||||
x="6.3993211"
|
||||
y="36.770775"
|
||||
id="text3597-9"
|
||||
transform="matrix(0.83039113,0,0,0.96470084,38.866062,-1.4735742)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3599-4"
|
||||
x="6.3993211"
|
||||
y="36.770775"
|
||||
style="font-size:24px;fill:#595959;fill-opacity:1;font-family:Verdana;-inkscape-font-specification:Verdana">ActionScript</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:35.80120468px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="45.606098"
|
||||
y="29.900066"
|
||||
id="text3597"
|
||||
transform="scale(0.92778003,1.0778417)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3599"
|
||||
x="45.606098"
|
||||
y="29.900066"
|
||||
style="font-size:21.48072433px;font-family:Verdana;-inkscape-font-specification:Verdana">ActionScript</tspan></text>
|
||||
<g
|
||||
id="g3805"
|
||||
transform="matrix(0.83039113,0,0,0.96470084,38.866062,-1.4735742)">
|
||||
<text
|
||||
id="text3597-4-8"
|
||||
y="36.500076"
|
||||
x="159.39526"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;fill:#6c0000;fill-opacity:1;stroke:none;filter:url(#filter3823);font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;fill:#6c0000;fill-opacity:1;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="36.500076"
|
||||
x="159.39526"
|
||||
id="tspan3599-0-8"
|
||||
sodipodi:role="line">decompiler</tspan></text>
|
||||
<text
|
||||
id="text3597-4"
|
||||
y="34.750473"
|
||||
x="157.41711"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;fill:#ff0000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;fill:#ff0000;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="34.750473"
|
||||
x="157.41711"
|
||||
id="tspan3599-0"
|
||||
sodipodi:role="line">decompiler</tspan></text>
|
||||
</g>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:41.63574982px;font-style:normal;font-weight:normal;fill:#000080;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="13.621976"
|
||||
y="31.957207"
|
||||
id="text3597-2"
|
||||
transform="scale(0.97464215,1.0260176)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3599-45"
|
||||
x="13.621976"
|
||||
y="31.957207"
|
||||
style="font-size:24.98145103px;fill:#000080;font-family:Verdana;-inkscape-font-specification:Verdana">JP</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.7 KiB |
@@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="32"
|
||||
height="32"
|
||||
id="svg2"
|
||||
inkscape:label="Pozadí"
|
||||
version="1.1"
|
||||
inkscape:version="0.47 r22583"
|
||||
sodipodi:docname="open.svg"
|
||||
inkscape:export-filename="D:\Dokumenty\Programovani\JavaSE\ASDec\trunk\src\com\jpexs\asdec\gui\graphics\open.png"
|
||||
inkscape:export-xdpi="67.5"
|
||||
inkscape:export-ydpi="67.5">
|
||||
<defs
|
||||
id="defs3">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3601">
|
||||
<stop
|
||||
style="stop-color:#ffeeaa;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3603" />
|
||||
<stop
|
||||
style="stop-color:#a0892c;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3605" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient2821">
|
||||
<stop
|
||||
style="stop-color:#c8ab37;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop2823" />
|
||||
<stop
|
||||
style="stop-color:#ffeeaa;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop2825" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
id="perspective9" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2821"
|
||||
id="linearGradient2827"
|
||||
x1="17"
|
||||
y1="30.5"
|
||||
x2="17"
|
||||
y2="15.5"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3601"
|
||||
id="linearGradient3607"
|
||||
x1="13.257614"
|
||||
y1="1.5"
|
||||
x2="13.257614"
|
||||
y2="22.292511"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.2"
|
||||
inkscape:cx="18.374709"
|
||||
inkscape:cy="13.203513"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="706"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata6">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Vrstva 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1020.3622)">
|
||||
<path
|
||||
style="fill:url(#linearGradient3607);stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1;"
|
||||
d="M 1.6008877,2 1.5152287,30 25,30 25,6 10,6 10,2 1.6008877,2 z"
|
||||
id="path2815"
|
||||
transform="translate(0,1020.3622)"
|
||||
sodipodi:nodetypes="ccccccc" />
|
||||
<path
|
||||
style="fill:url(#linearGradient2827);stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1;"
|
||||
d="M 2,30 9,16 32,16 25,30 2,30 z"
|
||||
id="path2819"
|
||||
transform="translate(0,1020.3622)"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
@@ -0,0 +1,171 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="32px"
|
||||
height="32px"
|
||||
id="svg2822"
|
||||
version="1.1"
|
||||
inkscape:version="0.47 r22583"
|
||||
sodipodi:docname="proxy.svg"
|
||||
inkscape:export-filename="D:\Dokumenty\Programovani\JavaSE\ASDec\trunk\src\com\jpexs\asdec\gui\graphics\proxy48.png"
|
||||
inkscape:export-xdpi="135"
|
||||
inkscape:export-ydpi="135">
|
||||
<defs
|
||||
id="defs2824">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 16 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="32 : 16 : 1"
|
||||
inkscape:persp3d-origin="16 : 10.666667 : 1"
|
||||
id="perspective2830" />
|
||||
<inkscape:perspective
|
||||
id="perspective3620"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3680"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3712"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.3997253"
|
||||
inkscape:cx="42.166304"
|
||||
inkscape:cy="31.734779"
|
||||
inkscape:current-layer="g3736"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="706"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata2827">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Kabel"
|
||||
inkscape:groupmode="layer">
|
||||
<g
|
||||
id="g3666-5"
|
||||
transform="matrix(0.55104331,0,0,0.59178372,12.271228,-0.16251623)">
|
||||
<path
|
||||
sodipodi:nodetypes="csszzsszc"
|
||||
id="path2836-6"
|
||||
d="m 0.08930324,28.785083 c 0,0 3.66143306,-9.287537 10.98429876,-13.038273 7.322865,-3.750736 14.728383,-13.0419896 15.806673,-14.1099116 0.7541,-0.7468491 3.1768,-1.12806098 4.144475,0.021204 0.967675,1.1492648 0.432782,2.9645005 0.277353,2.9934376 C 31.146674,4.6804771 20.892837,16.554411 14.105823,19.798364 11.493337,21.04704 6.4220112,25.968288 6.2250734,27.77922 5.8783207,30.967767 3.5161253,31.203518 1.8663926,30.802068 0.2166599,30.400618 0.50838587,29.515172 0.08930324,28.785083 z"
|
||||
style="fill:#999999;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
transform="matrix(0.88014214,0,0,1.2457574,0.03112466,-7.072241)"
|
||||
d="m 6.2515457,28.9058 c 0,1.011377 -1.3853203,1.831261 -3.0941995,1.831261 -1.7088791,0 -3.09419937,-0.819884 -3.09419937,-1.831261 0,-1.011378 1.38532027,-1.831261 3.09419937,-1.831261 1.7088792,0 3.0941995,0.819883 3.0941995,1.831261 z"
|
||||
sodipodi:ry="1.8312609"
|
||||
sodipodi:rx="3.0941994"
|
||||
sodipodi:cy="28.9058"
|
||||
sodipodi:cx="3.1573462"
|
||||
id="path2838-2"
|
||||
style="fill:#999999;fill-opacity:1;stroke:#000000;stroke-opacity:1"
|
||||
sodipodi:type="arc" />
|
||||
</g>
|
||||
<g
|
||||
id="g3736"
|
||||
transform="matrix(1.251022,0,0,1.3291102,-5.3427122,-6.2271683)"
|
||||
style="fill:#cccccc">
|
||||
<rect
|
||||
y="13.728863"
|
||||
x="8.3137178"
|
||||
height="9.7679787"
|
||||
width="11.662386"
|
||||
id="rect3670-4"
|
||||
style="fill:#ff8080;fill-opacity:1;stroke:#000000;stroke-width:1.08294201000000000;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||
<path
|
||||
sodipodi:nodetypes="czzzz"
|
||||
id="path3698"
|
||||
d="M 8.3909445,13.431566 C 9.1741586,13.968315 19.275795,13.702637 20.18134,13.657997 21.086885,13.613357 28.172454,9.4137799 26.31518,9.3054269 24.457906,9.1970739 16.974476,8.9799591 15.929816,9.1159861 14.885156,9.2520131 7.6077305,12.894818 8.3909445,13.431566 z"
|
||||
style="fill:#ff8080;stroke:#000000;stroke-width:0.93249397999999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="czzzz"
|
||||
id="path3702"
|
||||
d="m 20.143504,23.643304 c 0.233329,0.226116 6.944642,-4.330114 7.088316,-5.196115 0.143674,-0.866002 -0.502911,-6.614209 -0.221014,-8.6829337 0.281897,-2.0687247 -6.150477,3.4801757 -6.854072,3.7936327 -0.703595,0.313456 -0.246561,9.8593 -0.01323,10.085416 z"
|
||||
style="fill:#ff8080;stroke:#000000;stroke-width:0.85765307999999985px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<text
|
||||
transform="matrix(0.78729415,-0.34209278,0.05263932,1.2473006,0,0)"
|
||||
id="text3732"
|
||||
y="23.833479"
|
||||
x="25.908604"
|
||||
style="font-size:7.24820566000000000px;font-style:normal;font-weight:normal;fill:#ff0000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
y="23.833479"
|
||||
x="25.908604"
|
||||
id="tspan3734"
|
||||
sodipodi:role="line">P</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
id="g3666"
|
||||
transform="matrix(0.43586752,0,0,0.45736299,0.742258,17.406327)">
|
||||
<g
|
||||
id="g3743"
|
||||
transform="matrix(0.90407364,0,0,1.0831425,-1.065431,-3.6227715)">
|
||||
<path
|
||||
style="fill:#999999;stroke:#000000;stroke-width:1.10787821px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 0.14455638,28.741787 c 0,0 4.51353632,-9.247381 13.54060862,-12.9819 9.027071,-3.734519 11.336692,-7.3476357 12.665925,-8.4109403 0.929598,-0.74362 3.916118,-1.1231837 5.108994,0.021112 1.192876,1.1442957 3.059182,1.0075571 0.3419,2.9804953 -2.717283,1.972938 -6.012413,6.213442 -14.378928,9.443369 C 14.202582,21.0372 7.9510373,25.93717 7.7082673,27.740273 7.280817,30.915033 4.3688821,31.149765 2.335217,30.750051 0.30155198,30.350337 0.66116958,29.468719 0.14455638,28.741787 z"
|
||||
id="path2836"
|
||||
sodipodi:nodetypes="csszzsszc" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#999999;fill-opacity:1;stroke:#000000;stroke-opacity:1"
|
||||
id="path2838"
|
||||
sodipodi:cx="3.1573462"
|
||||
sodipodi:cy="28.9058"
|
||||
sodipodi:rx="3.0941994"
|
||||
sodipodi:ry="1.8312609"
|
||||
d="m 6.2515457,28.9058 c 0,1.011377 -1.3853203,1.831261 -3.0941995,1.831261 -1.7088791,0 -3.09419937,-0.819884 -3.09419937,-1.831261 0,-1.011378 1.38532027,-1.831261 3.09419937,-1.831261 1.7088792,0 3.0941995,0.819883 3.0941995,1.831261 z"
|
||||
transform="matrix(0.88014214,0,0,1.2457574,0.03112466,-7.072241)" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Lupa">
|
||||
<g
|
||||
id="g3658"
|
||||
transform="matrix(1.0844092,0,0,1.0938392,-2.3754976,-1.1144395)" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.7 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,158 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project name="JPProxy" default="build" basedir=".">
|
||||
<description>Builds project JPProxy.</description>
|
||||
|
||||
|
||||
<import file="buildconfig.xml"/>
|
||||
<property name="DISTLIBRARIESFULLDIR" value="${DISTRIBUTIONDIR}/${DISTLIBRARIESDIR}"/>
|
||||
<property name="JAVADOCFULLDIR" value="${DISTRIBUTIONDIR}/${JAVADOCDIR}"/>
|
||||
<patternset id="compiler.resources">
|
||||
<include name="**/?*.properties"/>
|
||||
<include name="**/?*.bin"/>
|
||||
<include name="**/?*.xml"/>
|
||||
<include name="**/?*.txt"/>
|
||||
<include name="**/?*.gif"/>
|
||||
<include name="**/?*.png"/>
|
||||
<include name="**/?*.jpeg"/>
|
||||
<include name="**/?*.jpg"/>
|
||||
<include name="**/?*.html"/>
|
||||
<include name="**/?*.dtd"/>
|
||||
<include name="**/?*.tld"/>
|
||||
<include name="**/?*.mid"/>
|
||||
<include name="**/?*.wav"/>
|
||||
</patternset>
|
||||
|
||||
<path id="emma.lib">
|
||||
<pathelement location="${TESTLIBDIR}/emma.jar"/>
|
||||
<pathelement location="${TESTLIBDIR}/emma_ant.jar"/>
|
||||
</path>
|
||||
<taskdef resource="emma_ant.properties" classpathref="emma.lib"/>
|
||||
|
||||
<target name="coverage.instrumentation">
|
||||
<mkdir dir="${INSTRDIR}"/>
|
||||
<mkdir dir="${COVERAGEDIR}"/>
|
||||
<emma>
|
||||
<instr instrpath="${COMPILEDIR}" destdir="${INSTRDIR}" metadatafile="${COVERAGEDIR}/metadata.emma"
|
||||
mode="copy"></instr>
|
||||
</emma>
|
||||
<copy todir="${INSTRDIR}">
|
||||
<fileset dir="${SOURCEDIR}">
|
||||
<patternset refid="compiler.resources"/>
|
||||
<type type="file"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<target name="compile">
|
||||
<delete dir="${COMPILEDIR}"/>
|
||||
<mkdir dir="${COMPILEDIR}"/>
|
||||
<javac srcdir="${SOURCEDIR}" destdir="${COMPILEDIR}" includes="**/*.java" target="1.6" debug="true"
|
||||
debuglevel="lines,vars,source">
|
||||
<classpath>
|
||||
<fileset dir="${LIBRARIESDIR}" includes="**/*.jar"/>
|
||||
</classpath>
|
||||
</javac>
|
||||
<copy todir="${COMPILEDIR}">
|
||||
<fileset dir="${SOURCEDIR}">
|
||||
<patternset refid="compiler.resources"/>
|
||||
<type type="file"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<target name="test" depends="clean,compile">
|
||||
<delete dir="${TESTRESULTSDIR}"/>
|
||||
<mkdir dir="${TESTRESULTSDIR}"/>
|
||||
<mkdir dir="${TESTRESULTSDIR}/raw/"/>
|
||||
<delete dir="${COMPILETESTSDIR}"/>
|
||||
<mkdir dir="${COMPILETESTSDIR}"/>
|
||||
<javac srcdir="${TESTDIR}" destdir="${COMPILETESTSDIR}" includes="**/*.java" target="1.6">
|
||||
<classpath>
|
||||
<pathelement path="${COMPILEDIR}"/>
|
||||
<fileset dir="${LIBRARIESDIR}" includes="**/*.jar"/>
|
||||
<fileset dir="${TESTLIBDIR}" includes="**/*.jar"/>
|
||||
</classpath>
|
||||
</javac>
|
||||
<antcall target="coverage.instrumentation"/>
|
||||
<junit printsummary="yes" haltonfailure="yes" showoutput="yes">
|
||||
<classpath>
|
||||
<pathelement path="${INSTRDIR}"/>
|
||||
<pathelement path="${COMPILEDIR}"/>
|
||||
<pathelement path="${COMPILETESTSDIR}"/>
|
||||
<fileset dir="${LIBRARIESDIR}" includes="**/*.jar"/>
|
||||
<fileset dir="${TESTLIBDIR}" includes="**/*.jar"/>
|
||||
</classpath>
|
||||
<jvmarg value="-Demma.coverage.out.file=${COVERAGEDIR}/coverage.emma"/>
|
||||
<jvmarg value="-Demma.coverage.out.merge=true"/>
|
||||
<batchtest fork="yes" todir="${TESTRESULTSDIR}/raw/">
|
||||
<formatter type="xml"/>
|
||||
<fileset dir="${TESTDIR}">
|
||||
<include name="**/*.java"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
</junit>
|
||||
<!-- JUnit report -->
|
||||
<junitreport todir="${TESTRESULTSDIR}">
|
||||
<fileset dir="${TESTRESULTSDIR}/raw/">
|
||||
<include name="TEST-*.xml"/>
|
||||
</fileset>
|
||||
<report format="frames" todir="${TESTRESULTSDIR}\html\"/>
|
||||
</junitreport>
|
||||
<!-- Coverage report -->
|
||||
<mkdir dir="${COVERAGERESULTSDIR}"/>
|
||||
<emma>
|
||||
<report sourcepath="${SOURCEDIR}" depth="method">
|
||||
<fileset dir="${COVERAGEDIR}">
|
||||
<include name="*.emma"/>
|
||||
</fileset>
|
||||
<html outfile="${COVERAGERESULTSDIR}/index.html"/>
|
||||
</report>
|
||||
</emma>
|
||||
</target>
|
||||
<target name="build" depends="clean,compile">
|
||||
<mkdir dir="${DISTRIBUTIONDIR}"/>
|
||||
<delete dir="${DISTLIBRARIESFULLDIR}"/>
|
||||
<mkdir dir="${DISTLIBRARIESFULLDIR}"/>
|
||||
<copy todir="${DISTLIBRARIESFULLDIR}">
|
||||
<fileset dir="${LIBRARIESDIR}" includes="**/*.jar"/>
|
||||
</copy>
|
||||
<pathconvert pathsep=" " property="manifestClassPath">
|
||||
<fileset dir="${DISTRIBUTIONDIR}" includes="${DISTLIBRARIESDIR}/**/*.*"/>
|
||||
<chainedmapper>
|
||||
<flattenmapper/>
|
||||
<globmapper from="*" to="${DISTLIBRARIESDIR}/*"/>
|
||||
</chainedmapper>
|
||||
</pathconvert>
|
||||
|
||||
<jar destfile="${DISTRIBUTIONDIR}/${JARFILENAME}.jar" basedir="${COMPILEDIR}">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="${MAINCLASS}"/>
|
||||
<attribute name="Class-Path" value="${manifestClassPath}"/>
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="run" depends="build">
|
||||
<java jar="${DISTRIBUTIONDIR}/${JARFILENAME}.jar" fork="true"/>
|
||||
</target>
|
||||
|
||||
|
||||
<target name="javadoc">
|
||||
<mkdir dir="${JAVADOCFULLDIR}"/>
|
||||
<javadoc sourcepath="${SOURCEDIR}" destdir="${JAVADOCFULLDIR}" windowtitle="${PROJECTNAME}"
|
||||
useexternalfile="yes">
|
||||
<fileset dir="${SOURCEDIR}" includes="**/*.java"/>
|
||||
<classpath>
|
||||
<fileset dir="${LIBRARIESDIR}" includes="**/*.jar"/>
|
||||
</classpath>
|
||||
</javadoc>
|
||||
</target>
|
||||
<target name="clean">
|
||||
<delete dir="${DISTRIBUTIONDIR}"/>
|
||||
<delete dir="${COMPILETESTSDIR}"/>
|
||||
<delete dir="${COMPILEDIR}"/>
|
||||
<delete dir="${COVERAGEDIR}"/>
|
||||
<delete dir="${TESTRESULTSDIR}"/>
|
||||
</target>
|
||||
</project>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project name="buildconfig" basedir=".">
|
||||
<property name="PROJECTNAME" value="JPProxy"/>
|
||||
<property name="JARFILENAME" value="jpproxy"/>
|
||||
|
||||
<property name="MAINCLASS" value="com.jpexs.proxy.Main"/>
|
||||
<property name="SOURCEDIR" value="src"/>
|
||||
<property name="TESTDIR" value="test"/>
|
||||
<property name="TESTLIBDIR" value="testlib"/>
|
||||
<property name="TESTRESULTSDIR" value="reports/tests"/>
|
||||
<property name="COVERAGERESULTSDIR" value="reports/coverage"/>
|
||||
<property name="DISTRIBUTIONDIR" value="dist"/>
|
||||
<property name="COMPILEDIR" value="build/classes"/>
|
||||
<property name="INSTRDIR" value="build/instr-classes"/>
|
||||
<property name="COVERAGEDIR" value="coverage"/>
|
||||
<property name="COMPILETESTSDIR" value="build/test"/>
|
||||
<property name="LIBRARIESDIR" value="lib"/>
|
||||
|
||||
<property name="DISTLIBRARIESDIR" value="lib"/>
|
||||
<property name="JAVADOCDIR" value="javadoc"/>
|
||||
|
||||
</project>
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
http://archiv.nova.cz/static/cz/shared/app/MediaCenter.swf
|
||||
.\config\saved\asdec_85f11ffb.tmp
|
||||
http://admin.brightcove.com/viewer/us1.24.00.00/federatedVideo/BrightcovePlayer.swf
|
||||
.\config\saved\asdec_d5ca3577.tmp
|
||||
http://archiv.nova.cz/static/cz/shared/app/MediaCenter_Catchup.swf
|
||||
.\config\saved\asdec_d08cceb2.tmp
|
||||
http://abc.go.com/vp2/ws/utils/2000/geo/video/geolocation
|
||||
.\config\saved\asdec_70eaddc7.tmp
|
||||
http://ll.static.abc.com/m/vp2/prod/flash/VP2.swf?ver=*
|
||||
.\config\saved\asdec_a3d1aa1c.tmp
|
||||
http://archiv.nova.cz/static/shared/app/flowplayer/OpenAdStreamer-*.swf
|
||||
.\config\saved\asdec_65483348.tmp
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><geolocation brand="001" device="001" ver="2000" xmlns="http://abc.go.com/vp2/ws/xmlns"><user allowed="true"/></geolocation>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,134 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Class used to represent an array of bytes as an Object.
|
||||
*
|
||||
* @author Mark Boyns
|
||||
*/
|
||||
public class ByteArray {
|
||||
public byte bytes[];
|
||||
public int offset = 0;
|
||||
|
||||
/**
|
||||
* Create a ByteArray with the default size.
|
||||
*/
|
||||
public ByteArray() {
|
||||
this(512);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ByteArray with a specific default size.
|
||||
*/
|
||||
public ByteArray(int size) {
|
||||
bytes = new byte[size];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ByteArray from a String.
|
||||
*/
|
||||
public ByteArray(String s) {
|
||||
this(s.length());
|
||||
append(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ByteArray from an array of bytes.
|
||||
*/
|
||||
public ByteArray(byte b[]) {
|
||||
this(b.length);
|
||||
append(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a byte.
|
||||
*/
|
||||
public void append(byte ch) {
|
||||
if (offset == bytes.length) {
|
||||
byte tmpbytes[] = bytes;
|
||||
bytes = new byte[tmpbytes.length * 2];
|
||||
System.arraycopy(tmpbytes, 0, bytes, 0, offset);
|
||||
}
|
||||
bytes[offset++] = ch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a ByteArray.
|
||||
*/
|
||||
public void append(ByteArray b) {
|
||||
if (bytes.length - offset < b.length()) {
|
||||
byte tmpbytes[] = bytes;
|
||||
bytes = new byte[tmpbytes.length + b.length()];
|
||||
System.arraycopy(tmpbytes, 0, bytes, 0, offset);
|
||||
}
|
||||
System.arraycopy(b.bytes, 0, bytes, offset, b.length());
|
||||
offset += b.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an array of bytes.
|
||||
*/
|
||||
public void append(byte b[]) {
|
||||
if (bytes.length - offset < b.length) {
|
||||
byte tmpbytes[] = bytes;
|
||||
bytes = new byte[tmpbytes.length + b.length];
|
||||
System.arraycopy(tmpbytes, 0, bytes, 0, offset);
|
||||
}
|
||||
System.arraycopy(b, 0, bytes, offset, b.length);
|
||||
offset += b.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a String.
|
||||
*/
|
||||
public void append(String s) {
|
||||
append(s.getBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to String.
|
||||
*/
|
||||
public String toString() {
|
||||
return new String(bytes, 0, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bytes.
|
||||
*/
|
||||
public byte[] getBytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public void writeTo(OutputStream out)
|
||||
throws IOException {
|
||||
out.write(bytes, 0, offset);
|
||||
}
|
||||
|
||||
public byte get(int i) {
|
||||
return bytes[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of bytes.
|
||||
*/
|
||||
public int length() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
public void erase() {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
public void chop() {
|
||||
chop(1);
|
||||
}
|
||||
|
||||
public void chop(int i) {
|
||||
offset -= i;
|
||||
if (offset < 0) {
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Interface to catch contentTypes
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface CatchedListener {
|
||||
/**
|
||||
* Method called when specified contentType is received
|
||||
*
|
||||
* @param contentType Content type
|
||||
* @param url URL of the method
|
||||
* @param data Data stream
|
||||
*/
|
||||
public void catched(String contentType, String url, InputStream data);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* Client which reads a Request and writes a Reply.
|
||||
*
|
||||
* @author Mark Boyns
|
||||
*/
|
||||
public class Client extends Connection {
|
||||
/**
|
||||
* Create a Client from a Socket.
|
||||
*/
|
||||
Client(Socket s) throws IOException {
|
||||
super(s);
|
||||
in = new BufferedInputStream(in);
|
||||
//out = new DebugOutputStream(new BufferedOutputStream(out));
|
||||
out = new BufferedOutputStream(out);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a Request.
|
||||
*
|
||||
* @returns a Request.
|
||||
*/
|
||||
Request read() throws IOException {
|
||||
Request request = new Request(this);
|
||||
request.read(getInputStream());
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a Reply
|
||||
*/
|
||||
void write(Reply reply) throws IOException {
|
||||
reply.write(getOutputStream());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
|
||||
/**
|
||||
* Create a TCP connection from a Socket or hostname/port
|
||||
* with buffered IO.
|
||||
*
|
||||
* @author Mark Boyns
|
||||
* @see java.net.Socket
|
||||
*/
|
||||
class Connection {
|
||||
Socket socket = null;
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
|
||||
/**
|
||||
* Create a Connection from a Socket.
|
||||
*
|
||||
* @param socket a socket
|
||||
*/
|
||||
Connection(Socket socket) throws IOException {
|
||||
this.socket = socket;
|
||||
in = socket.getInputStream();
|
||||
out = socket.getOutputStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Connection from a hostname and port.
|
||||
*
|
||||
* @param host remote hostname
|
||||
* @param port remote port
|
||||
*/
|
||||
Connection(String host, int port) throws IOException {
|
||||
this(new Socket(host, port));
|
||||
}
|
||||
|
||||
Connection() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the input stream.
|
||||
*/
|
||||
InputStream getInputStream() {
|
||||
return in;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the output stream.
|
||||
*/
|
||||
OutputStream getOutputStream() {
|
||||
return out;
|
||||
}
|
||||
|
||||
void setInputStream(InputStream in) {
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
void setOutputStream(OutputStream out) {
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the connection.
|
||||
*/
|
||||
void close() {
|
||||
if (socket != null) {
|
||||
try {
|
||||
socket.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
System.out.println("Connection: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Socket getSocket() {
|
||||
return socket;
|
||||
}
|
||||
|
||||
public InetAddress getInetAddress() {
|
||||
return socket.getInetAddress();
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return socket.getPort();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getInetAddress().getHostAddress() + ":" + getPort();
|
||||
}
|
||||
|
||||
public void setTimeout(int timeout)
|
||||
throws SocketException {
|
||||
socket.setSoTimeout(timeout);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
class Copy implements Runnable {
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
|
||||
Copy(InputStream in, OutputStream out) {
|
||||
this.in = in;
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
int n;
|
||||
byte buffer[] = new byte[8192];
|
||||
|
||||
try {
|
||||
while ((n = in.read(buffer, 0, buffer.length)) > 0) {
|
||||
out.write(buffer, 0, n);
|
||||
out.flush();
|
||||
}
|
||||
out.flush();
|
||||
}
|
||||
catch (IOException e) {
|
||||
String s = e.toString();
|
||||
// ignore socket closed exceptions
|
||||
if (s.toLowerCase().indexOf("socket closed") == -1) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,575 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
|
||||
import java.io.*;
|
||||
import java.net.Socket;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* HTTP transaction handler. A handler is created by Server for
|
||||
* each HTTP transaction. Given a socket, the handler will deal with
|
||||
* the request, reply, and invoke request, reply, and content filters.
|
||||
*
|
||||
* @author Mark Boyns
|
||||
*/
|
||||
class Handler implements Runnable {
|
||||
static final boolean DEBUG = false;
|
||||
Socket socket = null;
|
||||
Request request = null;
|
||||
Reply reply = null;
|
||||
HttpRelay http = null;
|
||||
int currentLength = -1;
|
||||
int contentLength = -1;
|
||||
long idle = 0;
|
||||
double bytesPerSecond = 0;
|
||||
Client client;
|
||||
|
||||
int MAXTIMEOUT = 1000 * 60 * 5;
|
||||
List<Replacement> replacements;
|
||||
CatchedListener catchedListener;
|
||||
List<String> catchedContentTypes;
|
||||
ReplacedListener replacedListener;
|
||||
|
||||
/**
|
||||
* Create a Handler.
|
||||
*/
|
||||
Handler(Socket socket, List<Replacement> replacements, List<String> catchedContentTypes, CatchedListener catchedListener, ReplacedListener replacedListener) {
|
||||
this.socket = socket;
|
||||
this.replacements = replacements;
|
||||
this.catchedListener = catchedListener;
|
||||
this.catchedContentTypes = catchedContentTypes;
|
||||
this.replacedListener = replacedListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close all connections associated with this handler.
|
||||
*/
|
||||
synchronized void close() {
|
||||
if (client != null) {
|
||||
client.close();
|
||||
client = null;
|
||||
}
|
||||
if (http != null) {
|
||||
http.close();
|
||||
http = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush all data to the client.
|
||||
*/
|
||||
void flush() {
|
||||
if (client != null) {
|
||||
try {
|
||||
client.getOutputStream().flush();
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
boolean keepAlive = false;
|
||||
Exception reason = null;
|
||||
|
||||
Thread.currentThread().setName("Handler("
|
||||
+ socket.getInetAddress().getHostAddress()
|
||||
+ ")");
|
||||
|
||||
try {
|
||||
client = new Client(socket);
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
|
||||
do {
|
||||
request = null;
|
||||
reply = null;
|
||||
|
||||
idle = System.currentTimeMillis();
|
||||
|
||||
|
||||
try {
|
||||
request = client.read();
|
||||
if (Main.DEBUG_MODE) {
|
||||
System.out.println("REQUEST: " + request.getURL());
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
break;
|
||||
}
|
||||
|
||||
idle = 0;
|
||||
|
||||
|
||||
try {
|
||||
keepAlive = processRequest();
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
reason = ioe;
|
||||
keepAlive = false;
|
||||
}
|
||||
|
||||
if (request != null && reply != null) {
|
||||
// XXX insert the number of bytes read into the
|
||||
// reply content-length for logging.
|
||||
if (reply != null && currentLength > 0) {
|
||||
reply.setHeaderField("Content-length", currentLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (keepAlive);
|
||||
|
||||
|
||||
if (reason != null && reason.getMessage().indexOf("Broken pipe") == -1) {
|
||||
}
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
boolean processRequest() throws IOException {
|
||||
boolean keepAlive = false;
|
||||
|
||||
while (reply == null) {
|
||||
boolean secure = false;
|
||||
boolean uncompress = false;
|
||||
|
||||
|
||||
if (request.getCommand().equals("CONNECT")) {
|
||||
secure = true;
|
||||
} else if (request.getURL().startsWith("https://")) {
|
||||
System.out.println("Netscape keep-alive bug: " + request.getURL());
|
||||
return false;
|
||||
} else if (!request.getURL().startsWith("http://")) {
|
||||
System.out.println("Unknown URL: " + request.getURL());
|
||||
return false;
|
||||
}
|
||||
|
||||
keepAlive = (request.containsHeaderField("Proxy-Connection")
|
||||
&& request.getHeaderField("Proxy-Connection").equals("Keep-Alive"));
|
||||
|
||||
|
||||
/* First look for any HttpFilters */
|
||||
|
||||
|
||||
/* None found. Use http or https relay. */
|
||||
if (secure) {
|
||||
http = createHttpsRelay();
|
||||
} else {
|
||||
http = createHttpRelay();
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
http.sendRequest(request);
|
||||
if (http instanceof Http) {
|
||||
((Http) http).setTimeout(MAXTIMEOUT);
|
||||
}
|
||||
reply = http.recvReply(request);
|
||||
}
|
||||
catch (RetryRequestException e) {
|
||||
http.close();
|
||||
http = null;
|
||||
continue; /* XXX */
|
||||
}
|
||||
|
||||
/* Guess content-type if there aren't any headers.
|
||||
Probably an upgraded HTTP/0.9 reply. */
|
||||
if (reply.headerCount() == 0) {
|
||||
String url = request.getURL();
|
||||
if (url.endsWith("/")
|
||||
|| url.endsWith(".html") || url.endsWith(".htm")) {
|
||||
reply.setHeaderField("Content-type", "text/html");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String encoding = reply.getHeaderField("Content-Encoding");
|
||||
if (encoding != null && encoding.indexOf("gzip") != -1) {
|
||||
reply.removeHeaderField("Content-Encoding");
|
||||
reply.removeHeaderField("Content-length");
|
||||
uncompress = true;
|
||||
}
|
||||
/* update reply */
|
||||
|
||||
|
||||
reply.removeHeaderField("Proxy-Connection");
|
||||
if (keepAlive && reply.containsHeaderField("Content-length")) {
|
||||
reply.setHeaderField("Proxy-Connection", "Keep-Alive");
|
||||
} else {
|
||||
keepAlive = false;
|
||||
}
|
||||
|
||||
currentLength = -1;
|
||||
contentLength = -1;
|
||||
try {
|
||||
contentLength = Integer.parseInt(reply.getHeaderField("Content-length"));
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
}
|
||||
|
||||
/* update content-length reply */
|
||||
|
||||
|
||||
if (secure) {
|
||||
Https https = (Https) http;
|
||||
int timeout = MAXTIMEOUT;
|
||||
|
||||
client.write(reply);
|
||||
|
||||
try {
|
||||
https.setTimeout(timeout);
|
||||
|
||||
Copy cp = new Copy(client.getInputStream(), https.getOutputStream());
|
||||
WorkerThread.assignThread(cp, "");
|
||||
flushCopy(https.getInputStream(), client.getOutputStream(), -1, true);
|
||||
client.close();
|
||||
}
|
||||
catch (InterruptedIOException iioe) {
|
||||
// ignore socket timeout exceptions
|
||||
}
|
||||
} else if (reply.hasContent()) {
|
||||
try {
|
||||
processContent(uncompress);
|
||||
}
|
||||
catch (IOException e) {
|
||||
if (http instanceof Http) {
|
||||
((Http) http).reallyClose();
|
||||
} else {
|
||||
http.close();
|
||||
}
|
||||
http = null;
|
||||
client.close();
|
||||
client = null;
|
||||
throw e;
|
||||
//return false; /* XXX */
|
||||
}
|
||||
|
||||
/* Document contains no data. */
|
||||
if (contentLength == 0) {
|
||||
client.close();
|
||||
}
|
||||
} else {
|
||||
client.write(reply);
|
||||
}
|
||||
|
||||
http.close();
|
||||
}
|
||||
|
||||
return keepAlive;
|
||||
}
|
||||
|
||||
HttpRelay createHttpsRelay() throws IOException {
|
||||
HttpRelay http;
|
||||
|
||||
http = new Https(request.getHost(), request.getPort());
|
||||
|
||||
return http;
|
||||
}
|
||||
|
||||
HttpRelay createHttpRelay() throws IOException {
|
||||
HttpRelay http;
|
||||
|
||||
|
||||
http = Http.open(request.getHost(), request.getPort());
|
||||
|
||||
|
||||
return http;
|
||||
}
|
||||
|
||||
|
||||
InputStream readChunkedTransfer(InputStream in) throws IOException {
|
||||
ByteArrayOutputStream chunks = new ByteArrayOutputStream(8192);
|
||||
int size = 0;
|
||||
|
||||
contentLength = 0;
|
||||
while ((size = reply.getChunkSize(in)) > 0) {
|
||||
contentLength += size;
|
||||
copy(in, chunks, size, true);
|
||||
reply.readLine(in);
|
||||
}
|
||||
reply.getChunkedFooter(in);
|
||||
|
||||
reply.removeHeaderField("Transfer-Encoding");
|
||||
reply.setHeaderField("Content-length", contentLength);
|
||||
|
||||
return new ByteArrayInputStream(chunks.toByteArray());
|
||||
}
|
||||
|
||||
|
||||
private static DateFormat httpDateFormat() {
|
||||
DateFormat httpDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
|
||||
httpDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
return httpDateFormat;
|
||||
}
|
||||
|
||||
void disableReplyCaching() {
|
||||
reply.removeHeaderField("Cache-Control");
|
||||
reply.removeHeaderField("Last-Modified");
|
||||
reply.removeHeaderField("Expires");
|
||||
reply.removeHeaderField("Date");
|
||||
reply.removeHeaderField("ETag");
|
||||
reply.removeHeaderField("Pragma");
|
||||
|
||||
reply.setHeaderField("Pragma", "no-cache");
|
||||
reply.setHeaderField("Cache-Control", "no-cache, must-revalidate");
|
||||
Calendar now = Calendar.getInstance();
|
||||
reply.setHeaderField("Expires", httpDateFormat().format(now.getTime()));//"Sat, 26 Jul 1997 05:00:00 GMT");
|
||||
reply.setHeaderField("Last-Modified", "Sat, 26 Jul 1997 05:00:00 GMT");
|
||||
}
|
||||
|
||||
|
||||
void processContent(boolean uncompress) throws IOException {
|
||||
InputStream in;
|
||||
boolean chunked = false;
|
||||
|
||||
if (reply.containsHeaderField("Transfer-Encoding")
|
||||
&& reply.getTransferEncoding().equals("chunked")) {
|
||||
in = readChunkedTransfer(reply.getContent());
|
||||
chunked = true;
|
||||
} else {
|
||||
in = reply.getContent();
|
||||
}
|
||||
|
||||
if (in == null) {
|
||||
System.out.println("No inputstream");
|
||||
return;
|
||||
} else if (uncompress) {
|
||||
in = new GZIPInputStream(in);
|
||||
}
|
||||
|
||||
String url = request.getURL();
|
||||
boolean replaced = false;
|
||||
for (Replacement r : replacements) {
|
||||
if (r.matches(url)) {
|
||||
r.lastAccess = Calendar.getInstance();
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
try {
|
||||
FileInputStream fis = new FileInputStream(r.targetFile);
|
||||
byte buf[] = new byte[2048];
|
||||
int pos = 0;
|
||||
while ((pos = fis.read(buf)) > 0) {
|
||||
buffer.write(buf, 0, pos);
|
||||
}
|
||||
fis.close();
|
||||
buffer.close();
|
||||
} catch (IOException ex) {
|
||||
if (Main.DEBUG_MODE) {
|
||||
System.err.println("ERROR:Cannot read file: " + r.targetFile);
|
||||
}
|
||||
}
|
||||
byte bytes[] = buffer.toByteArray();
|
||||
contentLength = bytes.length;
|
||||
reply.setHeaderField("Content-length", contentLength);
|
||||
disableReplyCaching();
|
||||
client.write(reply);
|
||||
copy(new ByteArrayInputStream(bytes),
|
||||
client.getOutputStream(), contentLength, false);
|
||||
replaced = true;
|
||||
if (replacedListener != null) {
|
||||
replacedListener.replaced(r, request.getURL(), reply.getContentType());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!replaced) {
|
||||
|
||||
String contentType = reply.getHeaderField("Content-type");
|
||||
if (reply.getStatusCode() == 200) {
|
||||
if (contentType != null) {
|
||||
for (String ct : catchedContentTypes) {
|
||||
String convContentType = contentType;
|
||||
if (convContentType.contains(";"))
|
||||
convContentType = convContentType.substring(0, convContentType.indexOf(";"));
|
||||
|
||||
if (ct.toLowerCase().equals(convContentType.toLowerCase())) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
copy(in, baos, contentLength, true);
|
||||
if (catchedListener != null) {
|
||||
catchedListener.catched(ct, request.getURL(), new ByteArrayInputStream(baos.toByteArray()));
|
||||
}
|
||||
in = new ByteArrayInputStream(baos.toByteArray());
|
||||
disableReplyCaching();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
client.write(reply);
|
||||
copy(in, client.getOutputStream(), contentLength, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the content length.
|
||||
*/
|
||||
int getTotalBytes() {
|
||||
return contentLength > 0 ? contentLength : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of bytes read so far.
|
||||
*/
|
||||
int getCurrentBytes() {
|
||||
return currentLength > 0 ? currentLength : 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copy in to out.
|
||||
*
|
||||
* @param in InputStream
|
||||
* @param out OutputStream
|
||||
* @param monitored Update the Monitor
|
||||
*/
|
||||
void copy(InputStream in, OutputStream out, int length, boolean monitored)
|
||||
throws IOException {
|
||||
if (length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int n;
|
||||
byte buffer[] = new byte[8192];
|
||||
long start = System.currentTimeMillis();
|
||||
long now = 0, then = start;
|
||||
|
||||
bytesPerSecond = 0;
|
||||
|
||||
if (monitored) {
|
||||
currentLength = 0;
|
||||
}
|
||||
|
||||
for (; ;) {
|
||||
n = (length > 0) ? Math.min(length, buffer.length) : buffer.length;
|
||||
n = in.read(buffer, 0, n);
|
||||
if (n < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
out.write(buffer, 0, n);
|
||||
|
||||
if (monitored) {
|
||||
currentLength += n;
|
||||
|
||||
}
|
||||
|
||||
now = System.currentTimeMillis();
|
||||
bytesPerSecond = currentLength / ((now - start) / 1000.0);
|
||||
|
||||
// flush after 1 second
|
||||
if (now - then > 1000) {
|
||||
out.flush();
|
||||
}
|
||||
|
||||
if (length != -1) {
|
||||
length -= n;
|
||||
if (length == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
then = now;
|
||||
}
|
||||
|
||||
out.flush();
|
||||
|
||||
if (DEBUG) {
|
||||
System.out.println(currentLength + " bytes processed in "
|
||||
+ ((System.currentTimeMillis() - start)
|
||||
/ 1000.0) + " seconds "
|
||||
+ ((int) bytesPerSecond / 1024) + " kB/s");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy in to out.
|
||||
*
|
||||
* @param in InputStream
|
||||
* @param out OutputStream
|
||||
* @param monitored Update the Monitor
|
||||
*/
|
||||
void flushCopy(InputStream in, OutputStream out, int length, boolean monitored)
|
||||
throws IOException {
|
||||
if (length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int n;
|
||||
byte buffer[] = new byte[8192];
|
||||
long start = System.currentTimeMillis();
|
||||
bytesPerSecond = 0;
|
||||
|
||||
if (monitored) {
|
||||
currentLength = 0;
|
||||
}
|
||||
|
||||
for (; ;) {
|
||||
n = (length > 0) ? Math.min(length, buffer.length) : buffer.length;
|
||||
n = in.read(buffer, 0, n);
|
||||
if (n < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
out.write(buffer, 0, n);
|
||||
out.flush();
|
||||
if (monitored) {
|
||||
currentLength += n;
|
||||
|
||||
}
|
||||
bytesPerSecond = currentLength / ((System.currentTimeMillis() - start) / 1000.0);
|
||||
if (length != -1) {
|
||||
length -= n;
|
||||
if (length == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
out.flush();
|
||||
|
||||
if (DEBUG) {
|
||||
System.out.println(currentLength + " bytes processed in "
|
||||
+ ((System.currentTimeMillis() - start) / 1000.0) + " seconds "
|
||||
+ ((int) bytesPerSecond / 1024) + " kB/s");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a string represenation of the hander's state.
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuffer str = new StringBuffer();
|
||||
str.append("CLIENT ");
|
||||
str.append(socket.getInetAddress().getHostAddress());
|
||||
str.append(":");
|
||||
str.append(socket.getPort());
|
||||
str.append(" - ");
|
||||
if (request == null) {
|
||||
str.append("idle " + ((System.currentTimeMillis() - idle) / 1000.0) + " sec");
|
||||
} else {
|
||||
if (reply != null && currentLength > 0) {
|
||||
str.append("(");
|
||||
str.append(currentLength);
|
||||
if (contentLength > 0) {
|
||||
str.append("/");
|
||||
str.append(contentLength);
|
||||
}
|
||||
str.append(" ");
|
||||
str.append(((int) bytesPerSecond / 1024) + " kB/s");
|
||||
str.append(") ");
|
||||
}
|
||||
str.append(request.getURL());
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* @author Mark Boyns
|
||||
*/
|
||||
class Http extends HttpConnection {
|
||||
static final boolean DEBUG = false; /* enable lots of debug output */
|
||||
|
||||
/* XXX - more than 1 should work now. */
|
||||
static final int MAX_PENDING_REQUESTS = 1;
|
||||
|
||||
static Hashtable cache = new Hashtable(33);
|
||||
private static Object httpLock = new Object();
|
||||
|
||||
|
||||
String host;
|
||||
int port;
|
||||
boolean proxy = false;
|
||||
boolean persistent = false;
|
||||
boolean closed = false;
|
||||
long idle = 0;
|
||||
Vector queue = new Vector();
|
||||
|
||||
Http(String host, int port) throws IOException {
|
||||
this(host, port, false);
|
||||
}
|
||||
|
||||
Http(String host, int port, boolean isProxy) throws IOException {
|
||||
super(host, port);
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.proxy = isProxy;
|
||||
}
|
||||
|
||||
public synchronized void sendRequest(Request request)
|
||||
throws IOException, RetryRequestException {
|
||||
queue.addElement(request);
|
||||
|
||||
try {
|
||||
send(request);
|
||||
}
|
||||
catch (IOException e) {
|
||||
if (persistent) {
|
||||
persistent = false;
|
||||
if (DEBUG) System.out.println("RETRY SEND " + request.getURL());
|
||||
throw new RetryRequestException();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized Reply recvReply(Request request)
|
||||
throws IOException, RetryRequestException {
|
||||
while (queue.firstElement() != request) {
|
||||
try {
|
||||
wait();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
if (closed) {
|
||||
if (DEBUG) System.out.println("RETRY CLOSED " + request.getURL());
|
||||
throw new RetryRequestException();
|
||||
}
|
||||
|
||||
try {
|
||||
return recv();
|
||||
}
|
||||
catch (IOException e) {
|
||||
if (persistent) {
|
||||
persistent = false;
|
||||
if (DEBUG) System.out.println("RETRY RECV " + request.getURL());
|
||||
throw new RetryRequestException();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public void reallyClose() {
|
||||
persistent = false;
|
||||
if (DEBUG)
|
||||
System.out.println("REALLY CLOSE " + this);
|
||||
close();
|
||||
}
|
||||
|
||||
public synchronized void close() {
|
||||
if (persistent) {
|
||||
idle = System.currentTimeMillis();
|
||||
} else {
|
||||
cacheRemove(host, port, this);
|
||||
super.close();
|
||||
closed = true;
|
||||
}
|
||||
|
||||
if (queue.size() > 0) {
|
||||
queue.removeElementAt(0);
|
||||
if (DEBUG) {
|
||||
if (persistent)
|
||||
System.out.println("DONE " + this);
|
||||
else
|
||||
System.out.println("CLOSE " + this);
|
||||
}
|
||||
notify();
|
||||
}
|
||||
}
|
||||
|
||||
private void send(Request request) throws IOException {
|
||||
if (DEBUG) System.out.println("SEND " + request.getURL());
|
||||
|
||||
/* Prepare HTTP/1.1 request */
|
||||
request.removeHeaderField("Proxy-Connection");
|
||||
request.setHeaderField("Connection", "open");
|
||||
if (!request.containsHeaderField("Host")) {
|
||||
request.setHeaderField("Host", request.getHost());
|
||||
}
|
||||
|
||||
if (proxy) {
|
||||
request.write(getOutputStream());
|
||||
} else {
|
||||
String oldStatusLine = request.statusLine;
|
||||
StringBuffer head = new StringBuffer();
|
||||
head.append(request.getCommand());
|
||||
head.append(" ");
|
||||
head.append(request.getPath());
|
||||
head.append(" ");
|
||||
head.append("HTTP/1.0");
|
||||
request.statusLine = head.toString();
|
||||
|
||||
request.write(getOutputStream());
|
||||
|
||||
/* flush? */
|
||||
|
||||
request.statusLine = oldStatusLine;
|
||||
}
|
||||
}
|
||||
|
||||
private Reply recv() throws IOException {
|
||||
Reply reply = new Reply(getInputStream());
|
||||
reply.read();
|
||||
|
||||
String conn = reply.getHeaderField("Connection");
|
||||
|
||||
if (DEBUG) System.out.println("RECV " + reply.statusLine);
|
||||
|
||||
if (reply.containsHeaderField("Connection")
|
||||
&& reply.getHeaderField("Connection").equals("close")) {
|
||||
persistent = false;
|
||||
} else if (reply.getProtocol().equals("HTTP/1.1")) {
|
||||
persistent = true;
|
||||
} else {
|
||||
persistent = false;
|
||||
}
|
||||
|
||||
/* Received HTTP/1.1 "Continue". Read another Reply. */
|
||||
if (reply.getStatusCode() == 100) {
|
||||
reply = recv();
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
private boolean isBusy() {
|
||||
return queue.size() >= MAX_PENDING_REQUESTS;
|
||||
}
|
||||
|
||||
private boolean isPersistent() {
|
||||
return persistent;
|
||||
}
|
||||
|
||||
private static String cacheKey(String host, int port) {
|
||||
return host.toLowerCase() + ":" + port;
|
||||
}
|
||||
|
||||
private static Vector cacheLookup(String host, int port) {
|
||||
Vector v = (Vector) cache.get(cacheKey(host, port));
|
||||
return v;
|
||||
}
|
||||
|
||||
private static boolean cacheContains(Http http) {
|
||||
Vector v = (Vector) cache.get(cacheKey(http.host, http.port));
|
||||
return v != null ? v.contains(http) : false;
|
||||
}
|
||||
|
||||
private static void cacheInsert(String host, int port, Http http) {
|
||||
String key = cacheKey(host, port);
|
||||
Vector v = (Vector) cache.get(key);
|
||||
if (v == null) {
|
||||
v = new Vector();
|
||||
}
|
||||
v.addElement(http);
|
||||
cache.put(key, v);
|
||||
}
|
||||
|
||||
private static void cacheRemove(String host, int port, Http http) {
|
||||
Vector v = (Vector) cache.get(cacheKey(host, port));
|
||||
if (v != null) {
|
||||
v.removeElement(http);
|
||||
if (v.isEmpty()) {
|
||||
cache.remove(cacheKey(host, port));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void cacheClean() {
|
||||
long now = System.currentTimeMillis();
|
||||
Enumeration e = cache.keys();
|
||||
while (e.hasMoreElements()) {
|
||||
Vector v = (Vector) cache.get(e.nextElement());
|
||||
for (int i = 0; i < v.size(); i++) {
|
||||
Http http = (Http) v.elementAt(i);
|
||||
if (http.idle > 0 && now - http.idle > 30000) /* 30 seconds */ {
|
||||
if (DEBUG) System.out.println("IDLE " + http);
|
||||
http.persistent = false;
|
||||
http.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Http open(String host, int port, boolean isProxy)
|
||||
throws IOException {
|
||||
Http http = null;
|
||||
|
||||
synchronized (httpLock) {
|
||||
Vector v = cacheLookup(host, port);
|
||||
if (v != null) {
|
||||
for (int i = 0; i < v.size(); i++) {
|
||||
Http pick = (Http) v.elementAt(i);
|
||||
|
||||
/* find an http connection that isn't busy */
|
||||
if (pick.isPersistent() && !pick.isBusy()) {
|
||||
http = pick;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (http != null) {
|
||||
http.idle = 0;
|
||||
if (DEBUG) System.out.println("REUSE " + http);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (http == null) {
|
||||
if (DEBUG) System.out.println("OPENING " + host + ":" + port);
|
||||
http = new Http(host, port, isProxy);
|
||||
if (DEBUG) System.out.println("OPENED " + http);
|
||||
cacheInsert(host, port, http);
|
||||
}
|
||||
|
||||
return http;
|
||||
}
|
||||
|
||||
static Http open(String host, int port) throws IOException {
|
||||
return open(host, port, false);
|
||||
}
|
||||
|
||||
static Enumeration enumerate() {
|
||||
Vector list = new Vector();
|
||||
Enumeration e = cache.keys();
|
||||
while (e.hasMoreElements()) {
|
||||
Vector v = (Vector) cache.get(e.nextElement());
|
||||
for (int i = 0; i < v.size(); i++) {
|
||||
list.addElement(v.elementAt(i));
|
||||
}
|
||||
}
|
||||
return list.elements();
|
||||
}
|
||||
|
||||
static synchronized void clean() {
|
||||
cacheClean();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("SERVER ");
|
||||
buf.append(super.toString());
|
||||
if (isPersistent()) {
|
||||
buf.append(" - ");
|
||||
if (queue.size() > 0) {
|
||||
buf.append(queue.size());
|
||||
buf.append(" pending");
|
||||
} else {
|
||||
buf.append("idle " + ((System.currentTimeMillis() - idle) / 1000.0) + " sec");
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
abstract class HttpConnection extends Connection implements HttpRelay {
|
||||
HttpConnection(String host, int port) throws IOException {
|
||||
super(host, port);
|
||||
}
|
||||
|
||||
HttpConnection(Socket s) throws IOException {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public void sendRequest(Request request)
|
||||
throws IOException, RetryRequestException {
|
||||
request.write(getOutputStream());
|
||||
}
|
||||
|
||||
public Reply recvReply(Request request)
|
||||
throws IOException, RetryRequestException {
|
||||
Reply reply = new Reply(getInputStream());
|
||||
reply.read();
|
||||
return reply;
|
||||
}
|
||||
|
||||
public void setInputStream(InputStream in) {
|
||||
super.setInputStream(in);
|
||||
}
|
||||
|
||||
public void setOutputStream(OutputStream out) {
|
||||
super.setOutputStream(out);
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return super.getInputStream();
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream() {
|
||||
return super.getOutputStream();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface HttpRelay {
|
||||
void sendRequest(Request request) throws IOException, RetryRequestException;
|
||||
|
||||
Reply recvReply(Request request) throws IOException, RetryRequestException;
|
||||
|
||||
void close();
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Mark Boyns
|
||||
*/
|
||||
class Https extends HttpConnection {
|
||||
boolean proxy = false;
|
||||
|
||||
Https(String host, int port) throws IOException {
|
||||
super(host, port);
|
||||
}
|
||||
|
||||
Https(String host, int port, boolean isProxy) throws IOException {
|
||||
this(host, port);
|
||||
proxy = isProxy;
|
||||
}
|
||||
|
||||
public void sendRequest(Request request)
|
||||
throws IOException, RetryRequestException {
|
||||
if (proxy) {
|
||||
super.sendRequest(request);
|
||||
} else {
|
||||
/* nothing */
|
||||
}
|
||||
}
|
||||
|
||||
public Reply recvReply(Request request)
|
||||
throws IOException, RetryRequestException {
|
||||
Reply reply = new Reply(getInputStream());
|
||||
if (proxy) {
|
||||
reply.read();
|
||||
} else {
|
||||
reply.statusLine = "HTTP/1.0 200 Connection established";
|
||||
reply.setHeaderField("Proxy-agent", "ASDec");
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
/**
|
||||
* A wrapper around java.lang.String to have case-insensitive
|
||||
* hashCode and equals methods.
|
||||
*
|
||||
* @author Mark Boyns
|
||||
* @see String
|
||||
*/
|
||||
class Key {
|
||||
private String name = null;
|
||||
|
||||
/**
|
||||
* Create a Key.
|
||||
*/
|
||||
Key(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a lowercase hashCode.
|
||||
*/
|
||||
public int hashCode() {
|
||||
String s = name.toLowerCase();
|
||||
return s.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a lowercase equals.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
return name.equalsIgnoreCase(obj.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the key.
|
||||
*/
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class Main {
|
||||
public static int port = 55555;
|
||||
public static final String REPLACEMENTSFILE = "." + File.separator + "config" + File.separator + "replacements.ini";
|
||||
public static boolean DEBUG_MODE = false;
|
||||
|
||||
|
||||
public static void enterToContinue() {
|
||||
Scanner keyIn = new Scanner(System.in);
|
||||
System.out.print("Press the enter key to continue");
|
||||
keyIn.nextLine();
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i].toLowerCase().equals("--help")) {
|
||||
System.out.println("JPEXS Replacement Proxy");
|
||||
System.out.println("-----------------------");
|
||||
System.out.println("Replacements list is read from \"" + REPLACEMENTSFILE + "\" file.");
|
||||
System.out.println("Optional commandline parameters:");
|
||||
System.out.println(" -d");
|
||||
System.out.println(" Print debug info to console ");
|
||||
System.out.println(" -p<NUMBER>");
|
||||
System.out.println(" Set proxy port to <NUMBER>. Default is 55555.");
|
||||
System.exit(0);
|
||||
}
|
||||
if (args[i].toLowerCase().equals("-d")) {
|
||||
System.out.println("DEBUG mode ON");
|
||||
DEBUG_MODE = true;
|
||||
}
|
||||
if (args[i].toLowerCase().startsWith("-p")) {
|
||||
try {
|
||||
port = Integer.parseInt(args[i].substring(2));
|
||||
System.out.println("PORT set to " + port);
|
||||
} catch (NumberFormatException ex) {
|
||||
System.out.println("Invalit port, reset to " + port);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
List<Replacement> replacements = new ArrayList<Replacement>();
|
||||
if ((new File(REPLACEMENTSFILE)).exists()) {
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(new FileReader(REPLACEMENTSFILE));
|
||||
String s = "";
|
||||
while ((s = br.readLine()) != null) {
|
||||
String fileName = br.readLine();
|
||||
if (fileName == null) break;
|
||||
fileName = fileName.replaceAll("[\\\\/]", File.separator);
|
||||
Replacement r = new Replacement(s, fileName);
|
||||
if (DEBUG_MODE) {
|
||||
System.out.println("Added Replacement: " + r.urlPattern + " => " + r.targetFile);
|
||||
}
|
||||
replacements.add(r);
|
||||
}
|
||||
br.close();
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
} else {
|
||||
if (DEBUG_MODE) {
|
||||
System.out.println("WARNING:REPLACEMENTS FILE NOT FOUND.");
|
||||
}
|
||||
}
|
||||
Server.startServer(port, replacements, new ArrayList<String>(), new CatchedListener() {
|
||||
/**
|
||||
* Method called when specified contentType is received
|
||||
*
|
||||
* @param contentType Content type
|
||||
* @param url URL of the method
|
||||
* @param data Data stream
|
||||
*/
|
||||
public void catched(String contentType, String url, InputStream data) {
|
||||
|
||||
}
|
||||
}, new ReplacedListener() {
|
||||
public void replaced(Replacement replacement, String url, String contentType) {
|
||||
if (DEBUG_MODE) {
|
||||
System.out.println("REPLACED:" + url + " (Content-type:" + contentType + ") WITH FILE " + replacement.targetFile);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PushbackInputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Abstract class to represent message headers.
|
||||
*
|
||||
* @author Mark Boyns
|
||||
*/
|
||||
public abstract class Message {
|
||||
/**
|
||||
* Hashtable used to store message headers.
|
||||
*/
|
||||
private Hashtable headers = new Hashtable(33);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
String statusLine = null;
|
||||
|
||||
public String readLine(InputStream in) throws IOException {
|
||||
char buf[] = new char[128];
|
||||
int offset = 0;
|
||||
int ch;
|
||||
|
||||
for (; ;) {
|
||||
ch = in.read();
|
||||
if (ch == -1 || ch == '\n') {
|
||||
break;
|
||||
} else if (ch == '\r') {
|
||||
int tmpch = in.read();
|
||||
if (tmpch != '\n') {
|
||||
if (!(in instanceof PushbackInputStream)) {
|
||||
in = new PushbackInputStream(in);
|
||||
}
|
||||
((PushbackInputStream) in).unread(tmpch);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
if (offset == buf.length) {
|
||||
char tmpbuf[] = buf;
|
||||
buf = new char[tmpbuf.length * 2];
|
||||
System.arraycopy(tmpbuf, 0, buf, 0, offset);
|
||||
}
|
||||
buf[offset++] = (char) ch;
|
||||
}
|
||||
}
|
||||
return String.copyValueOf(buf, 0, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read headers and store them in the hashtable.
|
||||
*/
|
||||
void readHeaders(InputStream in) throws IOException {
|
||||
int i;
|
||||
Key key = null;
|
||||
|
||||
for (; ;) {
|
||||
String s = readLine(in);
|
||||
if (s == null) {
|
||||
break;
|
||||
}
|
||||
i = s.indexOf(':');
|
||||
if (i == -1) {
|
||||
/* end of header */
|
||||
if (s.length() == 0) {
|
||||
break;
|
||||
}
|
||||
/* multi-line headers */
|
||||
else if (key != null
|
||||
&& (s.startsWith(" ") || s.startsWith("\t"))) {
|
||||
int index = getHeaderValueCount(key.toString());
|
||||
index--;
|
||||
Vector v = (Vector) headers.get(key);
|
||||
v.setElementAt(v.elementAt(index) + "\n" + s, index);
|
||||
}
|
||||
} else {
|
||||
key = new Key(s.substring(0, i));
|
||||
Vector v;
|
||||
if (headers.containsKey(key)) {
|
||||
v = (Vector) headers.get(key);
|
||||
} else {
|
||||
v = new Vector();
|
||||
}
|
||||
v.addElement(s.substring(i + 1).trim());
|
||||
headers.put(key, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int headerCount() {
|
||||
return headers.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Status line.
|
||||
*/
|
||||
public void setStatusLine(String l) {
|
||||
statusLine = l;
|
||||
}
|
||||
|
||||
public int getHeaderValueCount(String name) {
|
||||
Vector v = (Vector) headers.get(new Key(name));
|
||||
return v.size();
|
||||
}
|
||||
|
||||
public String getHeaderField(String name) {
|
||||
return getHeaderField(name, 0);
|
||||
}
|
||||
|
||||
public String getHeaderField(String name, int index) {
|
||||
Vector v = (Vector) headers.get(new Key(name));
|
||||
if (v == null) {
|
||||
return null;
|
||||
}
|
||||
return (String) v.elementAt(index);
|
||||
}
|
||||
|
||||
public void setHeaderField(String name, String value) {
|
||||
setHeaderField(name, value, 0);
|
||||
}
|
||||
|
||||
public void setHeaderField(String name, String value, int index) {
|
||||
Vector v;
|
||||
Key key = new Key(name);
|
||||
|
||||
if (headers.containsKey(key)) {
|
||||
v = (Vector) headers.get(key);
|
||||
} else {
|
||||
v = new Vector();
|
||||
if (index == 0) {
|
||||
v.addElement("");
|
||||
}
|
||||
headers.put(key, v);
|
||||
}
|
||||
v.setElementAt(value, index);
|
||||
}
|
||||
|
||||
public void setHeaderField(String name, int value) {
|
||||
setHeaderField(name, value, 0);
|
||||
}
|
||||
|
||||
public void setHeaderField(String name, int value, int index) {
|
||||
setHeaderField(name, new Integer(value).toString(), index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all header fields with the give name to the
|
||||
* specified value.
|
||||
*/
|
||||
public void setHeaderFields(String name, String value) {
|
||||
Vector v;
|
||||
Key key = new Key(name);
|
||||
|
||||
v = (Vector) headers.get(key);
|
||||
if (v != null) {
|
||||
for (int i = 0; i < v.size(); i++) {
|
||||
v.setElementAt(value, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void appendHeaderField(String name, String value) {
|
||||
appendHeaderField(name, value, 0);
|
||||
}
|
||||
|
||||
public void appendHeaderField(String name, String value, int index) {
|
||||
setHeaderField(name, getHeaderField(name, index) + value, index);
|
||||
}
|
||||
|
||||
public void removeHeaderField(String name) {
|
||||
headers.remove(new Key(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not a header exists.
|
||||
*
|
||||
* @param name header name
|
||||
*/
|
||||
public boolean containsHeaderField(String name) {
|
||||
return headers.containsKey(new Key(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an Enumeration of Strings
|
||||
*/
|
||||
public Enumeration getHeaders() {
|
||||
Vector v = new Vector();
|
||||
|
||||
for (Enumeration e = headers.keys(); e.hasMoreElements();) {
|
||||
v.addElement(e.nextElement().toString());
|
||||
}
|
||||
|
||||
return v.elements();
|
||||
}
|
||||
|
||||
private final static byte[] COLON_SPACE = ": ".getBytes();
|
||||
private final static byte[] CRLF = "\r\n".getBytes();
|
||||
|
||||
private ByteArray toByteArray(byte[] sep) {
|
||||
ByteArray buf = new ByteArray();
|
||||
Key key;
|
||||
String value;
|
||||
Vector v;
|
||||
int i = 0;
|
||||
|
||||
buf.append(statusLine);
|
||||
buf.append(sep);
|
||||
|
||||
for (Enumeration e = headers.keys(); e.hasMoreElements();) {
|
||||
key = (Key) e.nextElement();
|
||||
v = (Vector) headers.get(key);
|
||||
for (i = 0; i < v.size(); i++) {
|
||||
buf.append(key.toString());
|
||||
buf.append(COLON_SPACE);
|
||||
buf.append(v.elementAt(i).toString());
|
||||
buf.append(sep);
|
||||
}
|
||||
}
|
||||
buf.append(sep);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
private ByteArray toByteArray() {
|
||||
return toByteArray(CRLF);
|
||||
}
|
||||
|
||||
private ByteArray toByteArray(String sep) {
|
||||
return toByteArray(sep.getBytes());
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return toByteArray().toString();
|
||||
}
|
||||
|
||||
public String toString(String sep) {
|
||||
return toByteArray(sep).toString();
|
||||
}
|
||||
|
||||
public void write(OutputStream out)
|
||||
throws IOException {
|
||||
toByteArray().writeTo(out);
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
public interface ReplacedListener {
|
||||
public void replaced(Replacement replacement, String url, String contentType);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Replacement of URL with local file
|
||||
*/
|
||||
public class Replacement {
|
||||
|
||||
/**
|
||||
* URL pattern, can contain * wild-cards
|
||||
*/
|
||||
public String urlPattern;
|
||||
/**
|
||||
* Filename to replace content with
|
||||
*/
|
||||
public String targetFile;
|
||||
/**
|
||||
* Date of last accesing this url
|
||||
*/
|
||||
public Calendar lastAccess;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param urlPattern URL pattern, can contain * wild-cards
|
||||
* @param targetFile Filename to replace content with
|
||||
*/
|
||||
public Replacement(String urlPattern, String targetFile) {
|
||||
this.urlPattern = urlPattern;
|
||||
this.targetFile = targetFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when urlPattern matches specified url
|
||||
*
|
||||
* @param url Url to test match
|
||||
* @return True when matches
|
||||
*/
|
||||
public boolean matches(String url) {
|
||||
String pat = Pattern.quote(urlPattern);
|
||||
pat = pat.replace("*", "\\E.*\\Q");
|
||||
return Pattern.matches(pat, url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the object.
|
||||
*
|
||||
* @return a string representation of the object.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
|
||||
|
||||
if (lastAccess == null) {
|
||||
return " " + urlPattern;
|
||||
} else {
|
||||
return format.format(lastAccess.getTime()) + " " + urlPattern;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.SequenceInputStream;
|
||||
import java.util.Hashtable;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* @author Mark Boyns
|
||||
*/
|
||||
public class Reply extends Message {
|
||||
InputStream in = null;
|
||||
int statusCode = -1;
|
||||
|
||||
public Reply() {
|
||||
}
|
||||
|
||||
public Reply(InputStream in) {
|
||||
setContent(in);
|
||||
}
|
||||
|
||||
public void setContent(InputStream in) {
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
public InputStream getContent() {
|
||||
return in;
|
||||
}
|
||||
|
||||
void read() throws IOException {
|
||||
if (in != null) {
|
||||
read(in);
|
||||
}
|
||||
}
|
||||
|
||||
void read(InputStream in) throws IOException {
|
||||
statusLine = readLine(in);
|
||||
if (statusLine == null || statusLine.length() == 0) {
|
||||
throw new IOException("Missing HTTP status line");
|
||||
}
|
||||
|
||||
/* Look for HTTP/0.9 */
|
||||
if (!statusLine.startsWith("HTTP")) {
|
||||
/* Put back the line */
|
||||
if (this.in != null) {
|
||||
String putback = new String(statusLine + "\n");
|
||||
this.in = new SequenceInputStream(new ByteArrayInputStream(putback.getBytes("utf8")), in);
|
||||
}
|
||||
/* Fake a status line and upgrade to HTTP/1.0 */
|
||||
statusLine = "HTTP/1.0 200 OK";
|
||||
return;
|
||||
}
|
||||
|
||||
readHeaders(in);
|
||||
int code = getStatusCode();
|
||||
|
||||
/* RFC 2068: 204 and 304 MUST NOT contain a message body. */
|
||||
switch (code) {
|
||||
case 204: /* No Content */
|
||||
case 304: /* Not Modified */
|
||||
/* Ignore the message body if it exists */
|
||||
if (containsHeaderField("Content-length")) {
|
||||
int contentLength = 0;
|
||||
try {
|
||||
contentLength = Integer.parseInt(getHeaderField("Content-length"));
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
}
|
||||
int n;
|
||||
byte buffer[] = new byte[8192];
|
||||
while ((n = in.read(buffer, 0, buffer.length)) > 0) {
|
||||
/* ignore */
|
||||
}
|
||||
removeHeaderField("Content-length");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasContent() {
|
||||
switch (getStatusCode()) {
|
||||
case 204:
|
||||
case 304:
|
||||
return false;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
StringTokenizer st = new StringTokenizer(statusLine);
|
||||
String protocol = (String) st.nextToken();
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public int getStatusCode() {
|
||||
if (statusCode == -1) {
|
||||
StringTokenizer st = new StringTokenizer(statusLine);
|
||||
String protocol = (String) st.nextToken();
|
||||
String status = (String) st.nextToken();
|
||||
|
||||
try {
|
||||
statusCode = Integer.parseInt(status);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
statusCode = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
private Hashtable headerParser(String header) {
|
||||
Hashtable table = new Hashtable();
|
||||
String type = getHeaderField(header);
|
||||
if (type == null) {
|
||||
return table;
|
||||
}
|
||||
|
||||
StringTokenizer st = new StringTokenizer(type, ";");
|
||||
int count = 0;
|
||||
while (st.hasMoreTokens()) {
|
||||
String token = st.nextToken();
|
||||
token = token.trim();
|
||||
String name;
|
||||
String value;
|
||||
int i = token.indexOf('=');
|
||||
if (i != -1) {
|
||||
name = token.substring(0, i);
|
||||
value = token.substring(i + 1);
|
||||
} else {
|
||||
name = token;
|
||||
value = "";
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
table.put(header, name);
|
||||
} else {
|
||||
table.put(name, value);
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
Hashtable table = headerParser("Content-type");
|
||||
return (String) table.get("Content-type");
|
||||
}
|
||||
|
||||
public String getBoundary() {
|
||||
Hashtable table = headerParser("Content-type");
|
||||
return (String) table.get("boundary");
|
||||
}
|
||||
|
||||
public String getTransferEncoding() {
|
||||
Hashtable table = headerParser("Transfer-Encoding");
|
||||
return (String) table.get("Transfer-Encoding");
|
||||
}
|
||||
|
||||
public int getChunkSize(InputStream in) throws IOException {
|
||||
String line = readLine(in);
|
||||
line = line.trim(); /* apache can have trailing spaces */
|
||||
int size = -1;
|
||||
try {
|
||||
size = Integer.valueOf(line, 16).intValue();
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public void getChunkedFooter(InputStream in) throws IOException {
|
||||
for (; ;) {
|
||||
String line = readLine(in);
|
||||
if (line == null) {
|
||||
break;
|
||||
}
|
||||
int i = line.indexOf(':');
|
||||
if (i == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setStatusLine(String line) {
|
||||
this.statusLine = line;
|
||||
}
|
||||
|
||||
public static Reply createRedirect(String url) {
|
||||
Reply r = new Reply();
|
||||
r.setStatusLine("HTTP/1.0 302 Moved Temporarily");
|
||||
r.setHeaderField("Location", url);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Vector;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author Mark Boyns
|
||||
*/
|
||||
public class Request extends Message {
|
||||
private static Pattern httpRegex;
|
||||
private String command = null;
|
||||
private String url = null;
|
||||
private String protocol = null;
|
||||
private byte[] data = null;
|
||||
private Hashtable log;
|
||||
private Vector logHeaders;
|
||||
private Client client;
|
||||
|
||||
static {
|
||||
httpRegex = Pattern.compile("^(http|https):", Pattern.CASE_INSENSITIVE);
|
||||
}
|
||||
|
||||
public Request(Client client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
void read(InputStream in) throws IOException {
|
||||
statusLine = readLine(in);
|
||||
if (statusLine == null || statusLine.length() == 0) {
|
||||
throw new IOException("Empty request");
|
||||
}
|
||||
|
||||
StringTokenizer st = new StringTokenizer(statusLine);
|
||||
command = (String) st.nextToken();
|
||||
url = (String) st.nextToken();
|
||||
protocol = (String) st.nextToken();
|
||||
|
||||
if (!url.startsWith("http")) {
|
||||
Matcher match = httpRegex.matcher(url);
|
||||
if (match.matches()) {
|
||||
url = url.substring(match.start(),
|
||||
match.end()).toLowerCase()
|
||||
+ url.substring(match.end());
|
||||
}
|
||||
}
|
||||
|
||||
readHeaders(in);
|
||||
|
||||
if ("POST".equals(command) || "PUT".equals(command)) {
|
||||
try {
|
||||
int n = Integer.parseInt(getHeaderField("Content-length"));
|
||||
data = new byte[n];
|
||||
int offset = 0;
|
||||
while (offset < data.length) {
|
||||
n = in.read(data, offset, data.length - offset);
|
||||
if (n < 0) {
|
||||
throw new IOException("Not enough " + command + " data");
|
||||
}
|
||||
offset += n;
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
System.out.println("Malformed or missing " + command + " Content-length");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void write(OutputStream out)
|
||||
throws IOException {
|
||||
super.write(out);
|
||||
if (data != null) {
|
||||
out.write(data);
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
|
||||
public String getRequest() {
|
||||
return statusLine;
|
||||
}
|
||||
|
||||
public String getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
public void setCommand(String command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
public String getURL() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setURL(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public void setProtocol(String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
String url = getURL();
|
||||
String s;
|
||||
|
||||
if (url.startsWith("http://")) {
|
||||
s = url.substring(7, url.indexOf('/', 7));
|
||||
} else {
|
||||
s = url;
|
||||
}
|
||||
|
||||
int at = s.indexOf('@');
|
||||
if (at != -1) {
|
||||
s = s.substring(at + 1);
|
||||
}
|
||||
|
||||
if (s.indexOf(':') != -1) {
|
||||
return s.substring(0, s.indexOf(':'));
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
int port = 80;
|
||||
String url = getURL();
|
||||
String s;
|
||||
|
||||
if (url.startsWith("http://")) {
|
||||
s = url.substring(7, url.indexOf('/', 7));
|
||||
} else {
|
||||
s = url;
|
||||
}
|
||||
|
||||
int at = s.indexOf('@');
|
||||
if (at != -1) {
|
||||
s = s.substring(at + 1);
|
||||
}
|
||||
|
||||
if (s.indexOf(':') != -1) {
|
||||
try {
|
||||
port = Integer.parseInt(s.substring(s.indexOf(':') + 1));
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
System.out.println("Invalid port in " + url);
|
||||
}
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
return new String(data);
|
||||
}
|
||||
|
||||
public byte[] getDataBytes() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
|
||||
public String getPath() {
|
||||
String str = getURL();
|
||||
int pos = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
pos = str.indexOf('/', pos);
|
||||
pos++;
|
||||
}
|
||||
pos--;
|
||||
return str.substring(pos);
|
||||
}
|
||||
|
||||
public String getDocument() {
|
||||
String path = getPath();
|
||||
int n = path.lastIndexOf('/');
|
||||
if (n == path.length() - 1) {
|
||||
n = path.lastIndexOf('/', n - 1);
|
||||
}
|
||||
if (n < 0) {
|
||||
return "/";
|
||||
} else {
|
||||
return path.substring(n + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String getQueryString() {
|
||||
String path = getPath();
|
||||
int n = path.indexOf('?');
|
||||
if (n < 0) {
|
||||
return null;
|
||||
}
|
||||
return path.substring(n + 1);
|
||||
}
|
||||
|
||||
public synchronized void addLogEntry(String header,
|
||||
String message) {
|
||||
if (log == null) {
|
||||
log = new Hashtable();
|
||||
logHeaders = new Vector();
|
||||
}
|
||||
|
||||
Vector v = (Vector) log.get(header);
|
||||
if (log.get(header) == null) {
|
||||
v = new Vector();
|
||||
log.put(header, v);
|
||||
logHeaders.addElement(header);
|
||||
}
|
||||
v.addElement(message);
|
||||
}
|
||||
|
||||
public Enumeration getLogHeaders() {
|
||||
return logHeaders != null ? logHeaders.elements() : null;
|
||||
}
|
||||
|
||||
public Enumeration getLogEntries(String header) {
|
||||
return log != null ? ((Vector) log.get(header)).elements() : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
class RetryRequestException extends Exception {
|
||||
RetryRequestException() {
|
||||
super();
|
||||
}
|
||||
|
||||
RetryRequestException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Proxy server
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class Server extends Thread {
|
||||
private ServerSocket ssocket = null;
|
||||
private boolean stoppped = false;
|
||||
private List<Replacement> replacements;
|
||||
private static Server server;
|
||||
private List<String> catchedContentTypes;
|
||||
private CatchedListener catchedListener;
|
||||
private int port;
|
||||
private ReplacedListener replacedListener;
|
||||
|
||||
private Server(int port, List<Replacement> replacements, List<String> catchedContentTypes, CatchedListener catchedListener, ReplacedListener replacedListener) {
|
||||
this.replacements = replacements;
|
||||
this.catchedContentTypes = catchedContentTypes;
|
||||
this.catchedListener = catchedListener;
|
||||
this.replacedListener = replacedListener;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
private void stopRun() {
|
||||
stoppped = true;
|
||||
if (ssocket != null) {
|
||||
try {
|
||||
ssocket.close();
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts proxy server
|
||||
*
|
||||
* @param port Listening port
|
||||
* @param replacements List of replacements
|
||||
* @param catchedContentTypes Content types to sniff
|
||||
* @param catchedListener Catched listener
|
||||
*/
|
||||
public static void startServer(int port, List<Replacement> replacements, List<String> catchedContentTypes, CatchedListener catchedListener, ReplacedListener replacedListener) {
|
||||
stopServer();
|
||||
server = new Server(port, replacements, catchedContentTypes, catchedListener, replacedListener);
|
||||
//WorkerThread.assignThread(server, "Proxy server");
|
||||
server.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops proxy server
|
||||
*/
|
||||
public static void stopServer() {
|
||||
if (server != null) server.stopRun();
|
||||
server = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the server
|
||||
*/
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
ssocket = new ServerSocket(port);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Cannot bind to port");
|
||||
return;
|
||||
}
|
||||
for (; ;) {
|
||||
try {
|
||||
Socket sock = ssocket.accept();
|
||||
Handler handler = new Handler(sock, replacements, catchedContentTypes, catchedListener, replacedListener);
|
||||
WorkerThread.assignThread(handler, "Proxy handler");
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
if (stoppped)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
// Copyright (c) 1999 Brian Wellington ([email protected])
|
||||
// Portions Copyright (c) 1999 Network Associates, Inc.
|
||||
|
||||
package com.jpexs.proxy;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* An extension of a Thread that uses threads from a pool, rather than
|
||||
* allocating a new thread for each assigned task.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public class WorkerThread extends Thread {
|
||||
|
||||
private Runnable task;
|
||||
private String name;
|
||||
|
||||
private static int nactive = 0;
|
||||
private static Vector list = new Vector();
|
||||
private static int max = 10;
|
||||
private static long lifetime = 900 * 1000; /* 15 minute default */
|
||||
|
||||
private WorkerThread() {
|
||||
setDaemon(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the lifetime of an idle WorkerThread (in ms). A WorkerThread
|
||||
* will remain on the idle list for this much time before exiting. This
|
||||
* does not affect WorkerThreads currently idling.
|
||||
*/
|
||||
synchronized static void
|
||||
setLifetime(long time) {
|
||||
lifetime = time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of WorkerThreads that can exist at any given
|
||||
* time. If this value is decreased below the current number of
|
||||
* WorkerThreads, this will not take effect immediately.
|
||||
*/
|
||||
synchronized static void
|
||||
setMaxThreads(int maxThreads) {
|
||||
max = maxThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a WorkerThread to which a task can be assigned. If an idle
|
||||
* WorkerThread is present, it is removed from the idle list and returned.
|
||||
* If not, and the maximum number of WorkerThreads has not been reached,
|
||||
* a new WorkerThread is created. If the maximum number has been reached,
|
||||
* this blocks until a WorkerThread is free.
|
||||
*/
|
||||
static WorkerThread
|
||||
getThread() {
|
||||
WorkerThread t;
|
||||
synchronized (list) {
|
||||
if (list.size() > 0) {
|
||||
t = (WorkerThread) list.firstElement();
|
||||
list.removeElement(t);
|
||||
} else if (nactive >= max) {
|
||||
while (true) {
|
||||
try {
|
||||
list.wait();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
}
|
||||
if (list.size() == 0)
|
||||
continue;
|
||||
t = (WorkerThread) list.firstElement();
|
||||
list.removeElement(t);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
t = new WorkerThread();
|
||||
nactive++;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a task to a WorkerThread
|
||||
*
|
||||
* @param task The task to be run
|
||||
* @param name The name of the task
|
||||
*/
|
||||
public static void
|
||||
assignThread(Runnable task, String name) {
|
||||
while (true) {
|
||||
try {
|
||||
WorkerThread t = getThread();
|
||||
synchronized (t) {
|
||||
t.task = task;
|
||||
t.name = name;
|
||||
if (!t.isAlive())
|
||||
t.start();
|
||||
else
|
||||
t.notify();
|
||||
}
|
||||
return;
|
||||
}
|
||||
catch (IllegalThreadStateException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the task
|
||||
*/
|
||||
synchronized public void
|
||||
run() {
|
||||
while (true) {
|
||||
setName(name);
|
||||
try {
|
||||
task.run();
|
||||
}
|
||||
catch (Throwable t) {
|
||||
System.err.println(t);
|
||||
}
|
||||
setName("idle thread");
|
||||
synchronized (list) {
|
||||
list.addElement(this);
|
||||
if (nactive >= max)
|
||||
list.notify();
|
||||
nactive--;
|
||||
}
|
||||
task = null;
|
||||
try {
|
||||
wait(lifetime);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
}
|
||||
if (task == null) {
|
||||
list.removeElement(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
Version 0.9.5 - Java Reflection Completions additions
|
||||
* Configuration class overhaul. Each kit now has its own COnfiguration file
|
||||
which merges the superclass(es) Configurations.
|
||||
* Usable Reflect Completions Dialog (Java with F1 or Menu)
|
||||
* Java ENTER key responds properly to multi line comments
|
||||
* Font can be changed for each Kit
|
||||
* Kits for XHTML and Xpath added. XHTML has a simple Preview Action.
|
||||
* Added Execute Script to JacaScript (can also be used for Groovy if Groovy
|
||||
Scripting support is installed properly).
|
||||
* Hotkeys for actions are displayed in Popup Menus
|
||||
* Word Completion action can also do CamelCase matches
|
||||
* Smart Home Action (and Smart Home Extend Selection)
|
||||
* Enhanced JavaScript support. Issue 115
|
||||
* Better Undo grouping
|
||||
* Replace DIalog ENhancement. Only for updatedable editors and added single replace.
|
||||
* Added append method to SyntaxDocument
|
||||
* Fixed Issue 130 - Compound Undo on multiple lines.
|
||||
Version 0.9.4 - IntelliSense additions
|
||||
* Adding IntelliSense to Java with simple List of selectable keywords
|
||||
* Added Toggle Comment Actions using Control SLASH
|
||||
* Fixed Issue 47.
|
||||
* Added Clojure, Scala, DOS Batch and 'nix bash support
|
||||
* Added Configurable Popup menus with default Tango Desktop icons
|
||||
* Added configurable format for the CaretMonitor class
|
||||
* Toggle Comments Action selects the lines affected after being performed
|
||||
* Added multi-line support in ActionUtils.insertMagicSTring method.
|
||||
* GotoLine dialog responds to ESC key
|
||||
Version 0.9.3 - Start of scripts for the document:
|
||||
* Added new methods getLine() to SyntaxDocument
|
||||
* SyntaxDocument getIndexOf methods deprecated, use getMatchers instead
|
||||
* Added Line Numbering to Java
|
||||
* Added CaretMonitor Class
|
||||
* Merged Find And Replace dialogs into one.
|
||||
* Created SyntaxComponent interface and have all UI components implement
|
||||
that interface. DefaultSyntaxKit will use config.properties class to
|
||||
dynamically install these components.
|
||||
* Added Right Margin option and Single Color Selection Options
|
||||
* Added Python, C and C++ Support
|
||||
* Added Ruby Syntax Support
|
||||
* Fixed Issue 37 (NPE for LineNumbersRuler)
|
||||
* Fixed Issue 39 (Highlighting Tokens overrides selection highlights)
|
||||
* Fixed some JavaDoc comments.
|
||||
* Fixed Line Numbers being displayed for the height of the editor and now
|
||||
just for the actual available lines.
|
||||
* Fixed Margin typo in all project. Issue 43
|
||||
* Changing Actions to be more configurable:
|
||||
* SyntaxActions renamed to ActionUtils
|
||||
* Removed all inner classes from SyntaxActions
|
||||
* Will create new SyntaxAction interface that will allow dynamic addition
|
||||
actions (in the addKeyActions of DefaultSyntaxKit
|
||||
* Added Text AA property to SyntaxView
|
||||
Version 0.9.2:
|
||||
* Fixing Java Indentation and Un-Indentattion Actions
|
||||
* Added and used (in the Tester) clearUndoes on the SyntaxDocument
|
||||
* Added Basic JFlex Syntax
|
||||
* Added getContentTypes to DefaultSyntaxKit to get all registered
|
||||
ContentTypes. This is now also used in the SyntaxTester instead of
|
||||
hardcoding the types.
|
||||
* Cleanup and optimization of Lexers by removing duplicate Java Code
|
||||
(replaced with Regex OR)
|
||||
* Removed calls to deprecated calls in SyntaxView
|
||||
* Modified the SyntaxDOcument to override the fireXXX methods and parse
|
||||
the document at that time instead of overriding the inserUpdate method.
|
||||
This fixes issue 24.
|
||||
* Added Groovy GString expression highlights
|
||||
* Removed getLanguages method from Lexer interface and implementations.
|
||||
* Added WARNING and ERROR TokenTypes and added their default styles.
|
||||
* Moved Keymaps and install methods to SyntaxKits instead of the Lexers
|
||||
* Removed deprecated methods from SyntaxActions class
|
||||
* Split SyntaxActions into new package and moved inner classes to the new
|
||||
package
|
||||
* Added Token HighLighter to Java
|
||||
* Added Pairs Highlighter to Java
|
||||
* Token class made immutable (all final fields)
|
||||
* Added Find and Replace Dialogs and Action to Java (mapped to C-F and
|
||||
C-H )
|
||||
* Added pair matching to XML tags
|
||||
* Added CDATA matching and pair highlights for XML
|
||||
* Added Comment Pair Highlighting in XML
|
||||
* Fixed highlighting with selections so the selection always appears
|
||||
* Merged Find and Replace Dialogs into one
|
||||
* Fixed issue 33 (undable to add new line after final closing brace for
|
||||
Java)
|
||||
* Added Groovy Multi-Line strings and fixed Comments as Regex issue.
|
||||
* Fixes to empty find text field causing NPE
|
||||
Version 0.9.1
|
||||
* Fixed empty strings in XML syntax Issue 29
|
||||
* Fixed TAL lexer using incorrect package name
|
||||
Version 0.9.0
|
||||
* Initial version after major overhaul
|
||||
@@ -0,0 +1,11 @@
|
||||
# Java Regex Lexer:
|
||||
COMMENT=/\\*(?:.|[\\n\\r])*?\\*/|//.*
|
||||
STRING=\"((?:\\\")|.*)?\"
|
||||
IDENTIFIER=[a-z][a-zA-Z0-9_]*
|
||||
TYPE=[A-Z_]\\w*
|
||||
KEYWORD=abstract|boolean|break|byte|case|catch|char|class|const|continue|\
|
||||
do|double|enum|else|extends|final|finally|float|for|default|implements|import|\
|
||||
instanceof|int|interface|long|native|new|goto|if|public|short|super|switch|\
|
||||
synchronized|package|private|protected|transient|return|void|static|while|this|\
|
||||
throw|throws|try|volatile|strictfp|true|false|null
|
||||
TYPE3=@\\w+
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<actions>
|
||||
<action>
|
||||
<actionName>run</actionName>
|
||||
<goals>
|
||||
<goal>process-classes</goal>
|
||||
<goal>org.codehaus.mojo:exec-maven-plugin:1.1:exec</goal>
|
||||
</goals>
|
||||
<properties>
|
||||
<exec.args>-classpath %classpath jsyntaxpane.SyntaxTester</exec.args>
|
||||
<exec.executable>java</exec.executable>
|
||||
</properties>
|
||||
</action>
|
||||
<action>
|
||||
<actionName>debug</actionName>
|
||||
<goals>
|
||||
<goal>process-classes</goal>
|
||||
<goal>org.codehaus.mojo:exec-maven-plugin:1.1:exec</goal>
|
||||
</goals>
|
||||
<properties>
|
||||
<exec.args>-Xdebug -Djava.compiler=none -Xnoagent -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath jsyntaxpane.SyntaxTester</exec.args>
|
||||
<jpda.listen>true</jpda.listen>
|
||||
<exec.executable>java</exec.executable>
|
||||
</properties>
|
||||
</action>
|
||||
<action>
|
||||
<actionName>profile</actionName>
|
||||
<packagings>
|
||||
<packaging>jar</packaging>
|
||||
</packagings>
|
||||
<goals>
|
||||
<goal>process-classes</goal>
|
||||
<goal>org.codehaus.mojo:exec-maven-plugin:1.1:exec</goal>
|
||||
</goals>
|
||||
<properties>
|
||||
<exec.args>${profiler.args} -classpath %classpath jsyntaxpane.SyntaxTester</exec.args>
|
||||
<profiler.action>profile</profiler.action>
|
||||
<exec.executable>${profiler.java}</exec.executable>
|
||||
</properties>
|
||||
</action>
|
||||
</actions>
|
||||
@@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>jsyntaxpane</groupId>
|
||||
<artifactId>jsyntaxpane</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>0.9.5</version>
|
||||
<name>jsyntaxpane</name>
|
||||
<description>A very simple to use and extend JEditorKit that supports few languages. The main goal is to make it easy to have nice looking Java Swing Editors with support for Syntax Highlighting.</description>
|
||||
<url>http://jsyntaxpane.googlecode.com/</url>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<scm>
|
||||
<url>http://jsyntaxpane.googlecode.com/svn/</url>
|
||||
</scm>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>jflex</id>
|
||||
<name>JFlex repository</name>
|
||||
<url>http://jflex.sourceforge.net/repo/</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>RELEASE</version>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>**/Thumbs.db</exclude>
|
||||
</excludes>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>jsyntaxpane.SyntaxTester</mainClass>
|
||||
<packageName>jsyntaxpane</packageName>
|
||||
<addClasspath>true</addClasspath>
|
||||
<classpathPrefix />
|
||||
</manifest>
|
||||
<manifestEntries>
|
||||
<mode>development</mode>
|
||||
<url>${pom.url}</url>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>de.jflex</groupId>
|
||||
<artifactId>maven-jflex-plugin</artifactId>
|
||||
<!--version>0.2</version-->
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>generate</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/java" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2008 Ayman Al-Sairafi [email protected]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License
|
||||
* at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package jsyntaxpane;
|
||||
|
||||
import javax.swing.event.UndoableEditEvent;
|
||||
import javax.swing.text.AbstractDocument;
|
||||
import javax.swing.text.AbstractDocument.DefaultDocumentEvent;
|
||||
import javax.swing.undo.CannotUndoException;
|
||||
import javax.swing.undo.CompoundEdit;
|
||||
import javax.swing.undo.UndoManager;
|
||||
import javax.swing.undo.UndoableEdit;
|
||||
|
||||
/**
|
||||
* A revised UndoManager that groups undos based on positions. If the change is relatively next to the
|
||||
* previous change, like when continuous typing, then the undoes are grouped together.
|
||||
*
|
||||
* This is cutomized from the
|
||||
*
|
||||
* http://www.camick.com/java/source/CompoundUndoMan.java
|
||||
*
|
||||
* from the blog:
|
||||
*
|
||||
* http://tips4java.wordpress.com/2008/10/27/compound-undo-manager/
|
||||
*
|
||||
* @author Ayman Al-Sairafi
|
||||
*/
|
||||
public class CompoundUndoMan extends UndoManager {
|
||||
|
||||
private CompoundEdit compoundEdit;
|
||||
// This allows us to start combining operations.
|
||||
// it will be reset after the first change.
|
||||
private boolean startCombine = false;
|
||||
// This holds the start of the last line edited, if edits are on multiple
|
||||
// lines, then they will not be combined.
|
||||
private int lastLine = -1;
|
||||
|
||||
public CompoundUndoMan(SyntaxDocument doc) {
|
||||
doc.addUndoableEditListener(this);
|
||||
lastLine = doc.getStartPosition().getOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whenever an UndoableEdit happens the edit will either be absorbed
|
||||
* by the current compound edit or a new compound edit will be started
|
||||
*/
|
||||
@Override
|
||||
public void undoableEditHappened(UndoableEditEvent e) {
|
||||
// Start a new compound edit
|
||||
|
||||
AbstractDocument.DefaultDocumentEvent docEvt = (DefaultDocumentEvent) e.getEdit();
|
||||
|
||||
if (compoundEdit == null) {
|
||||
compoundEdit = startCompoundEdit(e.getEdit());
|
||||
startCombine = false;
|
||||
return;
|
||||
}
|
||||
|
||||
int editLine = ((SyntaxDocument)docEvt.getDocument()).getLineNumberAt(docEvt.getOffset());
|
||||
|
||||
// Check for an incremental edit or backspace.
|
||||
// The Change in Caret position and Document length should both be
|
||||
// either 1 or -1.
|
||||
if ((startCombine || Math.abs(docEvt.getLength()) == 1) && editLine == lastLine) {
|
||||
compoundEdit.addEdit(e.getEdit());
|
||||
startCombine = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Not incremental edit, end previous edit and start a new one
|
||||
lastLine = editLine;
|
||||
|
||||
compoundEdit.end();
|
||||
compoundEdit = startCompoundEdit(e.getEdit());
|
||||
}
|
||||
|
||||
/*
|
||||
** Each CompoundEdit will store a group of related incremental edits
|
||||
** (ie. each character typed or backspaced is an incremental edit)
|
||||
*/
|
||||
private CompoundEdit startCompoundEdit(UndoableEdit anEdit) {
|
||||
// Track Caret and Document information of this compound edit
|
||||
AbstractDocument.DefaultDocumentEvent docEvt = (DefaultDocumentEvent) anEdit;
|
||||
|
||||
// The compound edit is used to store incremental edits
|
||||
|
||||
compoundEdit = new MyCompoundEdit();
|
||||
compoundEdit.addEdit(anEdit);
|
||||
|
||||
// The compound edit is added to the UndoManager. All incremental
|
||||
// edits stored in the compound edit will be undone/redone at once
|
||||
|
||||
addEdit(compoundEdit);
|
||||
|
||||
return compoundEdit;
|
||||
}
|
||||
|
||||
class MyCompoundEdit extends CompoundEdit {
|
||||
|
||||
@Override
|
||||
public boolean isInProgress() {
|
||||
// in order for the canUndo() and canRedo() methods to work
|
||||
// assume that the compound edit is never in progress
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() throws CannotUndoException {
|
||||
// End the edit so future edits don't get absorbed by this edit
|
||||
|
||||
if (compoundEdit != null) {
|
||||
compoundEdit.end();
|
||||
}
|
||||
|
||||
super.undo();
|
||||
|
||||
// Always start a new compound edit after an undo
|
||||
|
||||
compoundEdit = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start to combine the next operations together. Only the next operation is combined.
|
||||
* The flag is then automatically reset.
|
||||
*/
|
||||
public void startCombine() {
|
||||
startCombine = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,671 @@
|
||||
/*
|
||||
* Copyright 2008 Ayman Al-Sairafi [email protected]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License
|
||||
* at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package jsyntaxpane;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Container;
|
||||
import java.util.logging.Level;
|
||||
import java.awt.Font;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.ActionMap;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.InputMap;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBoxMenuItem;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JToolBar;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.text.DefaultEditorKit;
|
||||
import javax.swing.text.Document;
|
||||
import javax.swing.text.EditorKit;
|
||||
import javax.swing.text.Element;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import javax.swing.text.View;
|
||||
import javax.swing.text.ViewFactory;
|
||||
import jsyntaxpane.actions.DefaultSyntaxAction;
|
||||
import jsyntaxpane.actions.SyntaxAction;
|
||||
import jsyntaxpane.components.SyntaxComponent;
|
||||
import jsyntaxpane.util.Configuration;
|
||||
import jsyntaxpane.util.JarServiceProvider;
|
||||
|
||||
/**
|
||||
* The DefaultSyntaxKit is the main entry to SyntaxPane. To use the package, just
|
||||
* set the EditorKit of the EditorPane to a new instance of this class.
|
||||
*
|
||||
* You need to pass a proper lexer to the class.
|
||||
*
|
||||
* @author ayman
|
||||
*/
|
||||
public class DefaultSyntaxKit extends DefaultEditorKit implements ViewFactory {
|
||||
|
||||
public static final String CONFIG_CARETCOLOR = "CaretColor";
|
||||
public static final String CONFIG_SELECTION = "SelectionColor";
|
||||
public static final String CONFIG_COMPONENTS = "Components";
|
||||
public static final String CONFIG_MENU = "PopupMenu";
|
||||
public static final String CONFIG_TOOLBAR = "Toolbar";
|
||||
public static final String CONFIG_TOOLBAR_ROLLOVER = "Toolbar.Buttons.Rollover";
|
||||
public static final String CONFIG_TOOLBAR_BORDER = "Toolbar.Buttons.BorderPainted";
|
||||
public static final String CONFIG_TOOLBAR_OPAQUE = "Toolbar.Buttons.Opaque";
|
||||
public static final String CONFIG_TOOLBAR_BORDER_SIZE = "Toolbar.Buttons.BorderSize";
|
||||
private static final Pattern ACTION_KEY_PATTERN = Pattern.compile("Action\\.((\\w|-)+)");
|
||||
private static final Pattern DEFAULT_ACTION_PATTERN = Pattern.compile("(DefaultAction.((\\w|-)+)).*");
|
||||
private static Font DEFAULT_FONT;
|
||||
private static Set<String> CONTENT_TYPES = new HashSet<String>();
|
||||
private static Boolean initialized = false;
|
||||
private static Map<String, String> abbrvs;
|
||||
private static String MENU_MASK_STRING = "control ";
|
||||
private Lexer lexer;
|
||||
private static final Logger LOG = Logger.getLogger(DefaultSyntaxKit.class.getName());
|
||||
private Map<JEditorPane, List<SyntaxComponent>> editorComponents =
|
||||
new WeakHashMap<JEditorPane, List<SyntaxComponent>>();
|
||||
private Map<JEditorPane, JPopupMenu> popupMenu =
|
||||
new WeakHashMap<JEditorPane, JPopupMenu>();
|
||||
/**
|
||||
* Main Configuration of JSyntaxPane EditorKits
|
||||
*/
|
||||
private static Map<Class<? extends DefaultSyntaxKit>, Configuration> CONFIGS;
|
||||
|
||||
static {
|
||||
// we only need to initialize once.
|
||||
if (!initialized) {
|
||||
initKit();
|
||||
}
|
||||
int menuMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
|
||||
if(menuMask == KeyEvent.ALT_DOWN_MASK) {
|
||||
MENU_MASK_STRING = "alt ";
|
||||
}
|
||||
}
|
||||
private static final String ACTION_MENU_TEXT = "MenuText";
|
||||
|
||||
/**
|
||||
* Create a new Kit for the given language
|
||||
* @param lexer
|
||||
*/
|
||||
public DefaultSyntaxKit(Lexer lexer) {
|
||||
super();
|
||||
this.lexer = lexer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds UI components to the pane
|
||||
* @param editorPane
|
||||
*/
|
||||
public void addComponents(JEditorPane editorPane) {
|
||||
// install the components to the editor:
|
||||
String[] components = getConfig().getPropertyList(CONFIG_COMPONENTS);
|
||||
for (String c : components) {
|
||||
installComponent(editorPane, c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SyntaxComponent of the the given classname and installs
|
||||
* it on the pane
|
||||
* @param pane
|
||||
* @param classname
|
||||
*/
|
||||
public void installComponent(JEditorPane pane, String classname) {
|
||||
try {
|
||||
@SuppressWarnings(value = "unchecked")
|
||||
Class compClass = Class.forName(classname);
|
||||
SyntaxComponent comp = (SyntaxComponent) compClass.newInstance();
|
||||
comp.config(getConfig());
|
||||
comp.install(pane);
|
||||
if (editorComponents.get(pane) == null) {
|
||||
editorComponents.put(pane, new ArrayList<SyntaxComponent>());
|
||||
}
|
||||
editorComponents.get(pane).add(comp);
|
||||
} catch (InstantiationException ex) {
|
||||
LOG.log(Level.SEVERE, null, ex);
|
||||
} catch (IllegalAccessException ex) {
|
||||
LOG.log(Level.SEVERE, null, ex);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
LOG.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the SyntaxCOmponent with given classname that is installed
|
||||
* on the given pane, then deinstalls and removes it fom the
|
||||
* editorComponents list
|
||||
* @param pane
|
||||
* @param classname
|
||||
*/
|
||||
public void deinstallComponent(JEditorPane pane, String classname) {
|
||||
for (SyntaxComponent c : editorComponents.get(pane)) {
|
||||
if (c.getClass().getName().equals(classname)) {
|
||||
c.deinstall(pane);
|
||||
editorComponents.get(pane).remove(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the component with given classname is installed on the
|
||||
* pane.
|
||||
* @param pane
|
||||
* @param classname
|
||||
* @return true if component is installed, false otherwise
|
||||
*/
|
||||
public boolean isComponentInstalled(JEditorPane pane, String classname) {
|
||||
for (SyntaxComponent c : editorComponents.get(pane)) {
|
||||
if (c.getClass().getName().equals(classname)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the component with given classname. If component is found
|
||||
* and installed, then it is deinstalled. Otherwise a new one is
|
||||
* installed
|
||||
* @param pane
|
||||
* @param classname
|
||||
* @return true if component was installed, false if it was removed
|
||||
*/
|
||||
public boolean toggleComponent(JEditorPane pane, String classname) {
|
||||
for (SyntaxComponent c : editorComponents.get(pane)) {
|
||||
if (c.getClass().getName().equals(classname)) {
|
||||
c.deinstall(pane);
|
||||
editorComponents.get(pane).remove(c);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
installComponent(pane, classname);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a popup menu to the editorPane if needed.
|
||||
*
|
||||
* @param editorPane
|
||||
*/
|
||||
public void addPopupMenu(JEditorPane editorPane) {
|
||||
String[] menuItems = getConfig().getPropertyList(CONFIG_MENU);
|
||||
if (menuItems == null || menuItems.length == 0) {
|
||||
return;
|
||||
}
|
||||
popupMenu.put(editorPane, new JPopupMenu());
|
||||
JMenu stack = null;
|
||||
for (String menuString : menuItems) {
|
||||
|
||||
// create the Popup menu
|
||||
if (menuString.equals("-")) {
|
||||
popupMenu.get(editorPane).addSeparator();
|
||||
} else if (menuString.startsWith(">")) {
|
||||
JMenu sub = new JMenu(menuString.substring(1));
|
||||
popupMenu.get(editorPane).add(sub);
|
||||
stack = sub;
|
||||
} else if (menuString.startsWith("<")) {
|
||||
Container parent = stack.getParent();
|
||||
if (parent instanceof JMenu) {
|
||||
JMenu jMenu = (JMenu) parent;
|
||||
stack = jMenu;
|
||||
} else {
|
||||
stack = null;
|
||||
}
|
||||
} else {
|
||||
Action action = editorPane.getActionMap().get(menuString);
|
||||
if (action != null) {
|
||||
JMenuItem menuItem;
|
||||
if (action.getValue(Action.SELECTED_KEY) != null) {
|
||||
menuItem = new JCheckBoxMenuItem(action);
|
||||
} else {
|
||||
menuItem = new JMenuItem(action);
|
||||
}
|
||||
// Use our own property if it was set for the menu text
|
||||
if (action.getValue(ACTION_MENU_TEXT) != null) {
|
||||
menuItem.setText((String) action.getValue(ACTION_MENU_TEXT));
|
||||
}
|
||||
if (stack == null) {
|
||||
popupMenu.get(editorPane).add(menuItem);
|
||||
} else {
|
||||
stack.add(menuItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
editorPane.setComponentPopupMenu(popupMenu.get(editorPane));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all pop-up menu items to a Toolbar. <b>You need to call the validate method
|
||||
* on the toolbar after this is done to layout the buttons.</b>
|
||||
* Only Actions which have a SMALL_ICON property will be added to the toolbar
|
||||
* There are three Configuration Keys that affect the appearance of the added buttons:
|
||||
* CONFIG_TOOLBAR_ROLLOVER, CONFIG_TOOLBAR_BORDER, CONFIG_TOOLBAR_OPAQUE
|
||||
*
|
||||
* @param editorPane
|
||||
* @param toolbar
|
||||
*/
|
||||
public void addToolBarActions(JEditorPane editorPane, JToolBar toolbar) {
|
||||
String[] toolBarItems = getConfig().getPropertyList(CONFIG_TOOLBAR);
|
||||
if (toolBarItems == null || toolBarItems.length == 0) {
|
||||
toolBarItems = getConfig().getPropertyList(CONFIG_MENU);
|
||||
if (toolBarItems == null || toolBarItems.length == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
boolean btnRolloverEnabled = getConfig().getBoolean(CONFIG_TOOLBAR_ROLLOVER, true);
|
||||
boolean btnBorderPainted = getConfig().getBoolean(CONFIG_TOOLBAR_BORDER, false);
|
||||
boolean btnOpaque = getConfig().getBoolean(CONFIG_TOOLBAR_OPAQUE, false);
|
||||
int btnBorderSize = getConfig().getInteger(CONFIG_TOOLBAR_BORDER_SIZE, 2);
|
||||
for (String menuString : toolBarItems) {
|
||||
if (menuString.equals("-") ||
|
||||
menuString.startsWith("<") ||
|
||||
menuString.startsWith(">")) {
|
||||
toolbar.addSeparator();
|
||||
} else {
|
||||
Action action = editorPane.getActionMap().get(menuString);
|
||||
if (action != null && action.getValue(Action.SMALL_ICON) != null) {
|
||||
JButton b = toolbar.add(action);
|
||||
b.setRolloverEnabled(btnRolloverEnabled);
|
||||
b.setBorderPainted(btnBorderPainted);
|
||||
b.setOpaque(btnOpaque);
|
||||
b.setFocusable(false);
|
||||
b.setBorder(BorderFactory.createEmptyBorder(btnBorderSize,
|
||||
btnBorderSize, btnBorderSize, btnBorderSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewFactory getViewFactory() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View create(Element element) {
|
||||
return new SyntaxView(element, getConfig());
|
||||
}
|
||||
|
||||
/**
|
||||
* Install the View on the given EditorPane. This is called by Swing and
|
||||
* can be used to do anything you need on the JEditorPane control. Here
|
||||
* I set some default Actions.
|
||||
*
|
||||
* @param editorPane
|
||||
*/
|
||||
@Override
|
||||
public void install(JEditorPane editorPane) {
|
||||
super.install(editorPane);
|
||||
// get our font
|
||||
String fontName = getProperty("DefaultFont");
|
||||
Font font = DEFAULT_FONT;
|
||||
if (fontName != null) {
|
||||
font = Font.decode(fontName);
|
||||
}
|
||||
editorPane.setFont(font);
|
||||
Configuration conf = getConfig();
|
||||
Color caretColor = conf.getColor(CONFIG_CARETCOLOR, Color.BLACK);
|
||||
editorPane.setCaretColor(caretColor);
|
||||
Color selectionColor = getConfig().getColor(CONFIG_SELECTION, new Color(0x99ccff));
|
||||
editorPane.setSelectionColor(selectionColor);
|
||||
addActions(editorPane);
|
||||
addComponents(editorPane);
|
||||
addPopupMenu(editorPane);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deinstall(JEditorPane editorPane) {
|
||||
List<SyntaxComponent> l = editorComponents.get(editorPane);
|
||||
for (SyntaxComponent c : editorComponents.get(editorPane)) {
|
||||
c.deinstall(editorPane);
|
||||
}
|
||||
editorComponents.clear();
|
||||
editorPane.getInputMap().clear();
|
||||
editorPane.getActionMap().clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add keyboard actions to this control using the Configuration we have
|
||||
* This is revised to properly use InputMap and ActionMap of the component
|
||||
* instead of using the KeyMaps directly.
|
||||
* @param editorPane
|
||||
*/
|
||||
public void addActions(JEditorPane editorPane) {
|
||||
InputMap imap = new InputMap();
|
||||
imap.setParent(editorPane.getInputMap());
|
||||
ActionMap amap = new ActionMap();
|
||||
amap.setParent(editorPane.getActionMap());
|
||||
|
||||
for (Configuration.StringKeyMatcher m : getConfig().getKeys(ACTION_KEY_PATTERN)) {
|
||||
String[] values = Configuration.COMMA_SEPARATOR.split(
|
||||
m.value);
|
||||
String actionClass = values[0];
|
||||
String actionName = m.group1;
|
||||
SyntaxAction action = createAction(actionClass);
|
||||
// The configuration keys will need to be prefixed by Action
|
||||
// to make it more readable in the Configuration files.
|
||||
action.config(getConfig(), DefaultSyntaxAction.ACTION_PREFIX + actionName);
|
||||
// Add the action to the component also
|
||||
amap.put(actionName, action);
|
||||
// Now bind all the keys to the Action we have using the InputMap
|
||||
for (int i = 1; i < values.length; i++) {
|
||||
String keyStrokeString = values[i].replace("menu ", MENU_MASK_STRING);
|
||||
KeyStroke ks = KeyStroke.getKeyStroke(keyStrokeString);
|
||||
// we may have more than onr value ( for key action ), but we will use the
|
||||
// last one in the single value here. This will display the key in the
|
||||
// popup menus. Pretty neat.
|
||||
if (ks == null) {
|
||||
throw new IllegalArgumentException("Invalid KeyStroke: " +
|
||||
keyStrokeString);
|
||||
}
|
||||
action.putValue(Action.ACCELERATOR_KEY, ks);
|
||||
imap.put(ks, actionName);
|
||||
}
|
||||
}
|
||||
|
||||
// Now configure the Default actions for better display in the popup menu
|
||||
for (Configuration.StringKeyMatcher m : getConfig().getKeys(DEFAULT_ACTION_PATTERN)) {
|
||||
String name = m.matcher.group(2);
|
||||
Action action = editorPane.getActionMap().get(name);
|
||||
if (action != null) {
|
||||
configActionProperties(action, name, m.group1);
|
||||
}
|
||||
// The below commented block does find the keys for the default Actions
|
||||
// using InputMap, however there are multiple bound keys for the
|
||||
// default actions that displaying them in the menu will probably not
|
||||
// be the most obvious binding
|
||||
/*
|
||||
for (KeyStroke key : imap.allKeys()) {
|
||||
Object o = imap.get(key);
|
||||
if(name.equals(o)) {
|
||||
action.putValue(Action.ACCELERATOR_KEY, key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
editorPane.setActionMap(amap);
|
||||
editorPane.setInputMap(JTextComponent.WHEN_FOCUSED, imap);
|
||||
}
|
||||
|
||||
private void configActionProperties(Action action, String actionName, String configKey) {
|
||||
|
||||
// if we have an icon, then load it:
|
||||
String iconLoc = getConfig().getString(configKey + ".SmallIcon", actionName + ".png");
|
||||
URL loc = this.getClass().getResource(DefaultSyntaxAction.SMALL_ICONS_LOC_PREFIX + iconLoc);
|
||||
if (loc != null) {
|
||||
ImageIcon i = new ImageIcon(loc);
|
||||
action.putValue(Action.SMALL_ICON, i);
|
||||
}
|
||||
// Set the menu text. Use the Action.NAME property, unless it is
|
||||
// already set.
|
||||
// The NAME would be set for default actions, and we should not change those names.
|
||||
// so we will put another property and use it for the menu text
|
||||
String name = getProperty(configKey + ".MenuText");
|
||||
if (action.getValue(Action.NAME) == null) {
|
||||
action.putValue(Action.NAME, name);
|
||||
} else {
|
||||
action.putValue(ACTION_MENU_TEXT, name);
|
||||
}
|
||||
// Set the menu tooltips
|
||||
String shortDesc = getProperty(configKey + ".ToolTip");
|
||||
if (shortDesc != null) {
|
||||
action.putValue(Action.SHORT_DESCRIPTION, shortDesc);
|
||||
} else {
|
||||
action.putValue(Action.SHORT_DESCRIPTION, name);
|
||||
}
|
||||
}
|
||||
|
||||
private SyntaxAction createAction(String actionClassName) {
|
||||
SyntaxAction action = null;
|
||||
try {
|
||||
Class clazz = Class.forName(actionClassName);
|
||||
action = (SyntaxAction) clazz.newInstance();
|
||||
} catch (InstantiationException ex) {
|
||||
throw new IllegalArgumentException("Cannot create action class: " +
|
||||
actionClassName + ". Ensure it has default constructor.", ex);
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw new IllegalArgumentException("Cannot create action class: " +
|
||||
actionClassName, ex);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new IllegalArgumentException("Cannot create action class: " +
|
||||
actionClassName, ex);
|
||||
} catch (ClassCastException ex) {
|
||||
throw new IllegalArgumentException("Cannot create action class: " +
|
||||
actionClassName, ex);
|
||||
}
|
||||
return action;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called by Swing to create a Document for the JEditorPane document
|
||||
* This may be called before you actually get a reference to the control.
|
||||
* We use it here to create a proper lexer and pass it to the
|
||||
* SyntaxDcument we return.
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Document createDefaultDocument() {
|
||||
return new SyntaxDocument(lexer);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called to initialize the list of <code>Lexer</code>s we have.
|
||||
* You can call this at initialization, or it will be called when needed.
|
||||
* The method will also add the appropriate EditorKit classes to the
|
||||
* corresponding ContentType of the JEditorPane. After this is called,
|
||||
* you can simply call the editor.setCOntentType("text/java") on the
|
||||
* control and you will be done.
|
||||
*/
|
||||
public synchronized static void initKit() {
|
||||
// attempt to find a suitable default font
|
||||
String defaultFont = getConfig(DefaultSyntaxKit.class).getString("DefaultFont");
|
||||
if (defaultFont != null) {
|
||||
DEFAULT_FONT = Font.decode(defaultFont);
|
||||
} else {
|
||||
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
String[] fonts = ge.getAvailableFontFamilyNames();
|
||||
Arrays.sort(fonts);
|
||||
if (Arrays.binarySearch(fonts, "Courier New") >= 0) {
|
||||
DEFAULT_FONT = new Font("Courier New", Font.PLAIN, 12);
|
||||
} else if (Arrays.binarySearch(fonts, "Courier") >= 0) {
|
||||
DEFAULT_FONT = new Font("Courier", Font.PLAIN, 12);
|
||||
} else if (Arrays.binarySearch(fonts, "Monospaced") >= 0) {
|
||||
DEFAULT_FONT = new Font("Monospaced", Font.PLAIN, 13);
|
||||
}
|
||||
}
|
||||
|
||||
// read the Default Kits and their associated types
|
||||
Properties kitsForTypes = JarServiceProvider.readProperties("jsyntaxpane/kitsfortypes");
|
||||
for (Map.Entry e : kitsForTypes.entrySet()) {
|
||||
String type = e.getKey().toString();
|
||||
String classname = e.getValue().toString();
|
||||
registerContentType(type, classname);
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the given content type to use the given class name as its kit
|
||||
* When this is called, an entry is added into the private HashMap of the
|
||||
* registered editors kits. This is needed so that the SyntaxPane library
|
||||
* has it's own registration of all the EditorKits
|
||||
* @param type
|
||||
* @param classname
|
||||
*/
|
||||
public static void registerContentType(String type, String classname) {
|
||||
try {
|
||||
// ensure the class is available and that it does supply a no args
|
||||
// constructor. This saves debugging later if the classname is incorrect
|
||||
// or does not behave correctly:
|
||||
Class c = Class.forName(classname);
|
||||
// attempt to create the class, if we cannot with an empty argument
|
||||
// then the class is invalid
|
||||
Object kit = c.newInstance();
|
||||
if (!(kit instanceof EditorKit)) {
|
||||
throw new IllegalArgumentException("Cannot register class: " + classname +
|
||||
". It does not extend EditorKit");
|
||||
}
|
||||
JEditorPane.registerEditorKitForContentType(type, classname);
|
||||
CONTENT_TYPES.add(type);
|
||||
} catch (InstantiationException ex) {
|
||||
throw new IllegalArgumentException("Cannot register class: " + classname +
|
||||
". Ensure it has Default Constructor.", ex);
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw new IllegalArgumentException("Cannot register class: " + classname, ex);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new IllegalArgumentException("Cannot register class: " + classname, ex);
|
||||
} catch (RuntimeException ex) {
|
||||
throw new IllegalArgumentException("Cannot register class: " + classname, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the content types supported by this library. This will be the
|
||||
* content types in the file WEB-INF/services/resources/jsyntaxpane/kitsfortypes
|
||||
* @return sorted array of all registered content types
|
||||
*/
|
||||
public static String[] getContentTypes() {
|
||||
String[] types = CONTENT_TYPES.toArray(new String[0]);
|
||||
Arrays.sort(types);
|
||||
return types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the given properties with the configurations for this Object
|
||||
*
|
||||
* @param config
|
||||
*/
|
||||
public void setConfig(Properties config) {
|
||||
getConfig().putAll(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given property to the given value. If the kit is not
|
||||
* initialized, then calls initKit
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
public void setProperty(String key, String value) {
|
||||
getConfig().put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property with the given key. If the kit is not
|
||||
* initialized, then calls initKit
|
||||
* Be careful when changing property as the default property may be used
|
||||
* @param key
|
||||
* @return value for given key
|
||||
*/
|
||||
public String getProperty(String key) {
|
||||
return getConfig().getString(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configuration for this Object
|
||||
* @return
|
||||
*/
|
||||
public Configuration getConfig() {
|
||||
return getConfig(this.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Configurations object for a Kit. Perfrom lazy creation of a
|
||||
* Configuration object if nothing is created.
|
||||
*
|
||||
* @param kit
|
||||
* @return
|
||||
*/
|
||||
public static synchronized Configuration getConfig(Class<? extends DefaultSyntaxKit> kit) {
|
||||
if (CONFIGS == null) {
|
||||
CONFIGS = new WeakHashMap<Class<? extends DefaultSyntaxKit>, Configuration>();
|
||||
Configuration defaultConfig = new Configuration(DefaultSyntaxKit.class);
|
||||
loadConfig(defaultConfig, DefaultSyntaxKit.class);
|
||||
CONFIGS.put(DefaultSyntaxKit.class, defaultConfig);
|
||||
}
|
||||
|
||||
if (CONFIGS.containsKey(kit)) {
|
||||
return CONFIGS.get(kit);
|
||||
} else {
|
||||
// recursive call until we read the Super duper DefaultSyntaxKit
|
||||
Class superKit = kit.getSuperclass();
|
||||
@SuppressWarnings("unchecked")
|
||||
Configuration defaults = getConfig(superKit);
|
||||
Configuration mine = new Configuration(kit, defaults);
|
||||
loadConfig(mine, kit);
|
||||
CONFIGS.put(kit, mine);
|
||||
return mine;
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, String> getAbbreviations() {
|
||||
// if we have not loaded the abbreviations, then load them now:
|
||||
if (abbrvs == null) {
|
||||
String cl = this.getClass().getName().replace('.', '/').toLowerCase();
|
||||
abbrvs = JarServiceProvider.readStringsMap(cl + "/abbreviations.properties");
|
||||
}
|
||||
return abbrvs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an abbrevisation to this kit's abbreviations.
|
||||
* @param abbr
|
||||
* @param template
|
||||
*/
|
||||
public static void addAbbreviation(String abbr, String template) {
|
||||
if (abbrvs == null) {
|
||||
abbrvs = new HashMap<String, String>();
|
||||
}
|
||||
abbrvs.put(abbr, template);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the template for the given abbreviation
|
||||
* @param abbr
|
||||
* @return
|
||||
*/
|
||||
public static String getAbbreviation(String abbr) {
|
||||
return abbrvs == null ? null : abbrvs.get(abbr);
|
||||
}
|
||||
|
||||
private static void loadConfig(Configuration conf, Class<? extends EditorKit> kit) {
|
||||
String url = kit.getName().replace(".", "/") + "/config";
|
||||
Properties p = JarServiceProvider.readProperties(url);
|
||||
if (p.size() == 0) {
|
||||
LOG.info("unable to load configuration for: " + kit + " from: " + url + ".properties");
|
||||
} else {
|
||||
conf.putAll(p);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return "text/" + this.getClass().getSimpleName().replace("SyntaxKit", "").toLowerCase();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2008 Ayman Al-Sairafi [email protected]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License
|
||||
* at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package jsyntaxpane;
|
||||
|
||||
import java.io.IOException;
|
||||
import jsyntaxpane.lexers.SimpleRegexLexer;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ayman Al-Sairafi
|
||||
*/
|
||||
public class JavaRegexKit extends DefaultSyntaxKit {
|
||||
|
||||
public JavaRegexKit() throws IOException {
|
||||
super(new SimpleRegexLexer("javaRegex.properties"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2008 Ayman Al-Sairafi [email protected]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License
|
||||
* at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package jsyntaxpane;
|
||||
|
||||
import java.util.List;
|
||||
import javax.swing.text.Segment;
|
||||
|
||||
/**
|
||||
* Lexers must implement these methods. These are used in the Tokenizer
|
||||
*
|
||||
* A Lexer should be tied to one document.
|
||||
*
|
||||
* @author Ayman Al-Sairafi
|
||||
*/
|
||||
public interface Lexer {
|
||||
/**
|
||||
* This is the only method a Lexer needs to implement. It will be passed
|
||||
* a Reader, and it should return non-overlapping Tokens for each recognized token
|
||||
* in the stream.
|
||||
* @param segment Text to parse.
|
||||
* @param ofst offset to add to start of each token (useful for nesting)
|
||||
* @param tokens List of Tokens to be added. This is done so that the caller creates the
|
||||
* appropriate List implementation and size. The parse method just adds to the list
|
||||
*/
|
||||
public void parse(Segment segment, int ofst, List<Token> tokens);
|
||||
}
|
||||
@@ -0,0 +1,595 @@
|
||||
/*
|
||||
* Copyright 2008 Ayman Al-Sairafi [email protected]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License
|
||||
* at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package jsyntaxpane;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.text.AttributeSet;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Element;
|
||||
import javax.swing.text.PlainDocument;
|
||||
import javax.swing.text.Segment;
|
||||
|
||||
/**
|
||||
* A document that supports being highlighted. The document maintains an
|
||||
* internal List of all the Tokens. The Tokens are updated using
|
||||
* a Lexer, passed to it during construction.
|
||||
*
|
||||
* @author Ayman Al-Sairafi
|
||||
*/
|
||||
public class SyntaxDocument extends PlainDocument {
|
||||
|
||||
Lexer lexer;
|
||||
List<Token> tokens;
|
||||
CompoundUndoMan undo;
|
||||
|
||||
public SyntaxDocument(Lexer lexer) {
|
||||
super();
|
||||
putProperty(PlainDocument.tabSizeAttribute, 4);
|
||||
this.lexer = lexer;
|
||||
// Listen for undo and redo events
|
||||
undo = new CompoundUndoMan(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the entire document and return list of tokens that do not already
|
||||
* exist in the tokens list. There may be overlaps, and replacements,
|
||||
* which we will cleanup later.
|
||||
* @return list of tokens that do not exist in the tokens field
|
||||
*/
|
||||
private void parse() {
|
||||
// if we have no lexer, then we must have no tokens...
|
||||
if (lexer == null) {
|
||||
tokens = null;
|
||||
return;
|
||||
}
|
||||
List<Token> toks = new ArrayList<Token>(getLength() / 10);
|
||||
long ts = System.nanoTime();
|
||||
int len = getLength();
|
||||
try {
|
||||
Segment seg = new Segment();
|
||||
getText(0, getLength(), seg);
|
||||
lexer.parse(seg, 0, toks);
|
||||
} catch (BadLocationException ex) {
|
||||
log.log(Level.SEVERE, null, ex);
|
||||
} finally {
|
||||
if (log.isLoggable(Level.FINEST)) {
|
||||
log.finest(String.format("Parsed %d in %d ms, giving %d tokens\n",
|
||||
len, (System.nanoTime() - ts) / 1000000, toks.size()));
|
||||
}
|
||||
tokens = toks;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fireChangedUpdate(DocumentEvent e) {
|
||||
parse();
|
||||
super.fireChangedUpdate(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fireInsertUpdate(DocumentEvent e) {
|
||||
parse();
|
||||
super.fireInsertUpdate(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fireRemoveUpdate(DocumentEvent e) {
|
||||
parse();
|
||||
super.fireRemoveUpdate(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the token with the replacement string
|
||||
* @param token
|
||||
* @param replacement
|
||||
*/
|
||||
public void replaceToken(Token token, String replacement) {
|
||||
try {
|
||||
replace(token.start, token.length, replacement, null);
|
||||
} catch (BadLocationException ex) {
|
||||
log.log(Level.WARNING, "unable to replace token: " + token, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is used to iterate over tokens between two positions
|
||||
*
|
||||
*/
|
||||
class TokenIterator implements ListIterator<Token> {
|
||||
|
||||
int start;
|
||||
int end;
|
||||
int ndx = 0;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private TokenIterator(int start, int end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
if (tokens != null && !tokens.isEmpty()) {
|
||||
Token token = new Token(TokenType.COMMENT, start, end - start);
|
||||
ndx = Collections.binarySearch((List) tokens, token);
|
||||
// we will probably not find the exact token...
|
||||
if (ndx < 0) {
|
||||
// so, start from one before the token where we should be...
|
||||
// -1 to get the location, and another -1 to go back..
|
||||
ndx = (-ndx - 1 - 1 < 0) ? 0 : (-ndx - 1 - 1);
|
||||
Token t = tokens.get(ndx);
|
||||
// if the prev token does not overlap, then advance one
|
||||
if (t.end() <= start) {
|
||||
ndx++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (tokens == null) {
|
||||
return false;
|
||||
}
|
||||
if (ndx >= tokens.size()) {
|
||||
return false;
|
||||
}
|
||||
Token t = tokens.get(ndx);
|
||||
if (t.start >= end) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token next() {
|
||||
return tokens.get(ndx++);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrevious() {
|
||||
if (tokens == null) {
|
||||
return false;
|
||||
}
|
||||
if (ndx <= 0) {
|
||||
return false;
|
||||
}
|
||||
Token t = tokens.get(ndx);
|
||||
if (t.end() <= start) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token previous() {
|
||||
return tokens.get(ndx--);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nextIndex() {
|
||||
return ndx + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int previousIndex() {
|
||||
return ndx - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Token e) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Token e) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an iterator of tokens between p0 and p1.
|
||||
* @param start start position for getting tokens
|
||||
* @param end position for last token
|
||||
* @return Iterator for tokens that overal with range from start to end
|
||||
*/
|
||||
public Iterator<Token> getTokens(int start, int end) {
|
||||
return new TokenIterator(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the token at a given position. May return null if no token is
|
||||
* found (whitespace skipped) or if the position is out of range:
|
||||
* @param pos
|
||||
* @return
|
||||
*/
|
||||
public Token getTokenAt(int pos) {
|
||||
if (tokens == null || tokens.isEmpty() || pos > getLength()) {
|
||||
return null;
|
||||
}
|
||||
Token tok = null;
|
||||
Token tKey = new Token(TokenType.DEFAULT, pos, 1);
|
||||
@SuppressWarnings("unchecked")
|
||||
int ndx = Collections.binarySearch((List) tokens, tKey);
|
||||
if (ndx < 0) {
|
||||
// so, start from one before the token where we should be...
|
||||
// -1 to get the location, and another -1 to go back..
|
||||
ndx = (-ndx - 1 - 1 < 0) ? 0 : (-ndx - 1 - 1);
|
||||
Token t = tokens.get(ndx);
|
||||
if ((t.start <= pos) && (pos <= t.end())) {
|
||||
tok = t;
|
||||
}
|
||||
} else {
|
||||
tok = tokens.get(ndx);
|
||||
}
|
||||
return tok;
|
||||
}
|
||||
|
||||
public Token getWordAt(int offs, Pattern p) {
|
||||
Token word = null;
|
||||
try {
|
||||
Element line = getParagraphElement(offs);
|
||||
if (line == null) {
|
||||
return word;
|
||||
}
|
||||
int lineStart = line.getStartOffset();
|
||||
int lineEnd = Math.min(line.getEndOffset(), getLength());
|
||||
Segment seg = new Segment();
|
||||
getText(lineStart, lineEnd - lineStart, seg);
|
||||
if (seg.count > 0) {
|
||||
// we need to get the word using the words pattern p
|
||||
Matcher m = p.matcher(seg);
|
||||
int o = offs - lineStart;
|
||||
while (m.find()) {
|
||||
if (m.start() <= o && o <= m.end()) {
|
||||
word = new Token(TokenType.DEFAULT, m.start() + lineStart, m.end() - m.start());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (BadLocationException ex) {
|
||||
Logger.getLogger(SyntaxDocument.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} finally {
|
||||
return word;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the token following the current token, or null
|
||||
* <b>This is an expensive operation, so do not use it to update the gui</b>
|
||||
* @param tok
|
||||
* @return
|
||||
*/
|
||||
public Token getNextToken(Token tok) {
|
||||
int n = tokens.indexOf(tok);
|
||||
if ((n >= 0) && (n < (tokens.size() - 1))) {
|
||||
return tokens.get(n + 1);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the token prior to the given token, or null
|
||||
* <b>This is an expensive operation, so do not use it to update the gui</b>
|
||||
* @param tok
|
||||
* @return
|
||||
*/
|
||||
public Token getPrevToken(Token tok) {
|
||||
int n = tokens.indexOf(tok);
|
||||
if ((n > 0) && (!tokens.isEmpty())) {
|
||||
return tokens.get(n - 1);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used to return the other part of a paired token in the document.
|
||||
* A paired part has token.pairValue <> 0, and the paired token will
|
||||
* have the negative of t.pairValue.
|
||||
* This method properly handles nestings of same pairValues, but overlaps
|
||||
* are not checked.
|
||||
* if The document does not contain a paired token, then null is returned.
|
||||
* @param t
|
||||
* @return the other pair's token, or null if nothing is found.
|
||||
*/
|
||||
public Token getPairFor(Token t) {
|
||||
if (t == null || t.pairValue == 0) {
|
||||
return null;
|
||||
}
|
||||
Token p = null;
|
||||
int ndx = tokens.indexOf(t);
|
||||
// w will be similar to a stack. The openners weght is added to it
|
||||
// and the closers are subtracted from it (closers are already negative)
|
||||
int w = t.pairValue;
|
||||
int direction = (t.pairValue > 0) ? 1 : -1;
|
||||
boolean done = false;
|
||||
int v = Math.abs(t.pairValue);
|
||||
while (!done) {
|
||||
ndx += direction;
|
||||
if (ndx < 0 || ndx >= tokens.size()) {
|
||||
break;
|
||||
}
|
||||
Token current = tokens.get(ndx);
|
||||
if (Math.abs(current.pairValue) == v) {
|
||||
w += current.pairValue;
|
||||
if (w == 0) {
|
||||
p = current;
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an undo action, if possible
|
||||
*/
|
||||
public void doUndo() {
|
||||
if (undo.canUndo()) {
|
||||
undo.undo();
|
||||
parse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a redo action, if possible.
|
||||
*/
|
||||
public void doRedo() {
|
||||
if (undo.canRedo()) {
|
||||
undo.redo();
|
||||
parse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a matcher that matches the given pattern on the entire document
|
||||
* @param pattern
|
||||
* @return matcher object
|
||||
*/
|
||||
public Matcher getMatcher(Pattern pattern) {
|
||||
return getMatcher(pattern, 0, getLength());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a matcher that matches the given pattern in the part of the
|
||||
* document starting at offset start. Note that the matcher will have
|
||||
* offset starting from <code>start</code>
|
||||
*
|
||||
* @param pattern
|
||||
* @param start
|
||||
* @return matcher that <b>MUST</b> be offset by start to get the proper
|
||||
* location within the document
|
||||
*/
|
||||
public Matcher getMatcher(Pattern pattern, int start) {
|
||||
return getMatcher(pattern, start, getLength() - start);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a matcher that matches the given pattern in the part of the
|
||||
* document starting at offset start and ending at start + length.
|
||||
* Note that the matcher will have
|
||||
* offset starting from <code>start</code>
|
||||
*
|
||||
* @param pattern
|
||||
* @param start
|
||||
* @param length
|
||||
* @return matcher that <b>MUST</b> be offset by start to get the proper
|
||||
* location within the document
|
||||
*/
|
||||
public Matcher getMatcher(Pattern pattern, int start, int length) {
|
||||
Matcher matcher = null;
|
||||
if (getLength() == 0) {
|
||||
return null;
|
||||
}
|
||||
if (start >= getLength()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
}
|
||||
if (start + length > getLength()) {
|
||||
length = getLength() - start;
|
||||
}
|
||||
Segment seg = new Segment();
|
||||
getText(start, length, seg);
|
||||
matcher = pattern.matcher(seg);
|
||||
} catch (BadLocationException ex) {
|
||||
log.log(Level.SEVERE, "Requested offset: " + ex.offsetRequested(), ex);
|
||||
}
|
||||
return matcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will discard all undoable edits
|
||||
*/
|
||||
public void clearUndos() {
|
||||
undo.discardAllEdits();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the line at given position. The line returned will NOT include
|
||||
* the line terminator '\n'
|
||||
* @param pos Position (usually from text.getCaretPosition()
|
||||
* @return the STring of text at given position
|
||||
* @throws BadLocationException
|
||||
*/
|
||||
public String getLineAt(int pos) throws BadLocationException {
|
||||
Element e = getParagraphElement(pos);
|
||||
Segment seg = new Segment();
|
||||
getText(e.getStartOffset(), e.getEndOffset() - e.getStartOffset(), seg);
|
||||
char last = seg.last();
|
||||
if (last == '\n' || last == '\r') {
|
||||
seg.count--;
|
||||
}
|
||||
return seg.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the line at given position
|
||||
* @param pos
|
||||
* @throws javax.swing.text.BadLocationException
|
||||
*/
|
||||
public void removeLineAt(int pos)
|
||||
throws BadLocationException {
|
||||
Element e = getParagraphElement(pos);
|
||||
remove(e.getStartOffset(), getElementLength(e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the line at given position with the given string, which can span
|
||||
* multiple lines
|
||||
* @param pos
|
||||
* @param newLines
|
||||
* @throws javax.swing.text.BadLocationException
|
||||
*/
|
||||
public void replaceLineAt(int pos, String newLines)
|
||||
throws BadLocationException {
|
||||
Element e = getParagraphElement(pos);
|
||||
replace(e.getStartOffset(), getElementLength(e), newLines, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get the length of an element and avoid getting
|
||||
* a too long element at the end of the document
|
||||
* @param e
|
||||
* @return
|
||||
*/
|
||||
private int getElementLength(Element e) {
|
||||
int end = e.getEndOffset();
|
||||
if (end >= (getLength() - 1)) {
|
||||
end--;
|
||||
}
|
||||
return end - e.getStartOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the text without the comments. For example for the string
|
||||
* <code>{ // it's a comment</code> this method will return "{ ".
|
||||
* @param aStart start of the text.
|
||||
* @param anEnd end of the text.
|
||||
* @return String for the line without comments (if exists).
|
||||
*/
|
||||
public synchronized String getUncommentedText(int aStart, int anEnd) {
|
||||
readLock();
|
||||
StringBuilder result = new StringBuilder();
|
||||
Iterator<Token> iter = getTokens(aStart, anEnd);
|
||||
while (iter.hasNext()) {
|
||||
Token t = iter.next();
|
||||
if (!TokenType.isComment(t)) {
|
||||
result.append(t.getText(this));
|
||||
}
|
||||
}
|
||||
readUnlock();
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the starting position of the line at pos
|
||||
* @param pos
|
||||
* @return starting position of the line
|
||||
*/
|
||||
public int getLineStartOffset(int pos) {
|
||||
return getParagraphElement(pos).getStartOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the end position of the line at pos.
|
||||
* Does a bounds check to ensure the returned value does not exceed
|
||||
* document length
|
||||
* @param pos
|
||||
* @return
|
||||
*/
|
||||
public int getLineEndOffset(int pos) {
|
||||
int end = 0;
|
||||
end = getParagraphElement(pos).getEndOffset();
|
||||
if (end >= getLength()) {
|
||||
end = getLength();
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of lines in this document
|
||||
* @return
|
||||
*/
|
||||
public int getLineCount() {
|
||||
Element e = getDefaultRootElement();
|
||||
int cnt = e.getElementCount();
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the line number at given position. The line numbers are zero based
|
||||
* @param pos
|
||||
* @return
|
||||
*/
|
||||
public int getLineNumberAt(int pos) {
|
||||
int lineNr = getDefaultRootElement().getElementIndex(pos);
|
||||
return lineNr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SyntaxDocument(" + lexer + ", " + ((tokens == null) ? 0 : tokens.size()) + " tokens)@" +
|
||||
hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* We override this here so that the replace is treated as one operation
|
||||
* by the undomanager
|
||||
* @param offset
|
||||
* @param length
|
||||
* @param text
|
||||
* @param attrs
|
||||
* @throws BadLocationException
|
||||
*/
|
||||
@Override
|
||||
public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
|
||||
remove(offset, length);
|
||||
undo.startCombine();
|
||||
insertString(offset, text, attrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the given string to the text of this document.
|
||||
* @param str
|
||||
* @return this document
|
||||
*/
|
||||
public SyntaxDocument append(String str) {
|
||||
try {
|
||||
insertString(getLength(), str, null);
|
||||
} catch (BadLocationException ex) {
|
||||
log.log(Level.WARNING, "Error appending str", ex);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
// our logger instance...
|
||||
private static final Logger log = Logger.getLogger(SyntaxDocument.class.getName());
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2008 Ayman Al-Sairafi [email protected]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License
|
||||
* at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package jsyntaxpane;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import javax.swing.text.Segment;
|
||||
import javax.swing.text.TabExpander;
|
||||
import javax.swing.text.Utilities;
|
||||
|
||||
/**
|
||||
* This class represents the Style for a TokenType. This class is responsible
|
||||
* for actually drawing a Token on the View.
|
||||
*
|
||||
* @author Ayman Al-Sairafi
|
||||
*/
|
||||
public final class SyntaxStyle {
|
||||
|
||||
private Color color;
|
||||
private int fontStyle;
|
||||
|
||||
public SyntaxStyle() {
|
||||
super();
|
||||
}
|
||||
|
||||
public SyntaxStyle(Color color, boolean bold, boolean italic) {
|
||||
super();
|
||||
this.color = color;
|
||||
setBold(bold);
|
||||
setItalic(italic);
|
||||
}
|
||||
|
||||
public SyntaxStyle(Color color, int fontStyle) {
|
||||
super();
|
||||
this.color = color;
|
||||
this.fontStyle = fontStyle;
|
||||
}
|
||||
|
||||
public SyntaxStyle(String str) {
|
||||
String[] parts = str.split("\\s*,\\s*");
|
||||
if (parts.length != 2) {
|
||||
throw new IllegalArgumentException("style not correct format: " + str);
|
||||
}
|
||||
this.color = new Color(Integer.decode(parts[0]));
|
||||
this.fontStyle = Integer.decode(parts[1]);
|
||||
}
|
||||
|
||||
public boolean isBold() {
|
||||
return (fontStyle & Font.BOLD) != 0;
|
||||
}
|
||||
|
||||
public void setBold(Boolean bold) {
|
||||
if (bold) {
|
||||
fontStyle |= Font.BOLD;
|
||||
} else {
|
||||
int mask = -1 ^ Font.BOLD;
|
||||
fontStyle = (fontStyle & (mask));
|
||||
}
|
||||
}
|
||||
|
||||
public String getColorString() {
|
||||
return String.format("0x%06x", color.getRGB() & 0x00ffffff);
|
||||
}
|
||||
|
||||
public void setColorString(String color) {
|
||||
this.color = Color.decode(color);
|
||||
}
|
||||
|
||||
public Boolean isItalic() {
|
||||
return (fontStyle & Font.ITALIC) != 0;
|
||||
}
|
||||
|
||||
public void setItalic(Boolean italic) {
|
||||
if (italic) {
|
||||
fontStyle |= Font.ITALIC;
|
||||
} else {
|
||||
fontStyle = (fontStyle & (-1 ^ Font.ITALIC));
|
||||
}
|
||||
}
|
||||
|
||||
public int getFontStyle() {
|
||||
return fontStyle;
|
||||
}
|
||||
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw text. This can directly call the Utilities.drawTabbedText.
|
||||
* Sub-classes can override this method to provide any other decorations.
|
||||
* @param segment - the source of the text
|
||||
* @param x - the X origin >= 0
|
||||
* @param y - the Y origin >= 0
|
||||
* @param graphics - the graphics context
|
||||
* @param e - how to expand the tabs. If this value is null, tabs will be
|
||||
* expanded as a space character.
|
||||
* @param startOffset - starting offset of the text in the document >= 0
|
||||
* @return
|
||||
*/
|
||||
public int drawText(Segment segment, int x, int y,
|
||||
Graphics graphics, TabExpander e, int startOffset) {
|
||||
graphics.setFont(graphics.getFont().deriveFont(getFontStyle()));
|
||||
FontMetrics fontMetrics = graphics.getFontMetrics();
|
||||
int a = fontMetrics.getAscent();
|
||||
int h = a + fontMetrics.getDescent();
|
||||
int w = Utilities.getTabbedTextWidth(segment, fontMetrics, 0, e, startOffset);
|
||||
int rX = x - 1;
|
||||
int rY = y - a;
|
||||
int rW = w + 2;
|
||||
int rH = h;
|
||||
if ((getFontStyle() & 0x10) != 0) {
|
||||
graphics.setColor(Color.decode("#EEEEEE"));
|
||||
graphics.fillRect(rX, rY, rW, rH);
|
||||
}
|
||||
graphics.setColor(getColor());
|
||||
x = Utilities.drawTabbedText(segment, x, y, graphics, e, startOffset);
|
||||
if ((getFontStyle() & 0x8) != 0) {
|
||||
graphics.setColor(Color.RED);
|
||||
graphics.drawRect(rX, rY, rW, rH);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2008 Ayman Al-Sairafi [email protected]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License
|
||||
* at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package jsyntaxpane;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.swing.text.Segment;
|
||||
import javax.swing.text.TabExpander;
|
||||
import jsyntaxpane.util.Configuration;
|
||||
import jsyntaxpane.util.JarServiceProvider;
|
||||
|
||||
/**
|
||||
* The Styles to use for each TokenType. The defaults are created here, and
|
||||
* then the resource META-INF/services/syntaxstyles.properties is read and
|
||||
* merged. You can also pass a properties instance and merge your prefered
|
||||
* styles into the default styles.
|
||||
*
|
||||
* Text is drawn by forwarding the drawText request to the SyntaxStyle for the
|
||||
* that matches the given TokenType
|
||||
*
|
||||
* @author Ayman Al-Sairafi
|
||||
*/
|
||||
public class SyntaxStyles {
|
||||
|
||||
public static final Pattern STYLE_PATTERN = Pattern.compile("Style\\.(\\w+)");
|
||||
|
||||
/**
|
||||
* You can call the mergeStyles method with a Properties file to customize
|
||||
* the existing styles. Any existing styles will be overwritten by the
|
||||
* styles you provide.
|
||||
* @param styles
|
||||
*/
|
||||
public void mergeStyles(Properties styles) {
|
||||
for (Map.Entry e : styles.entrySet()) {
|
||||
String tokenType = e.getKey().toString();
|
||||
String style = e.getValue().toString();
|
||||
try {
|
||||
TokenType tt = TokenType.valueOf(tokenType);
|
||||
SyntaxStyle tokenStyle = new SyntaxStyle(style);
|
||||
put(tt, tokenStyle);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
LOG.warning("illegal token type or style for: " + tokenType);
|
||||
}
|
||||
}
|
||||
}
|
||||
Map<TokenType, SyntaxStyle> styles;
|
||||
private static SyntaxStyles instance = createInstance();
|
||||
private static final Logger LOG = Logger.getLogger(SyntaxStyles.class.getName());
|
||||
private static SyntaxStyle DEFAULT_STYLE = new SyntaxStyle(Color.BLACK, Font.PLAIN);
|
||||
|
||||
private SyntaxStyles() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create default styles
|
||||
* @return
|
||||
*/
|
||||
private static SyntaxStyles createInstance() {
|
||||
SyntaxStyles syntaxstyles = new SyntaxStyles();
|
||||
Properties styles = JarServiceProvider.readProperties(SyntaxStyles.class);
|
||||
syntaxstyles.mergeStyles(styles);
|
||||
return syntaxstyles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Default Singleton
|
||||
* @return
|
||||
*/
|
||||
public static SyntaxStyles getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static SyntaxStyles read(Configuration config) {
|
||||
SyntaxStyles ss = createInstance();
|
||||
// Configuration styleConf = config.subConfig(STYLE_PROPERTY_KEY);
|
||||
|
||||
for (Configuration.StringKeyMatcher m : config.getKeys(STYLE_PATTERN)) {
|
||||
String type = m.group1;
|
||||
try {
|
||||
ss.put(TokenType.valueOf(type), new SyntaxStyle(m.value));
|
||||
} catch (IllegalArgumentException e) {
|
||||
Logger.getLogger(SyntaxStyles.class.getName()).warning(
|
||||
String.format("Invalid Token Type [%s] for Style of ", type));
|
||||
}
|
||||
}
|
||||
return ss;
|
||||
}
|
||||
|
||||
public void put(TokenType type, SyntaxStyle style) {
|
||||
if (styles == null) {
|
||||
styles = new HashMap<TokenType, SyntaxStyle>();
|
||||
}
|
||||
styles.put(type, style);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the style for the given TokenType
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public SyntaxStyle getStyle(TokenType type) {
|
||||
if (styles != null && styles.containsKey(type)) {
|
||||
return styles.get(type);
|
||||
} else {
|
||||
return DEFAULT_STYLE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the given Token. This will simply find the proper SyntaxStyle for
|
||||
* the TokenType and then asks the proper Style to draw the text of the
|
||||
* Token.
|
||||
* @param segment
|
||||
* @param x
|
||||
* @param y
|
||||
* @param graphics
|
||||
* @param e
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
public int drawText(Segment segment, int x, int y,
|
||||
Graphics graphics, TabExpander e, Token token) {
|
||||
SyntaxStyle s = getStyle(token.type);
|
||||
return s.drawText(segment, x, y, graphics, e, token.start);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.6" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
|
||||
<Properties>
|
||||
<Property name="defaultCloseOperation" type="int" value="3"/>
|
||||
<Property name="title" type="java.lang.String" value="JSyntaxPane Tester"/>
|
||||
</Properties>
|
||||
<SyntheticProperties>
|
||||
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
|
||||
</SyntheticProperties>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jCmbLangs" min="-2" pref="135" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="441" max="32767" attributes="0"/>
|
||||
<Component id="lblCaretPos" min="-2" pref="119" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="lblToken" pref="221" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="484" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="jToolBar1" alignment="0" pref="715" max="32767" attributes="1"/>
|
||||
<Component id="jScrollPane1" alignment="0" pref="715" max="32767" attributes="1"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="jToolBar1" min="-2" pref="25" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="jScrollPane1" pref="382" max="32767" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="lblToken" min="-2" pref="19" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="lblCaretPos" alignment="3" pref="21" max="32767" attributes="0"/>
|
||||
<Component id="jCmbLangs" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="lblCaretPos">
|
||||
<Properties>
|
||||
<Property name="horizontalAlignment" type="int" value="11"/>
|
||||
<Property name="text" type="java.lang.String" value="Caret Position"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
|
||||
<AuxValues>
|
||||
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JEditorPane" name="jEdtTest">
|
||||
<Properties>
|
||||
<Property name="contentType" type="java.lang.String" value=""/>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Monospaced" size="13" style="0"/>
|
||||
</Property>
|
||||
<Property name="caretColor" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="ff" green="cc" red="99" type="rgb"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="caretUpdate" listener="javax.swing.event.CaretListener" parameters="javax.swing.event.CaretEvent" handler="jEdtTestCaretUpdate"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Component class="javax.swing.JLabel" name="lblToken">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Courier New" size="12" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Token under cursor"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="jCmbLangs">
|
||||
<Properties>
|
||||
<Property name="maximumRowCount" type="int" value="20"/>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="0"/>
|
||||
</Property>
|
||||
<Property name="focusable" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="jCmbLangsItemStateChanged"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Container class="javax.swing.JToolBar" name="jToolBar1">
|
||||
<Properties>
|
||||
<Property name="rollover" type="boolean" value="true"/>
|
||||
<Property name="focusable" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright 2008 Ayman Al-Sairafi [email protected]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License
|
||||
* at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package jsyntaxpane;
|
||||
|
||||
import jsyntaxpane.actions.ActionUtils;
|
||||
import jsyntaxpane.actions.CaretMonitor;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.EditorKit;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class SyntaxTester extends javax.swing.JFrame {
|
||||
|
||||
/**
|
||||
* Creates new form Tester
|
||||
*/
|
||||
public SyntaxTester() {
|
||||
// this is a test for adding regex lexer. It wont work unless the
|
||||
// JavaRegex.properties is found in the classpath
|
||||
//DefaultSyntaxKit.registerContentType("text/flasm", "jsyntaxpane.syntaxkits.Flasm3SyntaxKit");
|
||||
initComponents();
|
||||
jCmbLangs.setModel(new DefaultComboBoxModel(DefaultSyntaxKit.getContentTypes()));
|
||||
// jEdtTest.setContentType(jCmbLangs.getItemAt(0).toString());
|
||||
jCmbLangs.setSelectedItem("text/java");
|
||||
new CaretMonitor(jEdtTest, lblCaretPos);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to
|
||||
* initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is
|
||||
* always regenerated by the Form Editor.
|
||||
*/
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
lblCaretPos = new javax.swing.JLabel();
|
||||
jScrollPane1 = new javax.swing.JScrollPane();
|
||||
jEdtTest = new javax.swing.JEditorPane();
|
||||
lblToken = new javax.swing.JLabel();
|
||||
jCmbLangs = new javax.swing.JComboBox();
|
||||
jToolBar1 = new javax.swing.JToolBar();
|
||||
|
||||
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
|
||||
setTitle("JSyntaxPane Tester");
|
||||
|
||||
lblCaretPos.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
|
||||
lblCaretPos.setText("Caret Position");
|
||||
|
||||
jEdtTest.setContentType("");
|
||||
jEdtTest.setFont(new java.awt.Font("Monospaced", 0, 13)); // NOI18N
|
||||
jEdtTest.setCaretColor(new java.awt.Color(153, 204, 255));
|
||||
jEdtTest.addCaretListener(new javax.swing.event.CaretListener() {
|
||||
public void caretUpdate(javax.swing.event.CaretEvent evt) {
|
||||
jEdtTestCaretUpdate(evt);
|
||||
}
|
||||
});
|
||||
jScrollPane1.setViewportView(jEdtTest);
|
||||
|
||||
lblToken.setFont(new java.awt.Font("Courier New", 0, 12));
|
||||
lblToken.setText("Token under cursor");
|
||||
|
||||
jCmbLangs.setMaximumRowCount(20);
|
||||
jCmbLangs.setFocusable(false);
|
||||
jCmbLangs.addItemListener(new java.awt.event.ItemListener() {
|
||||
public void itemStateChanged(java.awt.event.ItemEvent evt) {
|
||||
jCmbLangsItemStateChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
jToolBar1.setRollover(true);
|
||||
jToolBar1.setFocusable(false);
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
||||
getContentPane().setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(jCmbLangs, javax.swing.GroupLayout.PREFERRED_SIZE, 135, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 441, Short.MAX_VALUE)
|
||||
.addComponent(lblCaretPos, javax.swing.GroupLayout.PREFERRED_SIZE, 119, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap())
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(lblToken, javax.swing.GroupLayout.DEFAULT_SIZE, 221, Short.MAX_VALUE)
|
||||
.addGap(484, 484, 484))
|
||||
.addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 715, Short.MAX_VALUE)
|
||||
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 715, Short.MAX_VALUE)
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 382, Short.MAX_VALUE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(lblToken, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(lblCaretPos, javax.swing.GroupLayout.DEFAULT_SIZE, 21, Short.MAX_VALUE)
|
||||
.addComponent(jCmbLangs, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addContainerGap())
|
||||
);
|
||||
|
||||
pack();
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void jEdtTestCaretUpdate(javax.swing.event.CaretEvent evt) {//GEN-FIRST:event_jEdtTestCaretUpdate
|
||||
SyntaxDocument sDoc = ActionUtils.getSyntaxDocument(jEdtTest);
|
||||
if (sDoc != null) {
|
||||
Token t = sDoc.getTokenAt(evt.getDot());
|
||||
if (t != null) {
|
||||
CharSequence tData = t.getText(sDoc);
|
||||
if (t.length > 40) {
|
||||
tData = tData.subSequence(0, 40);
|
||||
}
|
||||
lblToken.setText(t.toString() + ": " + tData);
|
||||
} else {
|
||||
// null token, remove the status
|
||||
lblToken.setText("NO Token at cursor");
|
||||
}
|
||||
}
|
||||
|
||||
}//GEN-LAST:event_jEdtTestCaretUpdate
|
||||
|
||||
private void jCmbLangsItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_jCmbLangsItemStateChanged
|
||||
if (evt.getStateChange() == ItemEvent.SELECTED) {
|
||||
String lang = jCmbLangs.getSelectedItem().toString();
|
||||
|
||||
// save the state of the current JEditorPane, as it's Document is about
|
||||
// to be replaced.
|
||||
String oldText = jEdtTest.getText();
|
||||
|
||||
// install a new DefaultSyntaxKit on the JEditorPane for the requested language.
|
||||
jEdtTest.setContentType(lang);
|
||||
// Recreate the Toolbar
|
||||
jToolBar1.removeAll();
|
||||
EditorKit kit = jEdtTest.getEditorKit();
|
||||
if (kit instanceof DefaultSyntaxKit) {
|
||||
DefaultSyntaxKit defaultSyntaxKit = (DefaultSyntaxKit) kit;
|
||||
defaultSyntaxKit.addToolBarActions(jEdtTest, jToolBar1);
|
||||
}
|
||||
jToolBar1.validate();
|
||||
try {
|
||||
// setText should not be called (read the JavaDocs). Better use the read
|
||||
// method and create a new document.
|
||||
jEdtTest.read(new StringReader(oldText), lang);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(SyntaxTester.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
jEdtTest.requestFocusInWindow();
|
||||
}//GEN-LAST:event_jCmbLangsItemStateChanged
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String args[]) {
|
||||
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
DefaultSyntaxKit.initKit();
|
||||
new SyntaxTester().setVisible(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.exit(2);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JComboBox jCmbLangs;
|
||||
private javax.swing.JEditorPane jEdtTest;
|
||||
private javax.swing.JScrollPane jScrollPane1;
|
||||
private javax.swing.JToolBar jToolBar1;
|
||||
private javax.swing.JLabel lblCaretPos;
|
||||
private javax.swing.JLabel lblToken;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2008 Ayman Al-Sairafi [email protected]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License
|
||||
* at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package jsyntaxpane;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Toolkit;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Element;
|
||||
import javax.swing.text.PlainView;
|
||||
import javax.swing.text.Segment;
|
||||
import javax.swing.text.ViewFactory;
|
||||
import jsyntaxpane.util.Configuration;
|
||||
|
||||
public class SyntaxView extends PlainView {
|
||||
|
||||
public static final String PROPERTY_RIGHT_MARGIN_COLOR = "RightMarginColor";
|
||||
public static final String PROPERTY_RIGHT_MARGIN_COLUMN = "RightMarginColumn";
|
||||
public static final String PROPERTY_SINGLE_COLOR_SELECT = "SingleColorSelect";
|
||||
private static final Logger log = Logger.getLogger(SyntaxView.class.getName());
|
||||
private SyntaxStyle DEFAULT_STYLE = SyntaxStyles.getInstance().getStyle(TokenType.DEFAULT);
|
||||
private final boolean singleColorSelect;
|
||||
private final int rightMarginColumn;
|
||||
private final Color rightMarginColor;
|
||||
private final SyntaxStyles styles;
|
||||
|
||||
/**
|
||||
* Construct a new view using the given configuration and prefix given
|
||||
*
|
||||
* @param element
|
||||
* @param config
|
||||
*/
|
||||
public SyntaxView(Element element, Configuration config) {
|
||||
super(element);
|
||||
singleColorSelect = config.getBoolean(PROPERTY_SINGLE_COLOR_SELECT, false);
|
||||
rightMarginColor = new Color(config.getInteger(PROPERTY_RIGHT_MARGIN_COLOR,
|
||||
0xFF7777));
|
||||
rightMarginColumn = config.getInteger(PROPERTY_RIGHT_MARGIN_COLUMN,
|
||||
0);
|
||||
styles = SyntaxStyles.read(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int drawUnselectedText(Graphics graphics, int x, int y, int p0,
|
||||
int p1) {
|
||||
setRenderingHits((Graphics2D) graphics);
|
||||
Font saveFont = graphics.getFont();
|
||||
Color saveColor = graphics.getColor();
|
||||
SyntaxDocument doc = (SyntaxDocument) getDocument();
|
||||
Segment segment = getLineBuffer();
|
||||
// Draw the right margin first, if needed. This way the text overalys
|
||||
// the margin
|
||||
if (rightMarginColumn > 0) {
|
||||
int m_x = rightMarginColumn * graphics.getFontMetrics().charWidth('m');
|
||||
int h = graphics.getFontMetrics().getHeight();
|
||||
graphics.setColor(rightMarginColor);
|
||||
graphics.drawLine(m_x, y, m_x, y - h);
|
||||
}
|
||||
try {
|
||||
// Colour the parts
|
||||
Iterator<Token> i = doc.getTokens(p0, p1);
|
||||
int start = p0;
|
||||
while (i.hasNext()) {
|
||||
Token t = i.next();
|
||||
// if there is a gap between the next token start and where we
|
||||
// should be starting (spaces not returned in tokens), then draw
|
||||
// it in the default type
|
||||
if (start < t.start) {
|
||||
doc.getText(start, t.start - start, segment);
|
||||
x = DEFAULT_STYLE.drawText(segment, x, y, graphics, this, start);
|
||||
}
|
||||
// t and s are the actual start and length of what we should
|
||||
// put on the screen. assume these are the whole token....
|
||||
int l = t.length;
|
||||
int s = t.start;
|
||||
// ... unless the token starts before p0:
|
||||
if (s < p0) {
|
||||
// token is before what is requested. adgust the length and s
|
||||
l -= (p0 - s);
|
||||
s = p0;
|
||||
}
|
||||
// if token end (s + l is still the token end pos) is greater
|
||||
// than p1, then just put up to p1
|
||||
if (s + l > p1) {
|
||||
l = p1 - s;
|
||||
}
|
||||
doc.getText(s, l, segment);
|
||||
x = styles.drawText(segment, x, y, graphics, this, t);
|
||||
start = t.end();
|
||||
}
|
||||
// now for any remaining text not tokenized:
|
||||
if (start < p1) {
|
||||
doc.getText(start, p1 - start, segment);
|
||||
x = DEFAULT_STYLE.drawText(segment, x, y, graphics, this, start);
|
||||
}
|
||||
} catch (BadLocationException ex) {
|
||||
log.log(Level.SEVERE, "Requested: " + ex.offsetRequested(), ex);
|
||||
} finally {
|
||||
graphics.setFont(saveFont);
|
||||
graphics.setColor(saveColor);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int drawSelectedText(Graphics graphics, int x, int y, int p0, int p1)
|
||||
throws BadLocationException {
|
||||
if (singleColorSelect) {
|
||||
if (rightMarginColumn > 0) {
|
||||
int m_x = rightMarginColumn * graphics.getFontMetrics().charWidth('m');
|
||||
int h = graphics.getFontMetrics().getHeight();
|
||||
graphics.setColor(rightMarginColor);
|
||||
graphics.drawLine(m_x, y, m_x, y - h);
|
||||
}
|
||||
return super.drawUnselectedText(graphics, x, y, p0, p1);
|
||||
} else {
|
||||
return drawUnselectedText(graphics, x, y, p0, p1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Rendering Hints o nthe Graphics. This is used so that
|
||||
* any painters can set the Rendering Hits to match the view.
|
||||
* @param g2d
|
||||
*/
|
||||
public static void setRenderingHits(Graphics2D g2d) {
|
||||
g2d.addRenderingHints(sysHints);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateDamage(javax.swing.event.DocumentEvent changes,
|
||||
Shape a,
|
||||
ViewFactory f) {
|
||||
super.updateDamage(changes, a, f);
|
||||
java.awt.Component host = getContainer();
|
||||
host.repaint();
|
||||
}
|
||||
/**
|
||||
* The values for the string key for Text Anti-Aliasing
|
||||
*/
|
||||
private static RenderingHints sysHints;
|
||||
|
||||
static {
|
||||
sysHints = null;
|
||||
try {
|
||||
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<RenderingHints.Key,?> map = (Map<RenderingHints.Key,?>)
|
||||
toolkit.getDesktopProperty("awt.font.desktophints");
|
||||
sysHints = new RenderingHints(map);
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2008 Ayman Al-Sairafi [email protected]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License
|
||||
* at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package jsyntaxpane;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Document;
|
||||
import javax.swing.text.Segment;
|
||||
|
||||
/**
|
||||
* A Token in a Document. Tokens do NOT store a reference to the
|
||||
* underlying SyntaxDocument, and must generally be obtained from
|
||||
* the SyntaxDocument methods. The reason for not storing the
|
||||
* SyntaxDocument is simply for memory, as the number of Tokens
|
||||
* per document can be large, you may end up with twice the memory
|
||||
* in a SyntaxDocument with Tokens than a simple PlainDocument.
|
||||
*
|
||||
* @author Ayman Al-Sairafi
|
||||
*/
|
||||
public class Token implements Serializable, Comparable {
|
||||
|
||||
public final TokenType type;
|
||||
public final int start;
|
||||
public final int length;
|
||||
/**
|
||||
* the pair value to use if this token is one of a pair:
|
||||
* This is how it is used:
|
||||
* The openning part will have a positive number X
|
||||
* The closing part will have a negative number X
|
||||
* X should be unique for a pair:
|
||||
* e.g. for [ pairValue = +1
|
||||
* for ] pairValue = -1
|
||||
*/
|
||||
public final byte pairValue;
|
||||
/**
|
||||
* The kind of the Document. This is only needed if proper Parsing
|
||||
* of a document is needed and it makes certain operations faster.
|
||||
* You can use any of the supplied Generic Values, or create your
|
||||
* language specific uses by using USER_FIRST + x;
|
||||
*/
|
||||
public final short kind = 0;
|
||||
|
||||
/**
|
||||
* Constructs a new token
|
||||
* @param type
|
||||
* @param start
|
||||
* @param length
|
||||
*/
|
||||
public Token(TokenType type, int start, int length) {
|
||||
this.type = type;
|
||||
this.start = start;
|
||||
this.length = length;
|
||||
this.pairValue = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new part of pair token
|
||||
* @param type
|
||||
* @param start
|
||||
* @param length
|
||||
* @param pairValue
|
||||
*/
|
||||
public Token(TokenType type, int start, int length, byte pairValue) {
|
||||
this.type = type;
|
||||
this.start = start;
|
||||
this.length = length;
|
||||
this.pairValue = pairValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof Object) {
|
||||
Token token = (Token) obj;
|
||||
return ((this.start == token.start) &&
|
||||
(this.length == token.length) &&
|
||||
(this.type.equals(token.type)));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (pairValue == 0) {
|
||||
return String.format("%s (%d, %d)", type, start, length);
|
||||
} else {
|
||||
return String.format("%s (%d, %d) (%d)", type, start, length, pairValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Object o) {
|
||||
Token t = (Token) o;
|
||||
if (this.start != t.start) {
|
||||
return (this.start - t.start);
|
||||
} else if (this.length != t.length) {
|
||||
return (this.length - t.length);
|
||||
} else {
|
||||
return this.type.compareTo(t.type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return the end position of the token.
|
||||
* @return start + length
|
||||
*/
|
||||
public int end() {
|
||||
return start + length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text of the token from this document
|
||||
* @param doc
|
||||
* @return
|
||||
*/
|
||||
public CharSequence getText(Document doc) {
|
||||
Segment text = new Segment();
|
||||
try {
|
||||
doc.getText(start, length, text);
|
||||
} catch (BadLocationException ex) {
|
||||
Logger.getLogger(Token.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} finally {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
public String getString(Document doc) {
|
||||
String result = "";
|
||||
try {
|
||||
result = doc.getText(start, length);
|
||||
} catch (BadLocationException ex) {
|
||||
Logger.getLogger(Token.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} finally {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2008 Ayman Al-Sairafi [email protected]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License
|
||||
* at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package jsyntaxpane;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* Two comparators to compare Tokens.
|
||||
* @author Ayman Al-Sairafi
|
||||
*/
|
||||
public class TokenComparators {
|
||||
|
||||
public static final Comparator<Token> LONGEST_FIRST = new LongestFirst();
|
||||
public static final Comparator<Token> SHORTEST_FIRST = new ShortestFirst();
|
||||
|
||||
private static class LongestFirst implements Comparator<Token>, Serializable {
|
||||
|
||||
@Override
|
||||
public int compare(Token t1, Token t2) {
|
||||
if (t1.start != t2.start) {
|
||||
return (t1.start - t2.start);
|
||||
} else if (t1.length != t2.length) {
|
||||
return (t2.length - t1.length);
|
||||
} else {
|
||||
return t1.type.compareTo(t2.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ShortestFirst implements Comparator<Token>, Serializable {
|
||||
|
||||
@Override
|
||||
public int compare(Token t1, Token t2) {
|
||||
if (t1.start != t2.start) {
|
||||
return (t1.start - t2.start);
|
||||
} else if (t1.length != t2.length) {
|
||||
return (t1.length - t2.length);
|
||||
} else {
|
||||
return t1.type.compareTo(t2.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2008 Ayman Al-Sairafi [email protected]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License
|
||||
* at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jsyntaxpane;
|
||||
|
||||
/**
|
||||
* Constants used by Tokens.
|
||||
* @author Ayman Al-Sairafi
|
||||
*/
|
||||
public class TokenConstants {
|
||||
/**
|
||||
* Token Kinds
|
||||
*/
|
||||
// Operators and separators - Suitable for Java Type Languages
|
||||
public static final short EQ = 1; // =
|
||||
public static final short GT = 2; // >
|
||||
public static final short LT = 3; // <
|
||||
public static final short NOT = 4; // !
|
||||
public static final short COMP = 5; // ~
|
||||
public static final short QUESTION = 6; // ?
|
||||
public static final short COLON = 7; // :
|
||||
public static final short EQEQ = 8; // ==
|
||||
public static final short LTEQ = 9; // <=
|
||||
public static final short GTEQ = 10; // >=
|
||||
public static final short NOTEQ = 11; // !=
|
||||
public static final short ANDAND = 12; // &&
|
||||
public static final short OROR = 13; // ||
|
||||
public static final short PLUSPLUS = 14; // ++
|
||||
public static final short MINUSMINUS = 15; // --
|
||||
public static final short PLUS = 16; // +
|
||||
public static final short MINUS = 17; // -
|
||||
public static final short MULT = 18; // *
|
||||
public static final short DIV = 19; // /
|
||||
public static final short AND = 20; // &
|
||||
public static final short OR = 21; // |
|
||||
public static final short XOR = 22; // ^
|
||||
public static final short MOD = 23; // %
|
||||
public static final short LSHIFT = 24; // <<
|
||||
public static final short RSHIFT = 25; // >>
|
||||
public static final short URSHIFT = 26; // >>>
|
||||
public static final short PLUSEQ = 27; // +=
|
||||
public static final short MINUSEQ = 28; // -=
|
||||
public static final short MULTEQ = 29; // *=
|
||||
public static final short DIVEQ = 30; // /=
|
||||
public static final short ANDEQ = 31; // &=
|
||||
public static final short OREQ = 32; // |=
|
||||
public static final short XOREQ = 33; // ^=
|
||||
public static final short MODEQ = 34; // %=
|
||||
public static final short LSHIFTEQ = 35; // <<=
|
||||
public static final short RSHIFTEQ = 36; // >>=
|
||||
public static final short URSHIFTEQ = 37; // >>>=
|
||||
public static final short LPAREN = 38; // (
|
||||
public static final short RPAREN = 39; // )
|
||||
public static final short LBRACE = 40; // {
|
||||
public static final short RBRACE = 41; // }
|
||||
public static final short LBRACK = 42; // [
|
||||
public static final short RBRACK = 43; // ]
|
||||
public static final short SEMICOLON = 44; // ;
|
||||
public static final short COMMA = 46; // ,
|
||||
public static final short DOT = 47; // .
|
||||
|
||||
// Keywords for Java Type Languages
|
||||
public static final short KW_START = 255;
|
||||
public static final short KW_abstract = KW_START + 0;
|
||||
public static final short KW_assert = KW_START + 1;
|
||||
public static final short KW_boolean = KW_START + 2;
|
||||
public static final short KW_break = KW_START + 3;
|
||||
public static final short KW_byte = KW_START + 4;
|
||||
public static final short KW_case = KW_START + 5;
|
||||
public static final short KW_catch = KW_START + 6;
|
||||
public static final short KW_char = KW_START + 7;
|
||||
public static final short KW_class = KW_START + 8;
|
||||
public static final short KW_const = KW_START + 9;
|
||||
public static final short KW_continue = KW_START + 10;
|
||||
public static final short KW_do = KW_START + 11;
|
||||
public static final short KW_double = KW_START + 12;
|
||||
public static final short KW_else = KW_START + 13;
|
||||
public static final short KW_extends = KW_START + 14;
|
||||
public static final short KW_final = KW_START + 15;
|
||||
public static final short KW_finally = KW_START + 16;
|
||||
public static final short KW_float = KW_START + 17;
|
||||
public static final short KW_for = KW_START + 18;
|
||||
public static final short KW_default = KW_START + 19;
|
||||
public static final short KW_implements = KW_START + 20;
|
||||
public static final short KW_import = KW_START + 21;
|
||||
public static final short KW_instanceof = KW_START + 22;
|
||||
public static final short KW_int = KW_START + 23;
|
||||
public static final short KW_interface = KW_START + 24;
|
||||
public static final short KW_long = KW_START + 25;
|
||||
public static final short KW_native = KW_START + 26;
|
||||
public static final short KW_new = KW_START + 27;
|
||||
public static final short KW_goto = KW_START + 28;
|
||||
public static final short KW_if = KW_START + 29;
|
||||
public static final short KW_public = KW_START + 30;
|
||||
public static final short KW_short = KW_START + 31;
|
||||
public static final short KW_super = KW_START + 32;
|
||||
public static final short KW_switch = KW_START + 33;
|
||||
public static final short KW_synchronized = KW_START + 34;
|
||||
public static final short KW_package = KW_START + 35;
|
||||
public static final short KW_private = KW_START + 36;
|
||||
public static final short KW_protected = KW_START + 37;
|
||||
public static final short KW_transient = KW_START + 38;
|
||||
public static final short KW_return = KW_START + 39;
|
||||
public static final short KW_void = KW_START + 40;
|
||||
public static final short KW_static = KW_START + 41;
|
||||
public static final short KW_while = KW_START + 42;
|
||||
public static final short KW_this = KW_START + 43;
|
||||
public static final short KW_throw = KW_START + 44;
|
||||
public static final short KW_throws = KW_START + 45;
|
||||
public static final short KW_try = KW_START + 46;
|
||||
public static final short KW_volatile = KW_START + 47;
|
||||
public static final short KW_strictfp = KW_START + 48;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2008 Ayman Al-Sairafi [email protected]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License
|
||||
* at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package jsyntaxpane;
|
||||
|
||||
/**
|
||||
* These are the various token types supported by JSyntaxPane.
|
||||
*
|
||||
* @author ayman
|
||||
*/
|
||||
public enum TokenType {
|
||||
|
||||
OPERATOR, // Language operators
|
||||
DELIMITER, // Delimiters. Constructs that are not necessarily operators for a language
|
||||
KEYWORD, // language reserved keywords
|
||||
KEYWORD2, // Other language reserved keywords, like C #defines
|
||||
IDENTIFIER, // identifiers, variable names, class names
|
||||
NUMBER, // numbers in various formats
|
||||
STRING, // String
|
||||
STRING2, // For highlighting meta chars within a String
|
||||
COMMENT, // comments
|
||||
COMMENT2, // special stuff within comments
|
||||
REGEX, // regular expressions
|
||||
REGEX2, // special chars within regular expressions
|
||||
TYPE, // Types, usually not keywords, but supported by the language
|
||||
TYPE2, // Types from standard libraries
|
||||
TYPE3, // Types for users
|
||||
DEFAULT, // any other text
|
||||
WARNING, // Text that should be highlighted as a warning
|
||||
ERROR; // Text that signals an error
|
||||
|
||||
/**
|
||||
* Tests if the given token is a Comment Token.
|
||||
* @param t
|
||||
* @return
|
||||
*/
|
||||
public static boolean isComment(Token t) {
|
||||
if (t != null && (t.type == COMMENT || t.type == COMMENT2)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the given token is a Keyword Token.
|
||||
* @param t
|
||||
* @return
|
||||
*/
|
||||
public static boolean isKeyword(Token t) {
|
||||
if (t != null && (t.type == KEYWORD || t.type == KEYWORD2)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests if the given token is a String Token.
|
||||
* @param t
|
||||
* @return
|
||||
*/
|
||||
public static boolean isString(Token t) {
|
||||
if (t != null && (t.type == STRING || t.type == STRING2)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+623
@@ -0,0 +1,623 @@
|
||||
/*
|
||||
* Copyright 2008 Ayman Al-Sairafi [email protected]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License
|
||||
* at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package jsyntaxpane.actions;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.MutableComboBoxModel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Document;
|
||||
import javax.swing.text.EditorKit;
|
||||
import javax.swing.text.Element;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import javax.swing.text.PlainDocument;
|
||||
import jsyntaxpane.DefaultSyntaxKit;
|
||||
import jsyntaxpane.SyntaxDocument;
|
||||
import jsyntaxpane.Token;
|
||||
|
||||
/**
|
||||
* Various utility methods to work on JEditorPane and its SyntaxDocument
|
||||
* for use by Actions
|
||||
*
|
||||
* @author Ayman Al-Sairafi
|
||||
*/
|
||||
public class ActionUtils {
|
||||
|
||||
private ActionUtils() {
|
||||
}
|
||||
|
||||
private static ActionUtils instance = null;
|
||||
|
||||
/**
|
||||
* Get the Singleton instance. Will be created lazily.
|
||||
* @return
|
||||
*/
|
||||
public static synchronized ActionUtils getInstance() {
|
||||
if(instance == null) {
|
||||
instance = new ActionUtils();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the indentation of a line of text. This is the subString from
|
||||
* beginning of line to the first non-space char
|
||||
* @param line the line of text
|
||||
* @return indentation of line.
|
||||
*/
|
||||
public static String getIndent(String line) {
|
||||
if (line == null || line.length() == 0) {
|
||||
return "";
|
||||
}
|
||||
int i = 0;
|
||||
while (i < line.length() && line.charAt(i) == ' ') {
|
||||
i++;
|
||||
}
|
||||
return line.substring(0, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the lines that span the selection (split as an array of Strings)
|
||||
* if there is no selection then current line is returned.
|
||||
*
|
||||
* Note that the strings returned will not contain the terminating line feeds
|
||||
* If the document is empty, then an empty string array is returned. So
|
||||
* you can always iterate over the returned array without a null check
|
||||
*
|
||||
* The text component will then have the full lines set as selection
|
||||
* @param target
|
||||
* @return String[] of lines spanning selection / or line containing dot
|
||||
*/
|
||||
public static String[] getSelectedLines(JTextComponent target) {
|
||||
String[] lines = null;
|
||||
try {
|
||||
PlainDocument pDoc = (PlainDocument) target.getDocument();
|
||||
int start = pDoc.getParagraphElement(target.getSelectionStart()).getStartOffset();
|
||||
int end;
|
||||
if (target.getSelectionStart() == target.getSelectionEnd()) {
|
||||
end = pDoc.getParagraphElement(target.getSelectionEnd()).getEndOffset();
|
||||
} else {
|
||||
// if more than one line is selected, we need to subtract one from the end
|
||||
// so that we do not select the line with the caret and no selection in it
|
||||
end = pDoc.getParagraphElement(target.getSelectionEnd() - 1).getEndOffset();
|
||||
}
|
||||
target.select(start, end);
|
||||
lines = pDoc.getText(start, end - start).split("\n");
|
||||
target.select(start, end);
|
||||
} catch (BadLocationException ex) {
|
||||
Logger.getLogger(ActionUtils.class.getName()).log(Level.SEVERE, null, ex);
|
||||
lines = EMPTY_STRING_ARRAY;
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the line of text at the TextComponent's current position
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public static String getLine(JTextComponent target) {
|
||||
return getLineAt(target, target.getCaretPosition());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the line of text at the given position. The returned value may
|
||||
* be null. It will not contain the trailing new-line character.
|
||||
* @param target the text component
|
||||
* @param pos char position
|
||||
* @return
|
||||
*/
|
||||
public static String getLineAt(JTextComponent target, int pos) {
|
||||
String line = null;
|
||||
Document doc = target.getDocument();
|
||||
if (doc instanceof PlainDocument) {
|
||||
PlainDocument pDoc = (PlainDocument) doc;
|
||||
int start = pDoc.getParagraphElement(pos).getStartOffset();
|
||||
int end = pDoc.getParagraphElement(pos).getEndOffset();
|
||||
try {
|
||||
line = doc.getText(start, end - start);
|
||||
if (line != null && line.endsWith("\n")) {
|
||||
line = line.substring(0, line.length() - 1);
|
||||
}
|
||||
} catch (BadLocationException ex) {
|
||||
Logger.getLogger(ActionUtils.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Frame that contains this component or null if the component
|
||||
* is not within a Window or the containing window is not a frame
|
||||
* @param comp
|
||||
* @return
|
||||
*/
|
||||
public static Frame getFrameFor(Component comp) {
|
||||
Window w = SwingUtilities.getWindowAncestor(comp);
|
||||
if (w != null && w instanceof Frame) {
|
||||
Frame frame = (Frame) w;
|
||||
return frame;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the the Token at pos as a String
|
||||
* @param doc
|
||||
* @param pos
|
||||
* @return
|
||||
*/
|
||||
public static String getTokenStringAt(
|
||||
SyntaxDocument doc, int pos) {
|
||||
String word = "";
|
||||
Token t = doc.getTokenAt(pos);
|
||||
if (t != null) {
|
||||
try {
|
||||
word = doc.getText(t.start, t.length);
|
||||
} catch (BadLocationException ex) {
|
||||
Logger.getLogger(ActionUtils.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
return word;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function that will return the SyntaxDocument attached to the
|
||||
* given text component. Return null if the document is not a
|
||||
* SyntaxDocument, or if the text component is null
|
||||
* @param component
|
||||
* @return
|
||||
*/
|
||||
public static SyntaxDocument getSyntaxDocument(JTextComponent component) {
|
||||
if (component == null) {
|
||||
return null;
|
||||
}
|
||||
Document doc = component.getDocument();
|
||||
if (doc instanceof SyntaxDocument) {
|
||||
return (SyntaxDocument) doc;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Line Number at the give position of the editor component.
|
||||
* The first line number is ZERO
|
||||
* @param editor
|
||||
* @param pos
|
||||
* @return line number
|
||||
* @throws javax.swing.text.BadLocationException
|
||||
*/
|
||||
public static int getLineNumber(JTextComponent editor, int pos)
|
||||
throws BadLocationException {
|
||||
if (getSyntaxDocument(editor) != null) {
|
||||
SyntaxDocument sdoc = getSyntaxDocument(editor);
|
||||
return sdoc.getLineNumberAt(pos);
|
||||
} else {
|
||||
Document doc = editor.getDocument();
|
||||
return doc.getDefaultRootElement().getElementIndex(pos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the column number at given position of editor. The first column is
|
||||
* ZERO
|
||||
* @param editor
|
||||
* @param pos
|
||||
* @return the 0 based column number
|
||||
* @throws javax.swing.text.BadLocationException
|
||||
*/
|
||||
public static int getColumnNumber(JTextComponent editor, int pos)
|
||||
throws BadLocationException {
|
||||
// speedup if the pos is 0
|
||||
if(pos == 0) {
|
||||
return 0;
|
||||
}
|
||||
Rectangle r = editor.modelToView(pos);
|
||||
int start = editor.viewToModel(new Point(0, r.y));
|
||||
int column = pos - start;
|
||||
return column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the closest position within the document of the component that
|
||||
* has given line and column.
|
||||
* @param editor
|
||||
* @param line the first being 1
|
||||
* @param column the first being 1
|
||||
* @return the closest positon for the text component at given line and
|
||||
* column
|
||||
*/
|
||||
public static int getDocumentPosition(JTextComponent editor, int line,
|
||||
int column) {
|
||||
int lineHeight = editor.getFontMetrics(editor.getFont()).getHeight();
|
||||
int charWidth = editor.getFontMetrics(editor.getFont()).charWidth('m');
|
||||
int y = line * lineHeight;
|
||||
int x = column * charWidth;
|
||||
Point pt = new Point(x, y);
|
||||
int pos = editor.viewToModel(pt);
|
||||
return pos;
|
||||
}
|
||||
|
||||
public static int getLineCount(JTextComponent pane) {
|
||||
SyntaxDocument sdoc = getSyntaxDocument(pane);
|
||||
if (sdoc != null) {
|
||||
return sdoc.getLineCount();
|
||||
}
|
||||
int count = 0;
|
||||
try {
|
||||
int p = pane.getDocument().getLength() - 1;
|
||||
if (p > 0) {
|
||||
count = getLineNumber(pane, p);
|
||||
}
|
||||
} catch (BadLocationException ex) {
|
||||
Logger.getLogger(ActionUtils.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the given item into the combo box, and set it as first selected
|
||||
* item. If the item already exists, it is removed, so there are no
|
||||
* duplicates.
|
||||
* @param combo
|
||||
* @param item the item to insert. if it's null, then nothing is inserted
|
||||
*/
|
||||
public static void insertIntoCombo(JComboBox combo, Object item) {
|
||||
if(item == null) {
|
||||
return;
|
||||
}
|
||||
MutableComboBoxModel model = (MutableComboBoxModel) combo.getModel();
|
||||
if (model.getSize() == 0) {
|
||||
model.insertElementAt(item, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
Object o = model.getElementAt(0);
|
||||
if (o.equals(item)) {
|
||||
return;
|
||||
}
|
||||
model.removeElement(item);
|
||||
model.insertElementAt(item, 0);
|
||||
combo.setSelectedIndex(0);
|
||||
}
|
||||
|
||||
public static void insertMagicString(JTextComponent target, String result) {
|
||||
try {
|
||||
insertMagicString(target, target.getCaretPosition(), result);
|
||||
} catch (BadLocationException ex) {
|
||||
Logger.getLogger(ActionUtils.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeat the string source repeat times.
|
||||
* If repeats == 0 then empty String is returned
|
||||
* if source is null, then empty string is returned
|
||||
* @param source
|
||||
* @param repeat
|
||||
* @return source String repeated repeat times.
|
||||
*/
|
||||
public static String repeatString(String source, int repeat) {
|
||||
if (repeat < 0) {
|
||||
throw new IllegalArgumentException("Cannot repeat " + repeat + " times.");
|
||||
}
|
||||
if (repeat == 0 || source == null || source.length() == 0) {
|
||||
return "";
|
||||
}
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for (int i = 0; i < repeat; i++) {
|
||||
buffer.append(source);
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given string is null, empty or contains whitespace only
|
||||
* @param string
|
||||
* @return true if string is null, empty or contains whitespace only, false
|
||||
* otherwise.
|
||||
*/
|
||||
public static boolean isEmptyOrBlanks(String string) {
|
||||
if (string == null || string.length() == 0) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < string.length(); i++) {
|
||||
char c = string.charAt(i);
|
||||
if (!Character.isWhitespace(c)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the TabStop property for the given text component, or 0 if not
|
||||
* used
|
||||
* @param text
|
||||
* @return
|
||||
*/
|
||||
public static int getTabSize(JTextComponent text) {
|
||||
Integer tabs = (Integer) text.getDocument().getProperty(PlainDocument.tabSizeAttribute);
|
||||
return (null == tabs) ? 0 : tabs.intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the given String into the textcomponent. If the string contains
|
||||
* the | vertical BAr char, then it will not be inserted, and the cursor will
|
||||
* be set to its location.
|
||||
* If there are TWO vertical bars, then the text between them will be selected
|
||||
* If the toInsert String is multiLine, then indentation of all following lines
|
||||
* will be the same as the first line. TAB characters will be replaced by
|
||||
* the number of spaces in the document's TAB property.
|
||||
* @param target
|
||||
* @param dot
|
||||
* @param toInsert
|
||||
* @throws javax.swing.text.BadLocationException
|
||||
*/
|
||||
public static void insertMagicString(JTextComponent target, int dot, String toInsert)
|
||||
throws BadLocationException {
|
||||
Document doc = target.getDocument();
|
||||
String[] lines = toInsert.split("\n");
|
||||
if (lines.length > 1) {
|
||||
// multi line strings will need to be indented
|
||||
String tabToSpaces = getTab(target);
|
||||
String currentLine = getLineAt(target, dot);
|
||||
String currentIndent = getIndent(currentLine);
|
||||
StringBuilder sb = new StringBuilder(toInsert.length());
|
||||
boolean firstLine = true;
|
||||
for (String l : lines) {
|
||||
if (!firstLine) {
|
||||
sb.append(currentIndent);
|
||||
}
|
||||
firstLine = false;
|
||||
// replace tabs with spaces.
|
||||
sb.append(l.replace("\t", tabToSpaces));
|
||||
sb.append("\n");
|
||||
}
|
||||
toInsert = sb.toString();
|
||||
}
|
||||
if (toInsert.indexOf('|') >= 0) {
|
||||
int ofst = toInsert.indexOf('|');
|
||||
int ofst2 = toInsert.indexOf('|', ofst + 1);
|
||||
toInsert = toInsert.replace("|", "");
|
||||
doc.insertString(dot, toInsert, null);
|
||||
dot = target.getCaretPosition();
|
||||
int strLength = toInsert.length();
|
||||
if (ofst2 > 0) {
|
||||
// note that we already removed the first |, so end offset is now
|
||||
// one less than what it was.
|
||||
target.select(dot + ofst - strLength, dot + ofst2 - strLength - 1);
|
||||
} else {
|
||||
target.setCaretPosition(dot + ofst - strLength);
|
||||
}
|
||||
} else {
|
||||
doc.insertString(dot, toInsert, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand the string template and replaces the selection with the expansion
|
||||
* of the template. The template String may contain any of the following
|
||||
* special tags.
|
||||
*
|
||||
* <li>{@code #{selection}} replaced with the selection, if any. If there is
|
||||
* no selection, then the {@code #{selection}} tag will be removed.
|
||||
* <li>{@code #{p:any text}} will be replaced by {@code any text} and then
|
||||
* set selection to {@code any text}
|
||||
*
|
||||
* This method properly handles indentation as follows:
|
||||
* The indentation of the whole block will match the indentation of the caret
|
||||
* line, or the line with the beginning of the selection, if the selection is
|
||||
* in whole line, i.e.e one or more lines of selected text. {@see selectLines()}
|
||||
*
|
||||
* @param target JEditorCOmponent to be affected
|
||||
* @param templateLines template split as a String array of lines.
|
||||
*
|
||||
* @see insertLinesTemplate
|
||||
*/
|
||||
public static void insertLinesTemplate(JTextComponent target, String[] templateLines) {
|
||||
// get some stuff we'll need:
|
||||
String thisIndent = getIndent(getLineAt(target, target.getSelectionStart()));
|
||||
String[] selLines = getSelectedLines(target);
|
||||
int selStart = -1, selEnd = -1;
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (String tLine : templateLines) {
|
||||
int selNdx = tLine.indexOf("#{selection}");
|
||||
if (selNdx >= 0) {
|
||||
// for each of the selected lines:
|
||||
for (String selLine : selLines) {
|
||||
sb.append(tLine.subSequence(0, selNdx));
|
||||
sb.append(selLine);
|
||||
sb.append('\n');
|
||||
}
|
||||
} else {
|
||||
sb.append(thisIndent);
|
||||
// now check for any ptags
|
||||
Matcher pm = PTAGS_PATTERN.matcher(tLine);
|
||||
int lineStart = sb.length();
|
||||
while (pm.find()) {
|
||||
selStart = pm.start() + lineStart;
|
||||
pm.appendReplacement(sb, pm.group(1));
|
||||
selEnd = sb.length();
|
||||
}
|
||||
pm.appendTail(sb);
|
||||
sb.append('\n');
|
||||
}
|
||||
}
|
||||
int ofst = target.getSelectionStart();
|
||||
target.replaceSelection(sb.toString());
|
||||
if (selStart >= 0) {
|
||||
// target.setCaretPosition(selStart);
|
||||
target.select(ofst + selStart, ofst + selEnd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand the string template and replaces the selection with the expansion
|
||||
* of the template. The template String may contain any of the following
|
||||
* special tags.
|
||||
*
|
||||
* <li>{@code #{selection}} replaced with the selection, if any. If there is
|
||||
* no selection, then the {@code #{selection}} tag will be removed.
|
||||
* <li>{@code #{p:AnyText}} will be replaced by {@code any text} and then
|
||||
* set the text selection to {@code AnyText}
|
||||
*
|
||||
* This methood does NOT perform any indentation and the template should
|
||||
* generally span one line only
|
||||
*
|
||||
* @param target
|
||||
* @param template
|
||||
*/
|
||||
public static void insertSimpleTemplate(JTextComponent target, String template) {
|
||||
String selected = target.getSelectedText();
|
||||
selected = (selected == null) ? "" : selected;
|
||||
StringBuffer sb = new StringBuffer(template.length());
|
||||
Matcher pm = PTAGS_PATTERN.matcher(template.replace(TEMPLATE_SELECTION, selected));
|
||||
int selStart = -1, selEnd = -1;
|
||||
int lineStart = 0;
|
||||
while (pm.find()) {
|
||||
selStart = pm.start() + lineStart;
|
||||
pm.appendReplacement(sb, pm.group(1));
|
||||
selEnd = sb.length();
|
||||
}
|
||||
pm.appendTail(sb);
|
||||
// String expanded = template.replace(TEMPLATE_SELECTION, selected);
|
||||
|
||||
if (selStart >= 0) {
|
||||
selStart += target.getSelectionStart();
|
||||
selEnd += target.getSelectionStart();
|
||||
}
|
||||
target.replaceSelection(sb.toString());
|
||||
if (selStart >= 0) {
|
||||
// target.setCaretPosition(selStart);
|
||||
target.select(selStart, selEnd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the selection is multi lined, then the full lines are selected,
|
||||
* otherwise, nothing is done.
|
||||
* @param target
|
||||
* @return true if the selection is multi-line, or a whole line
|
||||
*/
|
||||
public static boolean selectLines(JTextComponent target) {
|
||||
if (target.getSelectionStart() == target.getSelectionEnd()) {
|
||||
return false;
|
||||
}
|
||||
PlainDocument pDoc = (PlainDocument) target.getDocument();
|
||||
Element es = pDoc.getParagraphElement(target.getSelectionStart());
|
||||
// if more than one line is selected, we need to subtract one from the end
|
||||
// so that we do not select the line with the caret and no selection in it
|
||||
Element ee = pDoc.getParagraphElement(target.getSelectionEnd() - 1);
|
||||
if (es.equals(ee) && ee.getEndOffset() != target.getSelectionEnd()) {
|
||||
return false;
|
||||
}
|
||||
int start = es.getStartOffset();
|
||||
int end = ee.getEndOffset();
|
||||
target.select(start, end - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the caret position of the given target to the given line and column
|
||||
* @param target
|
||||
* @param line the first being 1
|
||||
* @param column the first being 1
|
||||
*/
|
||||
public static void setCaretPosition(JTextComponent target, int line, int column) {
|
||||
int p = getDocumentPosition(target, line, column);
|
||||
target.setCaretPosition(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string with number of spaces equal to the tab-stop of the TextComponent
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public static String getTab(JTextComponent target) {
|
||||
return SPACES.substring(0, getTabSize(target));
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches all actions of a JTextComponent for ab action of the given class and returns
|
||||
* the first one that matches that class, or null if no Action is found
|
||||
* @param <T>
|
||||
* @param target
|
||||
* @param aClass
|
||||
* @return Action object of that class or null
|
||||
*/
|
||||
public static <T extends Action> T getAction(JTextComponent target, Class<T> aClass) {
|
||||
for (Object k : target.getActionMap().allKeys()) {
|
||||
Action a = target.getActionMap().get(k);
|
||||
if (aClass.isInstance(a)) {
|
||||
@SuppressWarnings("unchecked")
|
||||
T t = (T) a;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DefaultSyntaxKit of this target, or null if the target does not
|
||||
* have a DefaultSyntaxKit
|
||||
* @param target
|
||||
* @return kit or null
|
||||
*/
|
||||
public static DefaultSyntaxKit getSyntaxKit(JTextComponent target) {
|
||||
DefaultSyntaxKit kit = null;
|
||||
if (target instanceof JEditorPane) {
|
||||
JEditorPane jEditorPane = (JEditorPane) target;
|
||||
EditorKit k = jEditorPane.getEditorKit();
|
||||
if (k instanceof DefaultSyntaxKit) {
|
||||
kit = (DefaultSyntaxKit) k;
|
||||
}
|
||||
}
|
||||
return kit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and send a KeyPress KeyEvent to the component given
|
||||
* @param target Editor to get the action
|
||||
* @param v_key from KeyEvent.V_ constants
|
||||
* @param modifiers from KeyEvent.*MASK constants
|
||||
*/
|
||||
public static void sendKeyPress(JTextComponent target, int v_key, int modifiers) {
|
||||
KeyEvent ke = new KeyEvent(target, KeyEvent.KEY_PRESSED, System.currentTimeMillis(),
|
||||
modifiers, v_key, KeyEvent.CHAR_UNDEFINED);
|
||||
target.dispatchEvent(ke);
|
||||
}
|
||||
// This is used internally to avoid NPE if we have no Strings
|
||||
final static String[] EMPTY_STRING_ARRAY = new String[0];
|
||||
// This is used to quickly create Strings of at most 16 spaces (using substring)
|
||||
final static String SPACES = " ";
|
||||
/**
|
||||
* The Pattern to use for PTags in insertSimpleTemplate
|
||||
*/
|
||||
public static final Pattern PTAGS_PATTERN = Pattern.compile("\\#\\{p:([^}]*)\\}");
|
||||
public static final String TEMPLATE_SELECTION = "#{selection}";
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2008 Ayman Al-Sairafi [email protected]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License
|
||||
* at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package jsyntaxpane.actions;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.event.CaretEvent;
|
||||
import javax.swing.event.CaretListener;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import jsyntaxpane.SyntaxDocument;
|
||||
|
||||
/**
|
||||
* This class can be used to display the caret location in friendly manner for
|
||||
* an EditorPane.
|
||||
*
|
||||
* @author Ayman Al-Sairafi
|
||||
*/
|
||||
public class CaretMonitor implements CaretListener {
|
||||
|
||||
private JLabel label;
|
||||
private JTextComponent text;
|
||||
|
||||
/**
|
||||
* The format string to use when there is no selected:
|
||||
* the arguments are:
|
||||
* 1 based line number
|
||||
* 1 based column number
|
||||
* 0 based position
|
||||
*/
|
||||
private String noSelectionFormat = "%d:%d (%d)";
|
||||
/**
|
||||
* The format string to use when something is selected:
|
||||
* the arguments are:
|
||||
* 1 based line number for selection start
|
||||
* 1 based column number for selection start
|
||||
* 1 based line number for selection end
|
||||
* 1 based column number for selection end
|
||||
* length of selection
|
||||
* 0 based start position
|
||||
* 0 based end position
|
||||
*/
|
||||
private String selectionFormat = "%d:%d - %d:%d (%d)";
|
||||
|
||||
public CaretMonitor(JTextComponent text, JLabel label) {
|
||||
this.label = label;
|
||||
this.text = text;
|
||||
text.addCaretListener(this);
|
||||
updateLabel(text.getCaretPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void caretUpdate(CaretEvent evt) {
|
||||
updateLabel(evt.getDot());
|
||||
}
|
||||
|
||||
protected void updateLabel(int pos) {
|
||||
if (text.getDocument() instanceof SyntaxDocument) {
|
||||
try {
|
||||
if (text.getSelectionStart() == text.getSelectionEnd()) {
|
||||
String loc = String.format(noSelectionFormat,
|
||||
ActionUtils.getLineNumber(text, pos) + 1,
|
||||
ActionUtils.getColumnNumber(text, pos) + 1,
|
||||
pos);
|
||||
label.setText(loc);
|
||||
} else {
|
||||
int start = text.getSelectionStart();
|
||||
int end = text.getSelectionEnd();
|
||||
String loc = String.format(selectionFormat,
|
||||
ActionUtils.getLineNumber(text, start) + 1,
|
||||
ActionUtils.getColumnNumber(text, start) + 1,
|
||||
ActionUtils.getLineNumber(text, end) + 1,
|
||||
ActionUtils.getColumnNumber(text, end) + 1,
|
||||
(end - start),
|
||||
start,
|
||||
end);
|
||||
label.setText(loc);
|
||||
}
|
||||
} catch (BadLocationException ex) {
|
||||
label.setText("Ex: " + ex.getMessage());
|
||||
}
|
||||
} else {
|
||||
label.setText(String.format(noSelectionFormat, 1, 1, 1));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
text.removeCaretListener(this);
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
public String getNoSelectionFormat() {
|
||||
return noSelectionFormat;
|
||||
}
|
||||
|
||||
public void setNoSelectionFormat(String noSelectionFormat) {
|
||||
this.noSelectionFormat = noSelectionFormat;
|
||||
}
|
||||
|
||||
public String getSelectionFormat() {
|
||||
return selectionFormat;
|
||||
}
|
||||
|
||||
public void setSelectionFormat(String selectionFormat) {
|
||||
this.selectionFormat = selectionFormat;
|
||||
}
|
||||
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2008 Ayman Al-Sairafi [email protected]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License
|
||||
* at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package jsyntaxpane.actions;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import jsyntaxpane.SyntaxDocument;
|
||||
import jsyntaxpane.Token;
|
||||
import jsyntaxpane.actions.gui.ComboCompletionDialog;
|
||||
import jsyntaxpane.util.JarServiceProvider;
|
||||
|
||||
/**
|
||||
* ComboBox like Completion Action:
|
||||
* This will display a list of items to choose from, it can be used similar to
|
||||
* IntelliSense. The List is obtained from a plain text file, each line being
|
||||
* an item in the list.
|
||||
*
|
||||
* @author Ayman Al-Sairafi
|
||||
*/
|
||||
public class ComboCompletionAction extends DefaultSyntaxAction {
|
||||
|
||||
Map<String, String> completions;
|
||||
ComboCompletionDialog dlg;
|
||||
private List<String> items;
|
||||
|
||||
public ComboCompletionAction() {
|
||||
super("COMBO_COMPLETION");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(JTextComponent target, SyntaxDocument sdoc,
|
||||
int dot, ActionEvent e) {
|
||||
if (sdoc == null) {
|
||||
return;
|
||||
}
|
||||
Token token = sdoc.getTokenAt(dot);
|
||||
String abbrev = "";
|
||||
if (token != null) {
|
||||
abbrev = token.getString(sdoc);
|
||||
target.select(token.start, token.end());
|
||||
}
|
||||
if (dlg == null) {
|
||||
dlg = new ComboCompletionDialog(target);
|
||||
}
|
||||
dlg.displayFor(abbrev, items);
|
||||
}
|
||||
|
||||
public void setItemsURL(String value) {
|
||||
items = JarServiceProvider.readLines(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the items to display in the combo
|
||||
* @return
|
||||
*/
|
||||
public List<String> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the items to display in the combo.
|
||||
* @param items
|
||||
*/
|
||||
public void setItems(List<String> items) {
|
||||
this.items = items;
|
||||
}
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2008 Ayman Al-Sairafi [email protected]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License
|
||||
* at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package jsyntaxpane.actions;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import jsyntaxpane.SyntaxDocument;
|
||||
import jsyntaxpane.Token;
|
||||
import jsyntaxpane.actions.gui.ComboCompletionDialog;
|
||||
import jsyntaxpane.util.StringUtils;
|
||||
|
||||
/**
|
||||
* This action will try to complete the word at the cursor by
|
||||
* looking for a matching word in this document that starts with
|
||||
* the same letters.
|
||||
*
|
||||
* This makes use of the SyntaxDocument.getWordAt, which requires
|
||||
* a Regexp Pattern. The Pattern should match any word regardless of
|
||||
* the Tokens.
|
||||
*
|
||||
* This Regexp is configurable with {@code ACTION_NAME.WordsRegexp}.
|
||||
* The default Regexp is \w+ (any word char)
|
||||
*
|
||||
* @author Ayman Al-Sairafi
|
||||
*/
|
||||
public class CompleteWordAction extends DefaultSyntaxAction {
|
||||
|
||||
public CompleteWordAction() {
|
||||
super("COMPLETE_WORD");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(JTextComponent target, SyntaxDocument sdoc,
|
||||
int dot, ActionEvent e) {
|
||||
Token current = sdoc.getWordAt(dot, wordsPattern);
|
||||
if (current == null) {
|
||||
return;
|
||||
}
|
||||
String cw = current.getString(sdoc);
|
||||
target.select(current.start, current.end());
|
||||
|
||||
sdoc.readLock();
|
||||
List<String> matches = new ArrayList<String>();
|
||||
Matcher m = sdoc.getMatcher(wordsPattern, 0, current.start);
|
||||
addWords(m, cw, matches);
|
||||
m = sdoc.getMatcher(wordsPattern, current.end(), sdoc.getLength() - current.end());
|
||||
addWords(m, cw, matches);
|
||||
sdoc.readUnlock();
|
||||
if (matches.size() == 0) {
|
||||
return;
|
||||
}
|
||||
if (matches.size() == 1) {
|
||||
target.replaceSelection(matches.get(0));
|
||||
return;
|
||||
}
|
||||
if (dlg == null) {
|
||||
dlg = new ComboCompletionDialog(target);
|
||||
}
|
||||
dlg.displayFor(cw, matches);
|
||||
}
|
||||
|
||||
public void setWordsRegexp(String value) {
|
||||
wordsPattern = Pattern.compile(value);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add words from the matcher m that match the word abbr to matches
|
||||
* List
|
||||
* @param m matcher instance, could be null, to iterate through
|
||||
* @param abbr abbriviated word
|
||||
* @param matches List of matches
|
||||
*/
|
||||
private void addWords(Matcher m, String abbr, List<String> matches) {
|
||||
while (m != null && m.find()) {
|
||||
String word = m.group();
|
||||
if (StringUtils.camelCaseMatch(word, abbr)) {
|
||||
if (!matches.contains(word)) {
|
||||
matches.add(word);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private ComboCompletionDialog dlg;
|
||||
private Pattern wordsPattern = DEFAULT_WORDS_REGEXP;
|
||||
private static final Pattern DEFAULT_WORDS_REGEXP = Pattern.compile("\\w+");
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2008 Ayman Al-Sairafi [email protected]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License
|
||||
* at http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package jsyntaxpane.actions;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.net.URL;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import javax.swing.text.TextAction;
|
||||
import jsyntaxpane.SyntaxDocument;
|
||||
import jsyntaxpane.util.Configuration;
|
||||
import jsyntaxpane.util.ReflectUtils;
|
||||
|
||||
/**
|
||||
* The DefaultSyntaxAction. You can extend this class or implement the interface
|
||||
* SyntaxAction to create your own actions.
|
||||
*
|
||||
* @author Ayman Al-Sairafi
|
||||
*/
|
||||
abstract public class DefaultSyntaxAction extends TextAction implements SyntaxAction {
|
||||
|
||||
public DefaultSyntaxAction(String actionName) {
|
||||
super(actionName);
|
||||
putValue(NAME, actionName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void config(Configuration config, String name) {
|
||||
// find setter methods for each property key:
|
||||
String actionName = name.substring(ACTION_PREFIX.length());
|
||||
for (Configuration.StringKeyMatcher m : config.getKeys(
|
||||
Pattern.compile(Pattern.quote(name) + "\\.((\\w|-)+)"))) {
|
||||
if (!ReflectUtils.callSetter(this, m.group1, m.value)) {
|
||||
putValue(m.group1, m.value);
|
||||
}
|
||||
}
|
||||
// if we did not put a name, use the action name
|
||||
if (getValue(NAME) == null) {
|
||||
putValue(NAME, actionName);
|
||||
}
|
||||
// if we did not put an icon, try and find one using our name
|
||||
if (getValue(SMALL_ICON) == null) {
|
||||
setSmallIcon(actionName + ".png");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JTextComponent text = getTextComponent(e);
|
||||
SyntaxDocument sdoc = ActionUtils.getSyntaxDocument(text);
|
||||
if (text != null) {
|
||||
actionPerformed(text, sdoc, text.getCaretPosition(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method that will be called if the Action is performed on a
|
||||
* JTextComponent. SyntaxActions should generally override this method.
|
||||
* @param target (non-null JTextComponent from Action.getSource
|
||||
* @param sDoc (SyntaxDOcument of the text component, could be null)
|
||||
* @param dot (position of caret at text document)
|
||||
* @param e actual ActionEvent passed to actionPerformed
|
||||
*/
|
||||
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
|
||||
int dot, ActionEvent e) {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Action " + getValue(NAME) + "of type " + this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the MenuText for the Action
|
||||
* @param text
|
||||
*/
|
||||
public final void setMenuText(String text) {
|
||||
putValue(NAME, text);
|
||||
// also set the SHORT_DESCRIPTIOn if it was not set, so we have
|
||||
// at least some tooltip for toolbar buttons
|
||||
if (getValue(SHORT_DESCRIPTION) == null) {
|
||||
putValue(SHORT_DESCRIPTION, text);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the ToolTip for the Action
|
||||
* @param text
|
||||
*/
|
||||
public final void setToolTip(String text) {
|
||||
putValue(SHORT_DESCRIPTION, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Large Icon for this action from given url
|
||||
*
|
||||
* @param url
|
||||
*/
|
||||
public final void setLargeIcon(String url) {
|
||||
URL loc = this.getClass().getResource(LARGE_ICONS_LOC_PREFIX + url);
|
||||
if (loc != null) {
|
||||
ImageIcon i = new ImageIcon(loc);
|
||||
putValue(LARGE_ICON_KEY, i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the SmallIcon for the Action
|
||||
* @param url
|
||||
*/
|
||||
public final void setSmallIcon(String url) {
|
||||
URL loc = this.getClass().getResource(SMALL_ICONS_LOC_PREFIX + url);
|
||||
if (loc != null) {
|
||||
ImageIcon i = new ImageIcon(loc);
|
||||
putValue(SMALL_ICON, i);
|
||||
}
|
||||
}
|
||||
public static final String ACTION_PREFIX = "Action.";
|
||||
public static final String SMALL_ICONS_LOC_PREFIX = "/META-INF/images/small-icons/";
|
||||
public static final String LARGE_ICONS_LOC_PREFIX = "/META-INF/images/large-icons/";
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user