Serious bug-fixing, yo.
This commit is contained in:
@ -1,22 +1,33 @@
|
||||
application {
|
||||
title="PitSwing"
|
||||
startupGroups=["PIT"]
|
||||
autoShutdown=true
|
||||
title = 'PitSwing'
|
||||
startupGroups = ['PIT']
|
||||
|
||||
// Should Griffon exit when no Griffon created frames are showing?
|
||||
autoShutdown = true
|
||||
|
||||
// If you want some non-standard application class, apply it here
|
||||
//frameClass = 'javax.swing.JFrame'
|
||||
}
|
||||
mvcGroups {
|
||||
NewIssueDialog {
|
||||
model="com.jdbernard.pit.swing.NewIssueDialogModel"
|
||||
controller="com.jdbernard.pit.swing.NewIssueDialogController"
|
||||
view="com.jdbernard.pit.swing.NewIssueDialogView"
|
||||
}
|
||||
ProjectPanel {
|
||||
model="com.jdbernard.pit.swing.ProjectPanelModel"
|
||||
view="com.jdbernard.pit.swing.ProjectPanelView"
|
||||
controller="com.jdbernard.pit.swing.ProjectPanelController"
|
||||
}
|
||||
PIT {
|
||||
model="com.jdbernard.pit.swing.PITModel"
|
||||
view="com.jdbernard.pit.swing.PITView"
|
||||
controller="com.jdbernard.pit.swing.PITController"
|
||||
}
|
||||
// MVC Group for "ProjectPanel"
|
||||
'ProjectPanel' {
|
||||
model = 'com.jdbernard.pit.swing.ProjectPanelModel'
|
||||
view = 'com.jdbernard.pit.swing.ProjectPanelView'
|
||||
controller = 'com.jdbernard.pit.swing.ProjectPanelController'
|
||||
}
|
||||
|
||||
// MVC Group for "NewIssueDialog"
|
||||
'NewIssueDialog' {
|
||||
model = 'com.jdbernard.pit.swing.NewIssueDialogModel'
|
||||
view = 'com.jdbernard.pit.swing.NewIssueDialogView'
|
||||
controller = 'com.jdbernard.pit.swing.NewIssueDialogController'
|
||||
}
|
||||
|
||||
// MVC Group for "PIT"
|
||||
'PIT' {
|
||||
model = 'com.jdbernard.pit.swing.PITModel'
|
||||
view = 'com.jdbernard.pit.swing.PITView'
|
||||
controller = 'com.jdbernard.pit.swing.PITController'
|
||||
}
|
||||
|
||||
}
|
||||
|
135
pit-swing/griffon-app/conf/BuildConfig.groovy
Normal file
135
pit-swing/griffon-app/conf/BuildConfig.groovy
Normal file
@ -0,0 +1,135 @@
|
||||
// key signing information
|
||||
environments {
|
||||
development {
|
||||
signingkey {
|
||||
params {
|
||||
sigfile = 'GRIFFON'
|
||||
keystore = "${basedir}/griffon-app/conf/keys/devKeystore"
|
||||
alias = 'development'
|
||||
storepass = 'BadStorePassword'
|
||||
keypass = 'BadKeyPassword'
|
||||
lazy = true // only sign when unsigned
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
test {
|
||||
griffon {
|
||||
jars {
|
||||
sign = false
|
||||
pack = false
|
||||
}
|
||||
}
|
||||
}
|
||||
production {
|
||||
signingkey {
|
||||
params {
|
||||
sigfile = 'GRIFFON'
|
||||
keystore = 'CHANGE ME'
|
||||
alias = 'CHANGE ME'
|
||||
// NOTE: for production keys it is more secure to rely on key prompting
|
||||
// no value means we will prompt //storepass = 'BadStorePassword'
|
||||
// no value means we will prompt //keypass = 'BadKeyPassword'
|
||||
lazy = false // sign, regardless of existing signatures
|
||||
}
|
||||
}
|
||||
|
||||
griffon {
|
||||
jars {
|
||||
sign = true
|
||||
pack = true
|
||||
destDir = "${basedir}/staging"
|
||||
}
|
||||
webstart {
|
||||
codebase = 'CHANGE ME'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
griffon {
|
||||
memory {
|
||||
//max = '64m'
|
||||
//min = '2m'
|
||||
//maxPermSize = '64m'
|
||||
}
|
||||
jars {
|
||||
sign = false
|
||||
pack = false
|
||||
destDir = "${basedir}/staging"
|
||||
jarName = "${appName}.jar"
|
||||
}
|
||||
extensions {
|
||||
jarUrls = []
|
||||
jnlpUrls = []
|
||||
/*
|
||||
props {
|
||||
someProperty = 'someValue'
|
||||
}
|
||||
resources {
|
||||
linux { // windows, macosx, solaris
|
||||
jars = []
|
||||
nativelibs = []
|
||||
props {
|
||||
someProperty = 'someValue'
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
webstart {
|
||||
codebase = "${new File(griffon.jars.destDir).toURI().toASCIIString()}"
|
||||
jnlp = 'application.jnlp'
|
||||
}
|
||||
applet {
|
||||
jnlp = 'applet.jnlp'
|
||||
html = 'applet.html'
|
||||
}
|
||||
}
|
||||
|
||||
// required for custom environments
|
||||
signingkey {
|
||||
params {
|
||||
def env = griffon.util.Environment.current.name
|
||||
sigfile = 'GRIFFON-' + env
|
||||
keystore = "${basedir}/griffon-app/conf/keys/${env}Keystore"
|
||||
alias = env
|
||||
// storepass = 'BadStorePassword'
|
||||
// keypass = 'BadKeyPassword'
|
||||
lazy = true // only sign when unsigned
|
||||
}
|
||||
}
|
||||
|
||||
griffon.project.dependency.resolution = {
|
||||
// inherit Griffon' default dependencies
|
||||
inherits("global") {
|
||||
}
|
||||
log "warn" // log level of Ivy resolver, either 'error', 'warn', 'info', 'debug' or 'verbose'
|
||||
repositories {
|
||||
griffonPlugins()
|
||||
griffonHome()
|
||||
griffonCentral()
|
||||
|
||||
// uncomment the below to enable remote dependency resolution
|
||||
// from public Maven repositories
|
||||
//mavenLocal()
|
||||
//mavenCentral()
|
||||
//mavenRepo "http://snapshots.repository.codehaus.org"
|
||||
//mavenRepo "http://repository.codehaus.org"
|
||||
//mavenRepo "http://download.java.net/maven/2/"
|
||||
//mavenRepo "http://repository.jboss.com/maven2/"
|
||||
}
|
||||
dependencies {
|
||||
// specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes eg.
|
||||
|
||||
// runtime 'mysql:mysql-connector-java:5.1.5'
|
||||
}
|
||||
}
|
||||
|
||||
griffon {
|
||||
doc {
|
||||
logo = '<a href="http://griffon.codehaus.org" target="_blank"><img alt="The Griffon Framework" src="../img/griffon.png" border="0"/></a>'
|
||||
sponsorLogo = "<br/>"
|
||||
footer = "<br/><br/>Made with Griffon (0.9)"
|
||||
}
|
||||
}
|
@ -17,78 +17,3 @@ log4j {
|
||||
}
|
||||
additivity.StackTrace=false
|
||||
}
|
||||
|
||||
// key signing information
|
||||
environments {
|
||||
development {
|
||||
signingkey {
|
||||
params {
|
||||
sigfile = 'GRIFFON'
|
||||
keystore = "${basedir}/griffon-app/conf/keys/devKeystore"
|
||||
alias = 'development'
|
||||
storepass = 'BadStorePassword'
|
||||
keypass = 'BadKeyPassword'
|
||||
lazy = true // only sign when unsigned
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
test {
|
||||
griffon {
|
||||
jars {
|
||||
sign = false
|
||||
pack = false
|
||||
}
|
||||
}
|
||||
}
|
||||
production {
|
||||
signingkey {
|
||||
params {
|
||||
sigfile = 'GRIFFON'
|
||||
keystore = 'CHANGE ME'
|
||||
alias = 'CHANGE ME'
|
||||
// NOTE: for production keys it is more secure to rely on key prompting
|
||||
// no value means we will prompt //storepass = 'BadStorePassword'
|
||||
// no value means we will prompt //keypass = 'BadKeyPassword'
|
||||
lazy = false // sign, regardless of existing signatures
|
||||
}
|
||||
}
|
||||
|
||||
griffon {
|
||||
jars {
|
||||
sign = true
|
||||
pack = true
|
||||
destDir = "${basedir}/staging"
|
||||
}
|
||||
webstart {
|
||||
codebase = 'CHANGE ME'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
griffon {
|
||||
memory {
|
||||
//max = '64m'
|
||||
//min = '2m'
|
||||
//maxPermSize = '64m'
|
||||
}
|
||||
jars {
|
||||
sign = false
|
||||
pack = false
|
||||
destDir = "${basedir}/staging"
|
||||
jarName = "${appName}.jar"
|
||||
}
|
||||
extensions {
|
||||
jarUrls = []
|
||||
jnlpUrls = []
|
||||
}
|
||||
webstart {
|
||||
codebase = "${new File(griffon.jars.destDir).toURI().toASCIIString()}"
|
||||
jnlp = 'application.jnlp'
|
||||
}
|
||||
applet {
|
||||
jnlp = 'applet.jnlp'
|
||||
html = 'applet.html'
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
codebase:'@griffonAppCodebase@',
|
||||
code:'@griffonAppletClass@',
|
||||
archive:'@appletJars@',
|
||||
width:'240', height:'320'} ;
|
||||
width:'@applet.width@', height:'@applet.height@'} ;
|
||||
var parameters = {fontSize:16,
|
||||
java_arguments: "-Djnlp.packEnabled=true",
|
||||
jnlp_href:'@griffonAppCodebase@/applet.jnlp',
|
||||
@ -20,7 +20,7 @@
|
||||
image:'griffon.png',
|
||||
boxmessage:'Loading @griffonAppName@',
|
||||
boxbgcolor:'#FFFFFF', boxfgcolor:'#000000',
|
||||
codebase_lookup: 'false'} ;
|
||||
codebase_lookup: 'false'@applet.script.params@} ;
|
||||
var version = '1.5.0' ;
|
||||
deployJava.runApplet(attributes, parameters, version);
|
||||
</script>
|
||||
@ -28,7 +28,7 @@
|
||||
<APPLET CODEBASE='@griffonAppCodebase@'
|
||||
CODE='@griffonAppletClass@'
|
||||
ARCHIVE='@appletJars@'
|
||||
WIDTH='240' HEIGHT='320'>
|
||||
WIDTH='@applet.width@' HEIGHT='@applet.height@'>
|
||||
<PARAM NAME="java_arguments" VALUE="-Djnlp.packEnabled=true">
|
||||
<PARAM NAME='jnlp_href' VALUE='@griffonAppCodebase@/applet.jnlp'>
|
||||
<PARAM NAME='dragggable' VALUE='true'>
|
||||
@ -37,6 +37,7 @@
|
||||
<PARAM NAME='boxbgcolor' VALUE='#FFFFFF'>
|
||||
<PARAM NAME='boxfgcolor' VALUE='#000000'>
|
||||
<PARAM NAME='codebase_lookup' VALUE='false'>
|
||||
@applet.tag.params@
|
||||
</APPLET>
|
||||
-->
|
||||
</body>
|
||||
|
@ -35,21 +35,25 @@
|
||||
<!--<j2ee-application-client-permissions/>-->
|
||||
</security>
|
||||
<resources>
|
||||
<property name="griffon.runmode" value="applet"/>
|
||||
<property name="jnlp.packEnabled" value="true"/>
|
||||
<j2se version="1.5+" @memoryOptions@/>
|
||||
<!-- auto-added jars follow, griffon-rt, app, and groovy -->
|
||||
@jnlpJars@
|
||||
<!-- Add all extra jars below here, or the app may break -->
|
||||
@jnlpExtensions@
|
||||
@jnlpProperties@
|
||||
</resources>
|
||||
@jnlpResources@
|
||||
<applet-desc
|
||||
documentbase="@griffonAppCodebase@"
|
||||
name="@griffonAppName@Applet"
|
||||
main-class="@griffonAppletClass@"
|
||||
width="320"
|
||||
height="640">
|
||||
width="@applet.width@"
|
||||
height="@applet.height@">
|
||||
<!-- params are ignored when referenced from web page for 6u10 -->
|
||||
<!--<param name="key1" value="value1"/>-->
|
||||
<!--<param name="key2" value="value2"/>-->
|
||||
@applet.tag.params@
|
||||
</applet-desc>
|
||||
</jnlp>
|
||||
|
@ -35,16 +35,20 @@
|
||||
<!--<j2ee-application-client-permissions/>-->
|
||||
</security>
|
||||
<resources>
|
||||
<property name="griffon.runmode" value="webstart"/>
|
||||
<property name="jnlp.packEnabled" value="true"/>
|
||||
<j2se version="1.5+" @memoryOptions@/>
|
||||
<!-- auto-added jars follow, griffon-rt, app, and groovy -->
|
||||
@jnlpJars@
|
||||
<!-- Add all extra jars below here, or the app may break -->
|
||||
@jnlpExtensions@
|
||||
@jnlpProperties@
|
||||
</resources>
|
||||
@jnlpResources@
|
||||
<application-desc main-class="@griffonApplicationClass@">
|
||||
<!-- params are ignored when referenced from web page for 6u10 -->
|
||||
<!--<param name="key1" value="value1"/>-->
|
||||
<!--<param name="key2" value="value2"/>-->
|
||||
@applet.tag.params@
|
||||
</application-desc>
|
||||
</jnlp>
|
||||
|
@ -13,6 +13,8 @@ class PITController {
|
||||
|
||||
void mvcGroupInit(Map args) {
|
||||
|
||||
model.newIssueDialogMVC = buildMVCGroup('NewIssueDialog')
|
||||
|
||||
SwingUtilities.invokeAndWait {
|
||||
model.issueListRenderer = new IssueTableCellRenderer()
|
||||
|
||||
@ -27,27 +29,27 @@ class PITController {
|
||||
|
||||
// look for general config options
|
||||
pitrcFile = new File(pitHome, 'pitrc')
|
||||
if(logDbg) logger.debug("$pitrcFile is " +
|
||||
if (logDbg) logger.debug("$pitrcFile is " +
|
||||
(pitrcFile.exists() ? '' : 'not ') + "present.")
|
||||
|
||||
// load general config (if present)
|
||||
if (pitrcFile.exists()) {
|
||||
pitrcFile.withInputStream() { config.load(it) }
|
||||
if (pitrcFile.exists() && pitrcFile.canRead()) {
|
||||
pitrcFile.withInputStream { config.load(it) }
|
||||
if (logDbg) logger.debug("Loaded pitrc")
|
||||
}
|
||||
|
||||
// look for swing specific config
|
||||
pitswingrcFile = new File(pitHome, 'pitswingrc')
|
||||
if (logDbg) logger.debug("$pitswingrcFile is " +
|
||||
(pitswingrcFile.exists() ? '' : 'not ') + "present.")
|
||||
if (logDbg) logger.debug("$pitswingrcFile is " +
|
||||
(pitswingrcFile.exists() ? '' : 'not ') + "present.")
|
||||
|
||||
// load swing specific config (if present)
|
||||
if (pitswingrcFile.exists()) {
|
||||
pitswingrcFile.withInputStream() { config.load(it) }
|
||||
if(logDbg) logger.debug("Loaded pitswingrc")
|
||||
if (pitswingrcFile.exists() && pitswingrcFile.canRead()) {
|
||||
pitswingrcFile.withInputStream { config.load(it) }
|
||||
if (logDbg) logger.debug("Loaded pitswingrc")
|
||||
}
|
||||
|
||||
// Process Configurable Options
|
||||
// Process configurable options
|
||||
// ----------------------------
|
||||
|
||||
if (logDbg) {
|
||||
@ -59,15 +61,16 @@ class PITController {
|
||||
Category.values().each { category ->
|
||||
def expectedKey = "issue." + category.name().toLowerCase() +
|
||||
".template"
|
||||
if(logDbg) logger.debug("Looking for key: $expectedKey")
|
||||
if (logDbg) logger.debug("Looking for key: $expectedKey")
|
||||
|
||||
config.keySet().each { currentKey ->
|
||||
if (currentKey == expectedKey)
|
||||
model.templates[(category)] =
|
||||
config.getProperty(expectedKey, "")
|
||||
if (currentKey == expectedKey)
|
||||
model.templates[(category)] =
|
||||
config.getProperty(expectedKey, "")
|
||||
if (logDbg) logger.debug("Template for category $category: '" +
|
||||
model.templates[(category)] + "'")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// load custom issueListRenderer
|
||||
@ -76,12 +79,12 @@ class PITController {
|
||||
// load initial repositories
|
||||
if (config.containsKey('initial-repositories')) {
|
||||
def initRepos = config.getProperty('initial-repositories', '')
|
||||
initRepos = initRepos.split(/[;:,]/)
|
||||
initRepos = initRepos.split(/[:;,]/)
|
||||
initRepos.each { repoPath -> loadProject(new File(repoPath)) }
|
||||
if(logDbg) logger.debug("Init repos: '$initRepos'")
|
||||
if (logDbg) logger.debug("Init repos: '$initRepos'")
|
||||
}
|
||||
|
||||
// load custom issue CSS
|
||||
// load custom issue css
|
||||
if (config.containsKey('issue.display.css')) {
|
||||
def issueCSS = config.getProperty('issue.display.css', "")
|
||||
|
||||
@ -89,20 +92,16 @@ class PITController {
|
||||
def cssFile
|
||||
|
||||
// use short-circuit logic to test several possible locations
|
||||
// for a css file
|
||||
if ((cssFile = new File(pitHome, issueCSS)).exists() ||
|
||||
(cssFile = new File(pitHome.parentFile(), issueCSS)).exists() ||
|
||||
(cssFile = new File(issueCSS).exists()))
|
||||
(cssFile = new File(issueCSS)).exists())
|
||||
issueCSS = cssFile.text
|
||||
|
||||
if (logDbg) logger.debug("CS for issue display: $issueCSS")
|
||||
|
||||
if (logDbg) logger.debug("CSS for issue display: $issueCSS")
|
||||
model.issueCSS = issueCSS
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
model.newIssueDialogMVC = buildMVCGroup('NewIssueDialog')
|
||||
}
|
||||
|
||||
void refreshIssues() {
|
||||
@ -111,12 +110,11 @@ class PITController {
|
||||
}
|
||||
}
|
||||
|
||||
def openProject = { evt = null ->
|
||||
def openProject = { evt = null ->
|
||||
if (view.openDialog.showOpenDialog(view.frame) !=
|
||||
JFileChooser.APPROVE_OPTION) return
|
||||
JFileChooser.APPROVE_OPTIONS) return
|
||||
|
||||
loadProject(view.openDialog.selectedFile)
|
||||
|
||||
}
|
||||
|
||||
def loadProject = { File projectDir ->
|
||||
@ -124,7 +122,7 @@ class PITController {
|
||||
|
||||
// if this is not a valid directory, do nothing
|
||||
// TODO: log to the user that this is not a valid directory
|
||||
if (!projectDir.exists() || !projectDir.isDirectory()) return;
|
||||
if (!projectDir.exists() || !projectDir.isDirectory()) return
|
||||
|
||||
// create new ProjectPanel MVC
|
||||
newMVC = buildMVCGroup('ProjectPanel',
|
||||
@ -134,28 +132,30 @@ class PITController {
|
||||
issueCSS: model.issueCSS,
|
||||
rootProject: new FileProject(projectDir))
|
||||
newMVC.model.id = projectDir.name
|
||||
|
||||
|
||||
// if we already have a tab with this id
|
||||
if (model.projectPanelMVCs[(newMVC.model.id)]) {
|
||||
|
||||
// try using the canonical path
|
||||
newMVC.model.id = projectDir.canonicalPath
|
||||
|
||||
// still not unique?
|
||||
if (model.projectPanelMVCs[(newMVC.model.id)]) {
|
||||
|
||||
|
||||
// first time this has happened?
|
||||
if (!model.projectIdMap[(newMVC.model.id)])
|
||||
if (!model.projectIdMap[(newMVC.model.id)])
|
||||
model.projectIdMap[(newMVC.model.id)] = 0
|
||||
|
||||
// no? increment
|
||||
else model.projectIdMap[(newMVC.model.id)] =
|
||||
else model.projectIdMap[(newMVC.model.id)] =
|
||||
model.projectIdMap[(newMVC.model.id)] + 1
|
||||
|
||||
// use our new, unique id
|
||||
newMVC.model.id += "-" + model.projectIdMap[(newMVC.model.id)]
|
||||
newMVC.model.id += "-" + model.projectIdMap[(newMVC.model.id)]
|
||||
}
|
||||
}
|
||||
|
||||
model.projectPanelMVCs[newMVC.model.id] = newMVC
|
||||
model.projectPanelMVCs[(newMVC.model.id)] = newMVC
|
||||
view.mainTabbedPane.addTab(newMVC.model.id, newMVC.view.panel)
|
||||
}
|
||||
|
||||
|
@ -34,17 +34,18 @@ class ProjectPanelController {
|
||||
refreshProject()
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* displayProject
|
||||
* @param project Project to display.
|
||||
*
|
||||
* @param project Project to display
|
||||
*/
|
||||
void displayProject(Project project) {
|
||||
view.issueTextArea.text = ""
|
||||
view.issueTextDisplay.text = ""
|
||||
view.issueTextPanelLayout.show(view.issueTextPanel, "display")
|
||||
void displayProject(Project project) {
|
||||
if (!project) return
|
||||
|
||||
view.issueTextArea.text = ""
|
||||
view.issueTextDisplay.text = ""
|
||||
view.issueTextPanelLayout.show(view.issueTextPanel, 'display')
|
||||
|
||||
// build a new IssueTableModel if none cached
|
||||
if (!model.projectTableModels[(project.name)]) {
|
||||
def itm = new IssueTableModel(project,
|
||||
model.filter ?: model.mainMVC.model.filter)
|
||||
@ -67,7 +68,7 @@ class ProjectPanelController {
|
||||
if (!issue) return
|
||||
|
||||
// hack because binding view.issueTextArea.font to
|
||||
// mainMVC.mode.issueDetailFont causes problems
|
||||
// mainMVC.model.issueDetailFont causes problems
|
||||
if (view.issueTextArea.font != model.mainMVC.model.issueDetailFont)
|
||||
view.issueTextArea.font = model.mainMVC.model.issueDetailFont
|
||||
|
||||
@ -75,10 +76,10 @@ class ProjectPanelController {
|
||||
view.issueTextArea.caretPosition = 0
|
||||
view.issueTextDisplay.text = rst2html(issue.text)
|
||||
view.issueTextDisplay.caretPosition = 0
|
||||
view.issueTextPanelLayout.show(view.issueTextPanel, "display")
|
||||
view.issueTextPanelLayout.show(view.issueTextPanel, 'display')
|
||||
}
|
||||
|
||||
void showProjectPopup(Project project, def x, def y) {
|
||||
void showProejctPopup(Project project, def x, def y) {
|
||||
model.popupProject = project
|
||||
view.projectPopupMenu.show(view.projectTree, x, y)
|
||||
}
|
||||
@ -120,7 +121,7 @@ class ProjectPanelController {
|
||||
|
||||
def project
|
||||
|
||||
if (evt.source == view.newProjectButton)
|
||||
if (evt.source == view.newProjectButton)
|
||||
project = model.selectedProject ?: model.rootProject
|
||||
else project = model.popupProject ?: model.rootProject
|
||||
def newProject = project.createNewProject(name)
|
||||
@ -134,7 +135,7 @@ class ProjectPanelController {
|
||||
|
||||
if (evt.source == view.deleteProjectButton)
|
||||
project = model.selectedProject ?: model.rootProject
|
||||
else project = model.popupProject ?: model.rootModel
|
||||
else project = model.popupProject ?: model.rootProject
|
||||
|
||||
project.delete()
|
||||
|
||||
@ -185,7 +186,7 @@ class ProjectPanelController {
|
||||
}
|
||||
|
||||
String rst2html(String rst) {
|
||||
Document doc // memory model of document
|
||||
Document doc
|
||||
StringWriter outString
|
||||
StringBuilder result = new StringBuilder()
|
||||
|
||||
@ -201,19 +202,18 @@ class ProjectPanelController {
|
||||
|
||||
// java's embeded html is primitive, we need to massage the results
|
||||
outString.toString().eachLine { line ->
|
||||
|
||||
// remove the XML version and encoding, title element,
|
||||
// meta elements
|
||||
|
||||
// remove the XML version and encoding, title element, meta elems
|
||||
if (line =~ /<\?.*\?>/ || line =~ /<meta.*$/ || line =~ /<title.*$/) { return }
|
||||
|
||||
// all other elements, remove all class,xmlns attributes
|
||||
// all other elements, remove all class, xmlns attributes
|
||||
def m = (line =~ /(<\S+)(\s*(class|xmlns)=".*"\s*)*(\/?>.*)/)
|
||||
if (m) line = m[0][1] + m[0][4]
|
||||
|
||||
result.append(line)
|
||||
|
||||
|
||||
// add in the CSS information to the head
|
||||
if (line =~/<head>/) result.append('<style type="text/css">' +
|
||||
if (line =~ /<head>/) result.append('<style type="text/css">' +
|
||||
model.issueCSS + '</style>')
|
||||
}
|
||||
|
||||
|
@ -1,25 +1,20 @@
|
||||
/*
|
||||
* This script is executed inside the EDT, so be sure to
|
||||
* call long running code in another thread.
|
||||
* This script is executed inside the UI thread, so be sure to call
|
||||
* long running code in another thread.
|
||||
*
|
||||
* You have the following options
|
||||
* - SwingBuilder.doOutside { // your code }
|
||||
* - execOutside { // your code }
|
||||
* - execFuture { // your code }
|
||||
* - Thread.start { // your code }
|
||||
* - SwingXBuilder.withWorker( start: true ) {
|
||||
* onInit { // initialization (optional, runs in current thread) }
|
||||
* work { // your code }
|
||||
* onDone { // finish (runs inside EDT) }
|
||||
* }
|
||||
*
|
||||
* You have the following options to run code again inside EDT
|
||||
* - SwingBuilder.doLater { // your code }
|
||||
* - SwingBuilder.edt { // your code }
|
||||
* - SwingUtilities.invokeLater { // your code }
|
||||
* You have the following options to run code again inside the UI thread
|
||||
* - execAsync { // your code }
|
||||
* - execSync { // your code }
|
||||
*/
|
||||
|
||||
import groovy.swing.SwingBuilder
|
||||
import griffon.util.GriffonPlatformHelper
|
||||
import griffon.util.GriffonApplicationHelper
|
||||
import static griffon.util.GriffonApplicationUtils.*
|
||||
|
||||
GriffonPlatformHelper.tweakForNativePlatform(app)
|
||||
SwingBuilder.lookAndFeel('org.pushingpixels.substance.api.skin.SubstanceCremeCoffeeLookAndFeel', 'nimbus', ['metal', [boldFonts: false]])
|
||||
|
@ -1,18 +1,13 @@
|
||||
/*
|
||||
* This script is executed inside the EDT, so be sure to
|
||||
* call long running code in another thread.
|
||||
* This script is executed inside the UI thread, so be sure to call
|
||||
* long running code in another thread.
|
||||
*
|
||||
* You have the following options
|
||||
* - SwingBuilder.doOutside { // your code }
|
||||
* - execOutside { // your code }
|
||||
* - execFuture { // your code }
|
||||
* - Thread.start { // your code }
|
||||
* - SwingXBuilder.withWorker( start: true ) {
|
||||
* onInit { // initialization (optional, runs in current thread) }
|
||||
* work { // your code }
|
||||
* onDone { // finish (runs inside EDT) }
|
||||
* }
|
||||
*
|
||||
* You have the following options to run code again inside EDT
|
||||
* - SwingBuilder.doLater { // your code }
|
||||
* - SwingBuilder.edt { // your code }
|
||||
* - SwingUtilities.invokeLater { // your code }
|
||||
* You have the following options to run code again inside the UI thread
|
||||
* - execAsync { // your code }
|
||||
* - execSync { // your code }
|
||||
*/
|
||||
|
@ -1,18 +1,13 @@
|
||||
/*
|
||||
* This script is executed inside the EDT, so be sure to
|
||||
* call long running code in another thread.
|
||||
* This script is executed inside the UI thread, so be sure to call
|
||||
* long running code in another thread.
|
||||
*
|
||||
* You have the following options
|
||||
* - SwingBuilder.doOutside { // your code }
|
||||
* - execOutside { // your code }
|
||||
* - execFuture { // your code }
|
||||
* - Thread.start { // your code }
|
||||
* - SwingXBuilder.withWorker( start: true ) {
|
||||
* onInit { // initialization (optional, runs in current thread) }
|
||||
* work { // your code }
|
||||
* onDone { // finish (runs inside EDT) }
|
||||
* }
|
||||
*
|
||||
* You have the following options to run code again inside EDT
|
||||
* - SwingBuilder.doLater { // your code }
|
||||
* - SwingBuilder.edt { // your code }
|
||||
* - SwingUtilities.invokeLater { // your code }
|
||||
*/
|
||||
* You have the following options to run code again inside the UI thread
|
||||
* - execAsync { // your code }
|
||||
* - execSync { // your code }
|
||||
*/
|
||||
|
@ -1,18 +1,13 @@
|
||||
/*
|
||||
* This script is executed inside the EDT, so be sure to
|
||||
* call long running code in another thread.
|
||||
* This script is executed inside the UI thread, so be sure to call
|
||||
* long running code in another thread.
|
||||
*
|
||||
* You have the following options
|
||||
* - SwingBuilder.doOutside { // your code }
|
||||
* - execOutside { // your code }
|
||||
* - execFuture { // your code }
|
||||
* - Thread.start { // your code }
|
||||
* - SwingXBuilder.withWorker( start: true ) {
|
||||
* onInit { // initialization (optional, runs in current thread) }
|
||||
* work { // your code }
|
||||
* onDone { // finish (runs inside EDT) }
|
||||
* }
|
||||
*
|
||||
* You have the following options to run code again inside EDT
|
||||
* - SwingBuilder.doLater { // your code }
|
||||
* - SwingBuilder.edt { // your code }
|
||||
* - SwingUtilities.invokeLater { // your code }
|
||||
*/
|
||||
* You have the following options to run code again inside the UI thread
|
||||
* - execAsync { // your code }
|
||||
* - execSync { // your code }
|
||||
*/
|
||||
|
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* This script is executed inside the UI thread, so be sure to call
|
||||
* long running code in another thread.
|
||||
*
|
||||
* You have the following options
|
||||
* - execOutside { // your code }
|
||||
* - execFuture { // your code }
|
||||
* - Thread.start { // your code }
|
||||
*
|
||||
* You have the following options to run code again inside the UI thread
|
||||
* - execAsync { // your code }
|
||||
* - execSync { // your code }
|
||||
*/
|
||||
|
@ -5,7 +5,6 @@ import com.jdbernard.pit.Status
|
||||
import groovy.beans.Bindable
|
||||
|
||||
class NewIssueDialogModel {
|
||||
|
||||
@Bindable boolean accept
|
||||
String text
|
||||
Category category
|
||||
|
@ -7,26 +7,28 @@ import com.jdbernard.pit.Project
|
||||
import com.jdbernard.pit.Status
|
||||
import groovy.beans.Bindable
|
||||
import java.awt.Font
|
||||
import javax.swing.ImageIcon
|
||||
|
||||
class PITModel {
|
||||
// filter for projects and issues
|
||||
|
||||
// filter for projects and classes
|
||||
Filter filter = new Filter(categories: [],
|
||||
status: [Status.NEW, Status.VALIDATION_REQUIRED])
|
||||
|
||||
def issueListRenderer
|
||||
|
||||
// map of category -> issue template
|
||||
def templates = [:]
|
||||
Map<Category, String> templates = [:]
|
||||
|
||||
def issueCSS = getClass().getResource("/default-issue.css").openStream().text
|
||||
|
||||
def categoryIcons = [:]
|
||||
def statusIcons = [:]
|
||||
String issueCSS = getClass().getResourceAsStream("/default-issue.css").text
|
||||
|
||||
Map<Category, ImageIcon> categoryIcons = [:]
|
||||
Map<Category, ImageIcon> statusIcons = [:]
|
||||
|
||||
def newIssueDialogMVC
|
||||
def projectPanelMVCs = [:]
|
||||
Map projectPanelMVCs = [:]
|
||||
|
||||
def projectIdMap = [:]
|
||||
Map projectIdMap = [:]
|
||||
|
||||
@Bindable issueDetailFont = new Font(Font.MONOSPACED, Font.PLAIN, 10)
|
||||
@Bindable Font issueDetailFont = new Font(Font.MONOSPACED, Font.PLAIN, 10)
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ class ProjectPanelModel {
|
||||
|
||||
String issueCSS = ""
|
||||
|
||||
// cache the ListModels
|
||||
// cache the models
|
||||
def projectTableModels = [:]
|
||||
def issueCellRenderer
|
||||
|
||||
|
@ -61,4 +61,5 @@ dialog = dialog(title: 'New Task...', modal: true, pack: true,
|
||||
},
|
||||
constraints: gbc(gridx: 1, gridy: 5, insets: [5, 5, 5, 5],
|
||||
anchor: GBC.WEST))
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import com.jdbernard.pit.Project
|
||||
import com.jdbernard.pit.FileProject
|
||||
import groovy.beans.Bindable
|
||||
import java.awt.BorderLayout as BL
|
||||
import java.awt.Color
|
||||
import java.awt.GridBagConstraints as GBC
|
||||
import javax.swing.DefaultComboBoxModel
|
||||
import javax.swing.DefaultListModel
|
||||
@ -16,7 +17,6 @@ import javax.swing.JFileChooser
|
||||
import javax.swing.JOptionPane
|
||||
import net.miginfocom.swing.MigLayout
|
||||
|
||||
import java.awt.Color
|
||||
|
||||
actions {
|
||||
action(
|
||||
@ -53,20 +53,17 @@ Status.values().each {
|
||||
model.statusIcons[(it)] = imageIcon("/${it.name().toLowerCase()}.png")
|
||||
}
|
||||
|
||||
|
||||
openDialog = fileChooser(fileSelectionMode: JFileChooser.DIRECTORIES_ONLY)
|
||||
|
||||
frame = application(title:'Personal Issue Tracker',
|
||||
frame = application(title: 'Personal Issue Tracker',
|
||||
minimumSize: [400, 200],
|
||||
preferredSize: [800, 500],
|
||||
pack:true,
|
||||
pack: true,
|
||||
locationRelativeTo: null,
|
||||
iconImage: imageIcon('/icon64x64.png').image,
|
||||
iconImages: [imageIcon('/icon64x64.png').image,
|
||||
imageIcon('/icon32x32.png').image,
|
||||
imageIcon('/icon16x16.png').image]
|
||||
) {
|
||||
|
||||
|
||||
// main menu
|
||||
menuBar() {
|
||||
menu("File") {
|
||||
@ -76,12 +73,12 @@ frame = application(title:'Personal Issue Tracker',
|
||||
menuItem(shutdown)
|
||||
}
|
||||
|
||||
menu('View') {
|
||||
menu("View") {
|
||||
menu('Category') {
|
||||
Category.values().each { cat ->
|
||||
checkBoxMenuItem(cat.toString(),
|
||||
selected: model.filter.categories.contains(cat),
|
||||
actionPerformed: { evt ->
|
||||
actionPerformed: {
|
||||
if (model.filter.categories.contains(cat)) {
|
||||
model.filter.categories.remove(cat)
|
||||
evt.source.selected = false
|
||||
@ -120,17 +117,17 @@ frame = application(title:'Personal Issue Tracker',
|
||||
JOptionPane.QUESTION_MESSAGE)
|
||||
if (newSize == null || !newSize.isFloat())
|
||||
JOptionPane.showMessageDialog(frame,
|
||||
"$newSize is not a valid size.",
|
||||
'Change Issue Detail Text Size...',
|
||||
'$newSize is not a valid size.',
|
||||
'Change Issue Detail Size...',
|
||||
JOptionPane.ERROR_MESSAGE)
|
||||
else model.issueDetailFont = model.issueDetailFont
|
||||
.deriveFont(newSize.toFloat())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
menu('Sort') {
|
||||
menu("Sort") {
|
||||
sortMenuButtonGroup = buttonGroup()
|
||||
checkBoxMenuItem('By ID',
|
||||
checkBoxMenuItem('By ID',
|
||||
buttonGroup: sortMenuButtonGroup,
|
||||
actionPerformed: {
|
||||
model.filter.issueSorter = { it.id }
|
||||
@ -160,6 +157,7 @@ frame = application(title:'Personal Issue Tracker',
|
||||
model.filter.issueSorter = { it.title }
|
||||
controller.refreshIssues()
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,13 +75,13 @@ projectPopupMenu = popupMenu() {
|
||||
menuItem(deleteProjectPop)
|
||||
}
|
||||
|
||||
// popup menu for isses
|
||||
// popup menu for issues
|
||||
issuePopupMenu = popupMenu() {
|
||||
menuItem(newIssue)
|
||||
menuItem(deleteIssuePop)
|
||||
separator()
|
||||
|
||||
menu('Change Category', enabled: bind { model.popupIssue != null }) {
|
||||
menu('Change Category', enabled: bind { model.popupIssue != null }) {
|
||||
Category.values().each { category ->
|
||||
menuItem(category.toString(),
|
||||
icon: model.mainMVC.model.categoryIcons[(category)],
|
||||
@ -91,15 +91,15 @@ issuePopupMenu = popupMenu() {
|
||||
model.popupIssue.category = category
|
||||
controller.refreshIssues()
|
||||
} catch (IOException ioe) {
|
||||
JOptionPane.showMessageDialog(mainMVC.view.frame,
|
||||
ioe.getLocalizedMessage(), 'Change Category',
|
||||
JOptionPane.showMessage(mainMVC.view.frame,
|
||||
ioe.getLocalizedMessage(), "Change Category",
|
||||
JOptionPane.ERROR_MESSAGE)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
menu('Change Status', enabled: bind { model.popupIssue != null }) {
|
||||
menu('Change Status', enabled: bind { model.popupIssue != null}) {
|
||||
Status.values().each { status ->
|
||||
menuItem(status.toString(),
|
||||
icon: model.mainMVC.model.statusIcons[(status)],
|
||||
@ -108,8 +108,8 @@ issuePopupMenu = popupMenu() {
|
||||
try {
|
||||
model.popupIssue.status = status
|
||||
controller.refreshIssues()
|
||||
} catch (IOException ioe) {
|
||||
JOptionPane.showMessageDialog(mainMVC.view.frame,
|
||||
} catch (IOException ioe) {
|
||||
JOptionPane.showMessage(model.mainMVC.view.frame,
|
||||
ioe.getLocalizedMessage(), 'Change Status',
|
||||
JOptionPane.ERROR_MESSAGE)
|
||||
}
|
||||
@ -123,14 +123,14 @@ issuePopupMenu = popupMenu() {
|
||||
def newPriority = JOptionPane.showInputDialog(mainMVC.view.frame,
|
||||
'New priority (0-9)', 'Change Priority...',
|
||||
JOptionPane.QUESTION_MESSAGE)
|
||||
try { model.popupIssue.priority = newPriority.toInteger() }
|
||||
try { model.popupIsse.priority = newPriority.toInteger() }
|
||||
catch (NumberFormatException nfe) {
|
||||
JOptionPane.showMessageDialog(mainMVC.view.frame,
|
||||
'The priority value must be an integer in [0-9].',
|
||||
'Change Priority...', JOptionPane.ERROR_MESSAGE)
|
||||
return
|
||||
} catch (IOException ioe) {
|
||||
JOptionPane.showMessageDialog(mainMVC.view.fraw,
|
||||
JOptionPane.showMessageDialog(model.mainMVC.view.frame,
|
||||
ioe.getLocalizedMessage(), 'Change Priority...',
|
||||
JOptionPane.ERROR_MESSAGE)
|
||||
}
|
||||
@ -140,28 +140,28 @@ issuePopupMenu = popupMenu() {
|
||||
|
||||
// main split view
|
||||
panel = splitPane(orientation: JSplitPane.HORIZONTAL_SPLIT,
|
||||
// dividerLocation: bind(source: model.mainModel, property: dividerLocation),
|
||||
dividerLocation: 200,
|
||||
oneTouchExpandable: true,
|
||||
constraints: gbc(fill: GBC.BOTH, insets: [10,10,10,10],
|
||||
constraints: gbc(fill: GBC.BOTH, insets: [10, 10, 10, 10],
|
||||
weightx: 2, weighty: 2)) {
|
||||
|
||||
// left side (projects tree and buttons)
|
||||
panel(constraints: "left") {
|
||||
// left side (project tree and buttons
|
||||
panel(constraints: 'left') {
|
||||
gridBagLayout()
|
||||
|
||||
// tree view of projects
|
||||
scrollPane(constraints: gbc(fill: GBC.BOTH, gridx: 0, gridy:0,
|
||||
scrollPane(constraints: gbc(fill: GBC.BOTH, gridx: 0, gridy: 0,
|
||||
gridwidth: 2, weightx: 2, weighty: 2)) {
|
||||
treeCellRenderer = new DefaultTreeCellRenderer()
|
||||
treeCellRenderer.leafIcon = treeCellRenderer.closedIcon
|
||||
|
||||
projectTree = tree(cellRenderer: treeCellRenderer,
|
||||
model: bind(source: model, sourceProperty: 'rootProject',
|
||||
sourceValue: {
|
||||
sourceValue: {
|
||||
if (model.rootProject) {
|
||||
def rootNode = new DefaultMutableTreeNode()
|
||||
def flatview = new FlatProjectView('All Issues')
|
||||
flatviews.projects[(model.rootProject.name)] =
|
||||
flatview.projects[(model.rootProject.name)] =
|
||||
model.rootProject
|
||||
rootNode.add(new DefaultMutableTreeNode(flatview))
|
||||
rootNode.add(controller.makeNodes(model.rootProject))
|
||||
@ -178,18 +178,17 @@ panel = splitPane(orientation: JSplitPane.HORIZONTAL_SPLIT,
|
||||
mouseClicked: { evt ->
|
||||
if (evt.button == MouseEvent.BUTTON3) {
|
||||
controller.showProjectPopup(
|
||||
projectTree.getPathForLocation(evt.x, evt.y)
|
||||
?.lastPathComponent?.userObject,
|
||||
projectTree.getPathForLocation(evt.x, evt.y)?.
|
||||
lastPathComponent?.userObject,
|
||||
evt.x, evt.y)
|
||||
}
|
||||
})
|
||||
projectTree.rootVisible = false
|
||||
|
||||
|
||||
projectTree.selectionModel.selectionMode =
|
||||
TreeSelectionModel.SINGLE_TREE_SELECTION
|
||||
}
|
||||
|
||||
// project buttons
|
||||
newProjectButton = button(newProject,
|
||||
constraints: gbc(fill: GBC.NONE, gridx: 0, gridy: 1,
|
||||
anchor: GBC.WEST))
|
||||
@ -198,7 +197,7 @@ panel = splitPane(orientation: JSplitPane.HORIZONTAL_SPLIT,
|
||||
anchor: GBC.WEST))
|
||||
}
|
||||
|
||||
// split between issue list and issue details
|
||||
// split between issues list and issue details
|
||||
splitPane(orientation: JSplitPane.VERTICAL_SPLIT,
|
||||
dividerLocation: 200, constraints: "right") {
|
||||
|
||||
@ -206,7 +205,7 @@ panel = splitPane(orientation: JSplitPane.HORIZONTAL_SPLIT,
|
||||
gridBagLayout()
|
||||
|
||||
scrollPane(constraints: gbc(fill: GBC.BOTH, weightx: 2,
|
||||
weighty: 2, gridx: 0, gridy: 0, gridwidth: 3)) {
|
||||
weighty: 2, gridx: 0, gridy: 0, gridwidth: 3)) {
|
||||
|
||||
issueTable = table(
|
||||
autoCreateRowSorter: true,
|
||||
@ -223,7 +222,7 @@ panel = splitPane(orientation: JSplitPane.HORIZONTAL_SPLIT,
|
||||
translatedPoint.translate(-issueTable.locationOnScreen.@x,
|
||||
-issueTable.locationOnScreen.@y)
|
||||
def row = issueTable.rowAtPoint(translatedPoint)
|
||||
|
||||
|
||||
issueTable.setRowSelectionInterval(row, row)
|
||||
|
||||
controller.showIssuePopup(
|
||||
@ -238,21 +237,6 @@ panel = splitPane(orientation: JSplitPane.HORIZONTAL_SPLIT,
|
||||
controller.displayIssue(controller.getSelectedIssue())
|
||||
}
|
||||
|
||||
/*issueList = list(
|
||||
cellRenderer: model.issueCellRenderer,
|
||||
selectionMode: ListSelectionModel.SINGLE_SELECTION,
|
||||
valueChanged: { evt ->
|
||||
controller.displayIssue(issueList.selectedValue)
|
||||
},
|
||||
mouseClicked: { evt ->
|
||||
if (evt.button == MouseEvent.BUTTON3) {
|
||||
issueList.selectedIndex = issueList.locationToIndex(
|
||||
[evt.x, evt.y] as Point)
|
||||
|
||||
controller.showIssuePopup(
|
||||
issueList.selectedValue, evt.x, evt.y)
|
||||
}
|
||||
})*/
|
||||
}
|
||||
|
||||
wordWrapCheckBox = checkBox('Word wrap',
|
||||
@ -266,7 +250,6 @@ panel = splitPane(orientation: JSplitPane.HORIZONTAL_SPLIT,
|
||||
enabled: bind(source: issueTable.selectionModel,
|
||||
sourceEvent: 'valueChanged',
|
||||
sourceValue: { !issueTable.selectionModel.isSelectionEmpty() }))
|
||||
|
||||
}
|
||||
|
||||
scrollPane(constraints: "bottom",
|
||||
@ -274,45 +257,38 @@ panel = splitPane(orientation: JSplitPane.HORIZONTAL_SPLIT,
|
||||
issueTextPanel = panel {
|
||||
issueTextPanelLayout = cardLayout()
|
||||
|
||||
def leavingEditorClosure = {
|
||||
def issue = controller.getSelectedIssue()
|
||||
if (issue == null) return
|
||||
if (issueTextArea.text != issue.text) {
|
||||
issue.text = issueTextArea.text
|
||||
issueTextDisplay.text = controller.rst2html(
|
||||
issueTextArea.text)
|
||||
}
|
||||
issueTextPanelLayout.show(issueTextPanel, 'display')
|
||||
}
|
||||
|
||||
issueTextArea = textArea(
|
||||
constraints: "editor",
|
||||
constraints: 'editor',
|
||||
wrapStyleWord: true,
|
||||
lineWrap: bind(source: wordWrapCheckBox,
|
||||
sourceProperty: 'selected'),
|
||||
editable: bind( source: issueTable.selectionModel,
|
||||
editable: bind(source: issueTable.selectionModel,
|
||||
sourceEvent: 'valueChanged',
|
||||
sourceValue:
|
||||
{ !issueTable.selectionModel.isSelectionEmpty() }),
|
||||
font: model.mainMVC.model.issueDetailFont,
|
||||
focusGained: {},
|
||||
focusLost: {
|
||||
def issue = controller.getSelectedIssue()
|
||||
if (issue == null) return
|
||||
if (issueTextArea.text != issue.text) {
|
||||
issue.text = issueTextArea.text
|
||||
issueTextDisplay.text = controller.rst2html(
|
||||
issueTextArea.text)
|
||||
}
|
||||
issueTextPanelLayout.show(issueTextPanel, "display")
|
||||
},
|
||||
mouseExited: {
|
||||
def issue = controller.getSelectedIssue()
|
||||
if (issue == null) return
|
||||
if (issueTextArea.text != issue.text) {
|
||||
issue.text = issueTextArea.text
|
||||
issueTextDisplay.text = controller.rst2html(
|
||||
issueTextArea.text)
|
||||
}
|
||||
issueTextPanelLayout.show(issueTextPanel, "display")
|
||||
})
|
||||
|
||||
issueTextDisplay = editorPane(contentType: "text/html",
|
||||
constraints: "display",
|
||||
focusLost: leavingEditorClosure,
|
||||
mouseExited: leavingEditorClosure)
|
||||
|
||||
issueTextDisplay = editorPane(contentType: 'text/html',
|
||||
constraints: 'display',
|
||||
editable: false,
|
||||
preferredSize: [10, 10],
|
||||
mouseClicked: { evt ->
|
||||
mouseClicked: {evt ->
|
||||
if (evt.clickCount > 1)
|
||||
issueTextPanelLayout.show(issueTextPanel, "editor")
|
||||
issueTextPanelLayout.show(issueTextPanel, 'editor')
|
||||
})
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user