diff --git a/.idea/misc.xml b/.idea/misc.xml
index eb311f1..ecc80d4 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -4,7 +4,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 0000000..e96534f
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/lib/kotlin-reflect.jar b/lib/kotlin-reflect.jar
index 6d7087d..9da99a2 100644
Binary files a/lib/kotlin-reflect.jar and b/lib/kotlin-reflect.jar differ
diff --git a/lib/kotlin-stdlib-jre7-sources.jar b/lib/kotlin-stdlib-jre7-sources.jar
index 769bb69..acd520f 100644
Binary files a/lib/kotlin-stdlib-jre7-sources.jar and b/lib/kotlin-stdlib-jre7-sources.jar differ
diff --git a/lib/kotlin-stdlib-jre7.jar b/lib/kotlin-stdlib-jre7.jar
index 819e578..656f193 100644
Binary files a/lib/kotlin-stdlib-jre7.jar and b/lib/kotlin-stdlib-jre7.jar differ
diff --git a/lib/kotlin-stdlib-jre8-sources.jar b/lib/kotlin-stdlib-jre8-sources.jar
index cfc1c61..d6ed88c 100644
Binary files a/lib/kotlin-stdlib-jre8-sources.jar and b/lib/kotlin-stdlib-jre8-sources.jar differ
diff --git a/lib/kotlin-stdlib-jre8.jar b/lib/kotlin-stdlib-jre8.jar
index 606f9c7..b3e193f 100644
Binary files a/lib/kotlin-stdlib-jre8.jar and b/lib/kotlin-stdlib-jre8.jar differ
diff --git a/lib/kotlin-stdlib-sources.jar b/lib/kotlin-stdlib-sources.jar
index 3197dda..d77c60a 100644
Binary files a/lib/kotlin-stdlib-sources.jar and b/lib/kotlin-stdlib-sources.jar differ
diff --git a/lib/kotlin-stdlib.jar b/lib/kotlin-stdlib.jar
index 30e90c5..9f30725 100644
Binary files a/lib/kotlin-stdlib.jar and b/lib/kotlin-stdlib.jar differ
diff --git a/lib/kotlin-test.jar b/lib/kotlin-test.jar
index cfc87d6..98caff7 100644
Binary files a/lib/kotlin-test.jar and b/lib/kotlin-test.jar differ
diff --git a/src/ClassySharkBytecodeViewer.kt b/src/ClassySharkBytecodeViewer.kt
index 8cced6d..40b84fe 100644
--- a/src/ClassySharkBytecodeViewer.kt
+++ b/src/ClassySharkBytecodeViewer.kt
@@ -19,19 +19,24 @@ import java.awt.BorderLayout
import java.awt.Color
import java.awt.Dimension
import java.awt.Font
+import java.beans.PropertyChangeEvent
+import java.beans.PropertyChangeListener
import java.io.*
+import java.util.prefs.Preferences
import javax.swing.*
import javax.swing.filechooser.FileNameExtensionFilter
-class ClassySharkBytecodeViewer @Throws(Exception::class)
-constructor() : JFrame() {
-
- internal var javaArea: JTextPane
- internal var asmArea: JTextPane
- internal var ASM: String = ""
- internal val panelTitle = "ClassyShark Byte Code Viewer"
- internal val RESULT_AREAS_BACKGROUND = Color(46, 48, 50)
- internal val INPUT_AREA_BACKGROUND = Color(88, 110, 117)
+class ClassySharkBytecodeViewer: JFrame(), PropertyChangeListener {
+
+ private var loadedFile: File
+ private var loadedFileWatcherThread: FileWatcherThread
+ private val searchText: JTextField
+ private var javaArea: JTextPane
+ private var asmArea: JTextPane
+ private var ASM: String = ""
+ private val panelTitle = "ClassyShark Byte Code Viewer"
+ private val RESULT_AREAS_BACKGROUND = Color(46, 48, 50)
+ private val INPUT_AREA_BACKGROUND = Color(88, 110, 117)
object IntroTextHolder {
@JvmStatic val INTRO_TEXT = "\n\n\n\n\n\n\n\n\n\n" +
@@ -39,7 +44,7 @@ constructor() : JFrame() {
"\n\n\n\n\n ClassyShark ByteCode Viewer ver." +
Version.MAJOR + "." + Version.MINOR
}
-
+
init {
title = panelTitle
defaultCloseOperation = JFrame.EXIT_ON_CLOSE
@@ -47,10 +52,11 @@ constructor() : JFrame() {
val mainPanel = JPanel()
mainPanel.layout = BoxLayout(mainPanel, BoxLayout.Y_AXIS)
+ val tabbedPane = JTabbedPane()
val openButton = JButton(createImageIcon("ic_open.png", "Search"))
openButton.addActionListener { openButtonPressed() }
- val searchText = JTextField()
+ searchText = JTextField()
searchText.font = Font("Menlo", Font.PLAIN, 18)
searchText.background = INPUT_AREA_BACKGROUND
searchText.foreground = Color.CYAN
@@ -74,7 +80,9 @@ constructor() : JFrame() {
javaArea.transferHandler = FileTransferHandler(this)
javaArea.preferredSize = Dimension(830, 250)
val javaScrollPane = JScrollPane(javaArea)
- resultPanel.add(javaScrollPane)
+
+ tabbedPane.addTab("Java", null, javaScrollPane,
+ "Java sources")
asmArea = SyntaxPane()
asmArea.font = Font("Menlo", Font.PLAIN, 18)
@@ -83,8 +91,9 @@ constructor() : JFrame() {
asmArea.foreground = Color.CYAN
asmArea.text = SharkBG.SHARKEY
val asmScrollPane = JScrollPane(asmArea)
- resultPanel.add(asmScrollPane)
-
+ tabbedPane.addTab("Bytecode", null, asmScrollPane,
+ "Java Bytecode")
+ resultPanel.add(tabbedPane)
mainPanel.add(resultPanel)
val asmSearch = IncrementalSearch(asmArea)
@@ -97,10 +106,45 @@ constructor() : JFrame() {
contentPane = mainPanel
pack()
setLocationRelativeTo(null)
+
+ loadedFile = File("")
+ loadedFileWatcherThread = FileWatcherThread("", "", this)
+ }
+
+ override fun propertyChange(evt: PropertyChangeEvent) {
+ if (evt.propertyName == "command") {
+ // Received new command (outside EDT)
+ SwingUtilities.invokeLater {
+ // Updating GUI inside EDT
+ onFileRecompiled()
+ }
+ }
+ }
+
+ fun onFileLoaded(file: File) {
+ try {
+ this.loadedFile = file
+ title = panelTitle + " - " + file.name
+
+ fillJavaArea(file)
+ fillAsmArea(file)
+
+ watchLoadedFileChanges(file)
+ } catch (e: FileNotFoundException) {
+ e.printStackTrace()
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
}
+ private val LAST_USED_FOLDER: String = "ClassySharkBytecodeViewer"
+
private fun openButtonPressed() {
- val fc = JFileChooser("ClassyShark Bytecode Viewer")
+
+ val prefs = Preferences.userRoot().node("ClassySharkBytecodeViewer")
+
+ val fc = JFileChooser(prefs.get(LAST_USED_FOLDER,
+ File(".").absolutePath))
fc.fileSelectionMode = JFileChooser.FILES_AND_DIRECTORIES
val filter = FileNameExtensionFilter("classes", "class")
@@ -109,15 +153,18 @@ constructor() : JFrame() {
val retValue = fc.showOpenDialog(JPanel())
if (retValue == JFileChooser.APPROVE_OPTION) {
- onFileDragged(fc.selectedFile)
+ onFileLoaded(fc.selectedFile)
+
+ prefs.put(LAST_USED_FOLDER, fc.selectedFile.parent)
}
}
- fun onFileDragged(file: File) {
+ private fun onFileRecompiled() {
try {
- title = panelTitle + " - " + file.name
- fillJavaArea(file)
- fillAsmArea(file)
+ title = panelTitle + " - " + loadedFile.name
+ searchText.text = ""
+ fillJavaArea(loadedFile)
+ fillAsmArea(loadedFile)
} catch (e: FileNotFoundException) {
e.printStackTrace()
} catch (e: IOException) {
@@ -125,6 +172,20 @@ constructor() : JFrame() {
}
}
+ private fun watchLoadedFileChanges(file: File) {
+
+ if(loadedFileWatcherThread.isAlive) {
+ loadedFileWatcherThread.interrupt()
+ }
+
+ loadedFileWatcherThread = FileWatcherThread(file.parent, file.name, this)
+ loadedFileWatcherThread.start()
+
+ // the line below must be there otherwise threading + file system events
+ // don't work possibly after the thread had started
+ loadedFileWatcherThread.addPropertyChangeListener(this)
+ }
+
private fun fillAsmArea(file: File) {
javaArea.caretPosition = 0
val inputStream = FileInputStream(file)
@@ -158,11 +219,11 @@ constructor() : JFrame() {
private fun createImageIcon(path: String,
description: String): ImageIcon? {
val imgURL = javaClass.getResource(path)
- if (imgURL != null) {
- return ImageIcon(imgURL, description)
+ return if (imgURL != null) {
+ ImageIcon(imgURL, description)
} else {
System.err.println("Couldn't find file: " + path)
- return null
+ null
}
}
@@ -173,7 +234,7 @@ constructor() : JFrame() {
val bytecodeViewer = ClassySharkBytecodeViewer()
if (args.size == 1) {
- bytecodeViewer.onFileDragged(File(args[0]))
+ bytecodeViewer.onFileLoaded(File(args[0]))
} else if (args.size > 1) {
System.out.println("Usage: java -jar ClassySharkBytecodeViewer.jar ")
}
diff --git a/src/FileTransferHandler.kt b/src/FileTransferHandler.kt
index 3c8102a..de52a69 100644
--- a/src/FileTransferHandler.kt
+++ b/src/FileTransferHandler.kt
@@ -32,7 +32,7 @@ class FileTransferHandler(private val classySharkBytecodeViewer: ClassySharkByte
return false
}
- data.map { it as File }.forEach { classySharkBytecodeViewer.onFileDragged(it) }
+ data.map { it as File }.forEach { classySharkBytecodeViewer.onFileLoaded(it) }
return true
diff --git a/src/FileWatcherThread.kt b/src/FileWatcherThread.kt
new file mode 100644
index 0000000..7e7519d
--- /dev/null
+++ b/src/FileWatcherThread.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * 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.
+ */
+
+import java.beans.PropertyChangeListener
+import java.beans.PropertyChangeSupport
+import java.nio.file.*
+import java.nio.file.StandardWatchEventKinds.*
+
+// todo make package com.borisfarber.csviewer
+class FileWatcherThread @Throws(Exception::class)
+constructor(directoryName: String, private val fileName: String,
+ listener:PropertyChangeListener) : Thread() {
+
+ private val watcher: WatchService = FileSystems.getDefault().newWatchService()
+ private val pcs: PropertyChangeSupport
+
+ private var command: String? = null
+
+ init {
+ val dir = Paths.get(directoryName)
+ dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY)
+ println("Watch Service registered for dir: " + dir.fileName)
+ this.pcs = PropertyChangeSupport(listener)
+ }
+
+ override fun run() {
+ while (true) {
+ val key: WatchKey
+ try {
+ key = watcher.take()
+ } catch (ex: InterruptedException) {
+ return
+ }
+
+ for (event in key.pollEvents()) {
+ val kind = event.kind()
+
+ val ev = event as WatchEvent
+ val fileName = ev.context()
+
+ val commandText = kind.name() + ": " + fileName
+ println(commandText)
+
+ if (fileName.endsWith(this.fileName)) {
+ setCommand(commandText)
+ }
+ }
+
+ val valid = key.reset()
+ if (!valid) {
+ break
+ }
+ }
+ }
+
+ private fun setCommand(command: String) {
+ val old = this.command
+ this.command = command
+ pcs.firePropertyChange("command", old, command)
+ }
+
+ fun addPropertyChangeListener(listener: PropertyChangeListener) {
+ pcs.addPropertyChangeListener(listener)
+ }
+
+ companion object {
+ @Throws(Exception::class)
+ @JvmStatic
+ fun main(args: Array) {
+ val directoryName = "/Users/"
+
+ val dwd = FileWatcherThread(directoryName,
+ "User.class", PropertyChangeListener { })
+ dwd.run()
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Version.kt b/src/Version.kt
index 7ade339..ac1c4dd 100644
--- a/src/Version.kt
+++ b/src/Version.kt
@@ -2,6 +2,6 @@
* This class holds the current ClassySharkBytecodeViewer version
*/
object Version {
- val MAJOR = 5
+ val MAJOR = 6
val MINOR = 0
}
\ No newline at end of file