Small enhancements to libpit to facilitate pit-swing.
Added delete() and createNewProject(String) to Project class. Added nicer toString() method to Category enum.
This commit is contained in:
parent
45516a5cd9
commit
60109087e5
@ -1,10 +1,10 @@
|
|||||||
#Mon Feb 22 07:08:09 CST 2010
|
#Wed Feb 24 03:03:11 CST 2010
|
||||||
build.dir=build
|
build.dir=build
|
||||||
src.dir=src
|
src.dir=src
|
||||||
lib.shared.dir=../shared-libs
|
lib.shared.dir=../shared-libs
|
||||||
test.dir=test
|
test.dir=test
|
||||||
build.number=2
|
build.number=4
|
||||||
expected.application.version=1.1.4
|
expected.application.version=1.1.5
|
||||||
lib.dir=lib
|
lib.dir=lib
|
||||||
release.dir=release
|
release.dir=release
|
||||||
release.jar=pit-${application.version}.jar
|
release.jar=pit-${application.version}.jar
|
||||||
|
Binary file not shown.
BIN
libpit/release/pit-1.1.5.jar
Normal file
BIN
libpit/release/pit-1.1.5.jar
Normal file
Binary file not shown.
@ -43,9 +43,9 @@ badd +1 test/com/jdbernard/pit/IssueTest.groovy
|
|||||||
badd +6 src/com/jdbernard/pit/Project.groovy
|
badd +6 src/com/jdbernard/pit/Project.groovy
|
||||||
badd +1 test/com/jdbernard/pit/ProjectTest.groovy
|
badd +1 test/com/jdbernard/pit/ProjectTest.groovy
|
||||||
badd +1 src/com/jdbernard/pit/FileIssue.groovy
|
badd +1 src/com/jdbernard/pit/FileIssue.groovy
|
||||||
badd +0 test/com/jdbernard/pit/FileIssueTest.groovy
|
badd +1 test/com/jdbernard/pit/FileIssueTest.groovy
|
||||||
badd +1 src/com/jdbernard/pit/FileProject.groovy
|
badd +1 src/com/jdbernard/pit/FileProject.groovy
|
||||||
badd +0 test/com/jdbernard/pit/FileProjectTest.groovy
|
badd +1 test/com/jdbernard/pit/FileProjectTest.groovy
|
||||||
args build.xml
|
args build.xml
|
||||||
edit build.xml
|
edit build.xml
|
||||||
set splitbelow splitright
|
set splitbelow splitright
|
||||||
@ -701,12 +701,12 @@ setlocal nowinfixwidth
|
|||||||
setlocal wrap
|
setlocal wrap
|
||||||
setlocal wrapmargin=0
|
setlocal wrapmargin=0
|
||||||
silent! normal! zE
|
silent! normal! zE
|
||||||
let s:l = 103 - ((26 * winheight(0) + 39) / 78)
|
let s:l = 1 - ((0 * winheight(0) + 39) / 78)
|
||||||
if s:l < 1 | let s:l = 1 | endif
|
if s:l < 1 | let s:l = 1 | endif
|
||||||
exe s:l
|
exe s:l
|
||||||
normal! zt
|
normal! zt
|
||||||
103
|
1
|
||||||
normal! 04l
|
normal! 0
|
||||||
wincmd w
|
wincmd w
|
||||||
exe 'vert 1resize ' . ((&columns * 91 + 91) / 182)
|
exe 'vert 1resize ' . ((&columns * 91 + 91) / 182)
|
||||||
exe 'vert 2resize ' . ((&columns * 90 + 91) / 182)
|
exe 'vert 2resize ' . ((&columns * 90 + 91) / 182)
|
||||||
@ -1260,12 +1260,12 @@ setlocal nowinfixwidth
|
|||||||
setlocal wrap
|
setlocal wrap
|
||||||
setlocal wrapmargin=0
|
setlocal wrapmargin=0
|
||||||
silent! normal! zE
|
silent! normal! zE
|
||||||
let s:l = 40 - ((39 * winheight(0) + 39) / 78)
|
let s:l = 1 - ((0 * winheight(0) + 39) / 78)
|
||||||
if s:l < 1 | let s:l = 1 | endif
|
if s:l < 1 | let s:l = 1 | endif
|
||||||
exe s:l
|
exe s:l
|
||||||
normal! zt
|
normal! zt
|
||||||
40
|
1
|
||||||
normal! 029l
|
normal! 0
|
||||||
wincmd w
|
wincmd w
|
||||||
argglobal
|
argglobal
|
||||||
edit test/com/jdbernard/pit/FileProjectTest.groovy
|
edit test/com/jdbernard/pit/FileProjectTest.groovy
|
||||||
@ -1364,17 +1364,16 @@ setlocal nowinfixwidth
|
|||||||
setlocal wrap
|
setlocal wrap
|
||||||
setlocal wrapmargin=0
|
setlocal wrapmargin=0
|
||||||
silent! normal! zE
|
silent! normal! zE
|
||||||
let s:l = 154 - ((77 * winheight(0) + 39) / 78)
|
let s:l = 1 - ((0 * winheight(0) + 39) / 78)
|
||||||
if s:l < 1 | let s:l = 1 | endif
|
if s:l < 1 | let s:l = 1 | endif
|
||||||
exe s:l
|
exe s:l
|
||||||
normal! zt
|
normal! zt
|
||||||
154
|
1
|
||||||
normal! 0
|
normal! 0
|
||||||
wincmd w
|
wincmd w
|
||||||
2wincmd w
|
|
||||||
exe 'vert 1resize ' . ((&columns * 91 + 91) / 182)
|
exe 'vert 1resize ' . ((&columns * 91 + 91) / 182)
|
||||||
exe 'vert 2resize ' . ((&columns * 90 + 91) / 182)
|
exe 'vert 2resize ' . ((&columns * 90 + 91) / 182)
|
||||||
tabnext 6
|
tabnext 1
|
||||||
if exists('s:wipebuf')
|
if exists('s:wipebuf')
|
||||||
silent exe 'bwipe ' . s:wipebuf
|
silent exe 'bwipe ' . s:wipebuf
|
||||||
endif
|
endif
|
||||||
|
@ -8,9 +8,11 @@ public enum Category {
|
|||||||
|
|
||||||
public static Category toCategory(String s) {
|
public static Category toCategory(String s) {
|
||||||
for(c in Category.values())
|
for(c in Category.values())
|
||||||
if (c.toString().startsWith(s.toUpperCase())) return c
|
if (c.name().startsWith(s.toUpperCase())) return c
|
||||||
throw new IllegalArgumentException("No category matches ${s}.")
|
throw new IllegalArgumentException("No category matches ${s}.")
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSymbol() { toString()[0].toLowerCase() }
|
public String getSymbol() { toString()[0].toLowerCase() }
|
||||||
|
|
||||||
|
public String toString() { return "${name()[0]}${name()[1..-1].toLowerCase()}" }
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,11 @@ public class FileIssue extends Issue {
|
|||||||
|
|
||||||
public String getFilename() { return makeFilename(id, category, priority) }
|
public String getFilename() { return makeFilename(id, category, priority) }
|
||||||
|
|
||||||
|
public void setText(String text) {
|
||||||
|
super.setText(text)
|
||||||
|
source.write(text)
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isValidFilename(String name) {
|
public static boolean isValidFilename(String name) {
|
||||||
return name ==~ /(\d+)([bcft])(\d).*/
|
return name ==~ /(\d+)([bcft])(\d).*/
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ class FileProject extends Project {
|
|||||||
protected File source
|
protected File source
|
||||||
|
|
||||||
public FileProject(File dir) {
|
public FileProject(File dir) {
|
||||||
super(dir.name)
|
super(dir.canonicalFile.name)
|
||||||
|
|
||||||
if (!dir.isDirectory())
|
if (!dir.isDirectory())
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
@ -65,6 +65,15 @@ class FileProject extends Project {
|
|||||||
return issue
|
return issue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FileProject createNewProject(String name) {
|
||||||
|
def newDir = new File(source, name)
|
||||||
|
newDir.mkdirs()
|
||||||
|
|
||||||
|
return new FileProject(newDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean delete() { return source.delete() }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() { return name }
|
public String toString() { return name }
|
||||||
|
|
||||||
|
@ -30,4 +30,8 @@ public abstract class Project {
|
|||||||
String toString() { return name }
|
String toString() { return name }
|
||||||
|
|
||||||
public abstract Issue createNewIssue(Map options)
|
public abstract Issue createNewIssue(Map options)
|
||||||
|
|
||||||
|
public abstract Project createNewProject(String name)
|
||||||
|
|
||||||
|
public abstract boolean delete()
|
||||||
}
|
}
|
||||||
|
@ -7,4 +7,10 @@ class MockProject extends Project {
|
|||||||
public Issue createNewIssue(Map options) {
|
public Issue createNewIssue(Map options) {
|
||||||
throw new UnsupportedOperationException()
|
throw new UnsupportedOperationException()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Project createNewProject(String name) {
|
||||||
|
throw new UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean delete() { return true }
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
package com.jdbernard.pit.swing
|
package com.jdbernard.pit.swing
|
||||||
|
|
||||||
import com.jdbernard.pit.Category
|
import com.jdbernard.pit.Category
|
||||||
|
import com.jdbernard.pit.Filter
|
||||||
import com.jdbernard.pit.Issue
|
import com.jdbernard.pit.Issue
|
||||||
import com.jdbernard.pit.Project
|
import com.jdbernard.pit.Project
|
||||||
import com.jdbernard.pit.FileProject
|
import com.jdbernard.pit.FileProject
|
||||||
|
import groovy.beans.Bindable
|
||||||
|
import java.awt.event.MouseEvent
|
||||||
import javax.swing.DefaultListModel
|
import javax.swing.DefaultListModel
|
||||||
import javax.swing.JFileChooser
|
import javax.swing.JFileChooser
|
||||||
|
import javax.swing.JOptionPane
|
||||||
import javax.swing.JSplitPane
|
import javax.swing.JSplitPane
|
||||||
import javax.swing.ListSelectionModel
|
import javax.swing.ListSelectionModel
|
||||||
import javax.swing.tree.DefaultMutableTreeNode
|
import javax.swing.tree.DefaultMutableTreeNode
|
||||||
@ -14,34 +18,78 @@ import javax.swing.tree.DefaultTreeModel
|
|||||||
import javax.swing.tree.TreeSelectionModel
|
import javax.swing.tree.TreeSelectionModel
|
||||||
import net.miginfocom.swing.MigLayout
|
import net.miginfocom.swing.MigLayout
|
||||||
|
|
||||||
// VIEW-Specific data
|
/* ********************
|
||||||
|
* VIEW-Specific data
|
||||||
|
* ********************/
|
||||||
|
|
||||||
|
// cache the ListModels
|
||||||
projectListModels = [:]
|
projectListModels = [:]
|
||||||
|
|
||||||
categoryIcons = [(Category.BUG): imageIcon('/bug.png'),
|
// map of category -> list icon
|
||||||
(Category.CLOSED): imageIcon('/closed.png'),
|
categoryIcons = [:]
|
||||||
(Category.FEATURE): imageIcon('/feature.png'),
|
|
||||||
(Category.TASK): imageIcon('/task.png')]
|
|
||||||
|
|
||||||
openDialog = fileChooser(fileSelectionMode: JFileChooser.DIRECTORIES_ONLY)
|
// filter for projects and issues
|
||||||
|
filter = new Filter(categories: [])
|
||||||
|
|
||||||
// event methods
|
@Bindable def popupProject = null
|
||||||
displayProject = { evt = null ->
|
|
||||||
def project= evt?.newLeadSelectionPath?.lastPathComponent?.userObject
|
// initialize category-related view data
|
||||||
|
Category.values().each {
|
||||||
|
categoryIcons[(it)] = imageIcon("/${it.name().toLowerCase()}.png")
|
||||||
|
filter.categories.add(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ***************
|
||||||
|
* event methods
|
||||||
|
* ***************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* displayProject
|
||||||
|
* @param project Project to display.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
displayProject = { project = null ->
|
||||||
issueTextArea.text = ""
|
issueTextArea.text = ""
|
||||||
if (!project) return
|
if (!project) return
|
||||||
|
|
||||||
if (!projectListModels[(project.name)]) {
|
if (!projectListModels[(project.name)]) {
|
||||||
def model = new DefaultListModel()
|
def model = new DefaultListModel()
|
||||||
project.eachIssue { model.addElement(it) }
|
project.eachIssue(filter) { model.addElement(it) }
|
||||||
projectListModels[(project.name)] = model
|
projectListModels[(project.name)] = model
|
||||||
}
|
}
|
||||||
|
|
||||||
issueList.setModel(projectListModels[(project.name)])
|
issueList.setModel(projectListModels[(project.name)])
|
||||||
}
|
}
|
||||||
|
|
||||||
displayIssue = { evt = null ->
|
displayIssue = { issue = null ->
|
||||||
if (issueList.selectedValue)
|
if (issue) issueTextArea.text = issue.text
|
||||||
issueTextArea.text = issueList.selectedValue.text
|
}
|
||||||
|
|
||||||
|
showProjectPopup = { project, x, y ->
|
||||||
|
popupProject = project
|
||||||
|
projectPopupMenu[1].enabled = project != null
|
||||||
|
projectPopupMenu.show(projectTree, x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ****************
|
||||||
|
* GUI components
|
||||||
|
* ****************/
|
||||||
|
openDialog = fileChooser(fileSelectionMode: JFileChooser.DIRECTORIES_ONLY)
|
||||||
|
|
||||||
|
projectPopupMenu = popupMenu() {
|
||||||
|
menuItem('New Project...',
|
||||||
|
actionPerformed: {
|
||||||
|
def name = JOptionPane.showInputDialog(frame, 'Project name:',
|
||||||
|
'New Project...', JOptionPane.QUESTION_MESSAGE)
|
||||||
|
|
||||||
|
if (!popupProject) popupProject = model.rootProject
|
||||||
|
def newProject = popupProject.createNewProject(name)
|
||||||
|
|
||||||
|
projectTree.model = new DefaultTreeModel(
|
||||||
|
makeNodes(model.rootProject))
|
||||||
|
})
|
||||||
|
menuItem('Delete Project',
|
||||||
|
actionPerformed: { popupProject.delete() })
|
||||||
}
|
}
|
||||||
|
|
||||||
frame = application(title:'Personal Issue Tracker',
|
frame = application(title:'Personal Issue Tracker',
|
||||||
@ -69,6 +117,29 @@ frame = application(title:'Personal Issue Tracker',
|
|||||||
projectDir = openDialog.selectedFile
|
projectDir = openDialog.selectedFile
|
||||||
model.rootProject = new FileProject(projectDir)
|
model.rootProject = new FileProject(projectDir)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
menuItem('Exit', actionPerformed: { app.shutdown() })
|
||||||
|
}
|
||||||
|
|
||||||
|
menu('View') {
|
||||||
|
Category.values().each {
|
||||||
|
checkBoxMenuItem(it.toString(),
|
||||||
|
selected: filter.categories.contains(it),
|
||||||
|
actionPerformed: { evt ->
|
||||||
|
def cat = Category.toCategory(evt.source.text)
|
||||||
|
if (filter.categories.contains(cat)) {
|
||||||
|
filter.categories.remove(cat)
|
||||||
|
evt.source.selected = false
|
||||||
|
} else {
|
||||||
|
filter.categories.add(cat)
|
||||||
|
evt.source.selected = true
|
||||||
|
}
|
||||||
|
projectListModels.clear()
|
||||||
|
displayProject(projectTree.leadSelectionPath
|
||||||
|
?.lastPathComponent?.userObject)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +160,19 @@ frame = application(title:'Personal Issue Tracker',
|
|||||||
new DefaultTreeModel(makeNodes(model.rootProject))
|
new DefaultTreeModel(makeNodes(model.rootProject))
|
||||||
} else new DefaultTreeModel()
|
} else new DefaultTreeModel()
|
||||||
}),
|
}),
|
||||||
valueChanged: displayProject)
|
valueChanged: { evt ->
|
||||||
|
displayProject(evt?.newLeadSelectionPath
|
||||||
|
?.lastPathComponent?.userObject)
|
||||||
|
},
|
||||||
|
mouseClicked: { evt ->
|
||||||
|
if (evt.button == MouseEvent.BUTTON3) {
|
||||||
|
showProjectPopup(
|
||||||
|
projectTree.getPathForLocation(evt.x, evt.y)
|
||||||
|
?.lastPathComponent?.userObject,
|
||||||
|
evt.x, evt.y)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
projectTree.selectionModel.selectionMode =
|
projectTree.selectionModel.selectionMode =
|
||||||
TreeSelectionModel.SINGLE_TREE_SELECTION
|
TreeSelectionModel.SINGLE_TREE_SELECTION
|
||||||
}
|
}
|
||||||
@ -103,7 +186,7 @@ frame = application(title:'Personal Issue Tracker',
|
|||||||
cellRenderer: new IssueListCellRenderer(
|
cellRenderer: new IssueListCellRenderer(
|
||||||
issueIcons: categoryIcons),
|
issueIcons: categoryIcons),
|
||||||
selectionMode: ListSelectionModel.SINGLE_SELECTION,
|
selectionMode: ListSelectionModel.SINGLE_SELECTION,
|
||||||
valueChanged: displayIssue)
|
valueChanged: { displayIssue(issueList.selectedValue) })
|
||||||
}
|
}
|
||||||
scrollPane(constraints: "bottom") {
|
scrollPane(constraints: "bottom") {
|
||||||
issueTextArea = textArea()
|
issueTextArea = textArea()
|
||||||
@ -112,8 +195,11 @@ frame = application(title:'Personal Issue Tracker',
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ******************
|
||||||
|
* Auxilary methods
|
||||||
|
* ******************/
|
||||||
def makeNodes(Project project) {
|
def makeNodes(Project project) {
|
||||||
def rootNode = new DefaultMutableTreeNode(project)
|
def rootNode = new DefaultMutableTreeNode(project)
|
||||||
project.eachProject { rootNode.add(makeNodes(it)) }
|
project.eachProject(filter) { rootNode.add(makeNodes(it)) }
|
||||||
return rootNode
|
return rootNode
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
application.version=1.1.4
|
application.version=1.1.5
|
||||||
|
Loading…
x
Reference in New Issue
Block a user