HG corrupted local copy, lost 22 changesets

This commit is contained in:
Jonathan Bernard 2010-02-26 13:21:24 -06:00
parent 39d98f7dde
commit 4179b993f4
80 changed files with 769 additions and 111 deletions

View File

@ -0,0 +1,2 @@
Fix Issue.toString() so that only the first letter is capitalized.
==================================================================

33
issues/libpit/0021fs.rst Normal file
View File

@ -0,0 +1,33 @@
Divorce opened/closed status and classification.
================================================
We need to track open/closed status and classification independantly.
Classification is one category, status should be another. Possible values for
status:
* new
* resolved
* awaiting validation
* rejected
* reassigned
For the file-based issue implementation, the file format changes from
``nnnnsp`` to ``nnnncsp`` where:
* ``nnnn`` still represents the bug number (no change)
* ``c`` represents the *category* (used to be ``s`` the status):
* ``b``: Bug
* ``f``: Feature
* ``t``: Task
* ``s`` represents *status*, a new field:
* ``a``: Reassigned
* ``j``: Rejected
* ``n``: New
* ``s``: Resolved
* ``v``: Awaiting Validation
* ``p`` still represents priority, ``0`` being the highest and ``9`` the
lowest.

View File

@ -0,0 +1,5 @@
Remember last opened directory.
===============================
This affects the JFileChooser, not the model.rootProject.

View File

@ -0,0 +1,2 @@
De-select the 'CLOSED' category by default.
===========================================

View File

@ -0,0 +1,2 @@
Clear the 'New Task...' dialog when hidden.
===========================================

View File

@ -0,0 +1,2 @@
Set the default priority to '5'.
================================

View File

@ -0,0 +1,2 @@
Issue display needs to save changes.
====================================

View File

@ -0,0 +1,2 @@
Do not load project directory on startup.
=========================================

View File

@ -0,0 +1,2 @@
Clear project lists when opening a new directory.
=================================================

View File

@ -0,0 +1,5 @@
Issue display may still lose changes.
=====================================
If the mouse is not within the text area and the user clicks on something
that changes the text area content, the changes are not saved.

View File

@ -0,0 +1 @@
Add an optional word-wrap at 80 characters for the Issue display

View File

@ -0,0 +1,2 @@
Make 'New' the default new issue status.
========================================

View File

@ -0,0 +1,2 @@
Add the ability to sort issues based on priority, id, category, or status.
==========================================================================

View File

@ -1,10 +1,10 @@
#Thu Feb 25 17:24:06 CST 2010 #Fri Feb 26 11:43:12 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=1 build.number=2
expected.application.version=1.1.8 expected.application.version=2.0.1
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.

Binary file not shown.

View File

@ -46,6 +46,8 @@ badd +1 src/com/jdbernard/pit/FileIssue.groovy
badd +1 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 +1 test/com/jdbernard/pit/FileProjectTest.groovy badd +1 test/com/jdbernard/pit/FileProjectTest.groovy
badd +1 src/com/jdbernard/pit/Status.groovy
badd +0 test/com/jdbernard/pit/StatusTest.groovy
args build.xml args build.xml
edit build.xml edit build.xml
set splitbelow splitright set splitbelow splitright
@ -155,7 +157,7 @@ setlocal nowinfixwidth
setlocal wrap setlocal wrap
setlocal wrapmargin=0 setlocal wrapmargin=0
silent! normal! zE silent! normal! zE
let s:l = 1 - ((0 * winheight(0) + 39) / 78) let s:l = 1 - ((0 * winheight(0) + 28) / 57)
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
@ -259,7 +261,7 @@ setlocal nowinfixwidth
setlocal wrap setlocal wrap
setlocal wrapmargin=0 setlocal wrapmargin=0
silent! normal! zE silent! normal! zE
let s:l = 1 - ((0 * winheight(0) + 39) / 78) let s:l = 1 - ((0 * winheight(0) + 28) / 57)
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
@ -376,7 +378,7 @@ setlocal nowinfixwidth
setlocal wrap setlocal wrap
setlocal wrapmargin=0 setlocal wrapmargin=0
silent! normal! zE silent! normal! zE
let s:l = 1 - ((0 * winheight(0) + 39) / 78) let s:l = 1 - ((0 * winheight(0) + 28) / 57)
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
@ -480,7 +482,228 @@ setlocal nowinfixwidth
setlocal wrap setlocal wrap
setlocal wrapmargin=0 setlocal wrapmargin=0
silent! normal! zE silent! normal! zE
let s:l = 1 - ((0 * winheight(0) + 39) / 78) let s:l = 1 - ((0 * winheight(0) + 28) / 57)
if s:l < 1 | let s:l = 1 | endif
exe s:l
normal! zt
1
normal! 0
wincmd w
exe 'vert 1resize ' . ((&columns * 91 + 91) / 182)
exe 'vert 2resize ' . ((&columns * 90 + 91) / 182)
tabedit src/com/jdbernard/pit/Status.groovy
set splitbelow splitright
wincmd _ | wincmd |
vsplit
1wincmd h
wincmd w
set nosplitbelow
set nosplitright
wincmd t
set winheight=1 winwidth=1
exe 'vert 1resize ' . ((&columns * 91 + 91) / 182)
exe 'vert 2resize ' . ((&columns * 90 + 91) / 182)
argglobal
setlocal keymap=
setlocal noarabic
setlocal autoindent
setlocal balloonexpr=
setlocal nobinary
setlocal bufhidden=
setlocal buflisted
setlocal buftype=
setlocal nocindent
setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e
setlocal cinoptions=
setlocal cinwords=if,else,while,do,for,switch
setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-
setlocal commentstring=/*%s*/
setlocal complete=.,w,b,u,t,i
setlocal completefunc=
setlocal nocopyindent
setlocal nocursorcolumn
setlocal nocursorline
setlocal define=
setlocal dictionary=
setlocal nodiff
setlocal equalprg=
setlocal errorformat=
setlocal expandtab
if &filetype != 'groovy'
setlocal filetype=groovy
endif
setlocal foldcolumn=0
setlocal foldenable
setlocal foldexpr=0
setlocal foldignore=#
setlocal foldlevel=0
setlocal foldmarker={{{,}}}
setlocal foldmethod=manual
setlocal foldminlines=1
setlocal foldnestmax=20
setlocal foldtext=foldtext()
setlocal formatexpr=
setlocal formatoptions=tcq
setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s*
setlocal grepprg=
setlocal iminsert=2
setlocal imsearch=2
setlocal include=
setlocal includeexpr=
setlocal indentexpr=
setlocal indentkeys=0{,0},:,0#,!^F,o,O,e
setlocal noinfercase
setlocal iskeyword=@,48-57,_,192-255
setlocal keywordprg=
setlocal nolinebreak
setlocal nolisp
setlocal nolist
setlocal makeprg=
setlocal matchpairs=(:),{:},[:]
setlocal nomodeline
setlocal modifiable
setlocal nrformats=octal,hex
set number
setlocal number
setlocal numberwidth=4
setlocal omnifunc=
setlocal path=
setlocal nopreserveindent
setlocal nopreviewwindow
setlocal quoteescape=\\
setlocal noreadonly
setlocal norightleft
setlocal rightleftcmd=search
setlocal noscrollbind
setlocal shiftwidth=4
setlocal noshortname
setlocal nosmartindent
setlocal softtabstop=0
setlocal nospell
setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+
setlocal spellfile=
setlocal spelllang=en
setlocal statusline=
setlocal suffixesadd=
setlocal swapfile
setlocal synmaxcol=3000
if &syntax != 'groovy'
setlocal syntax=groovy
endif
setlocal tabstop=4
setlocal tags=
setlocal textwidth=0
setlocal thesaurus=
setlocal nowinfixheight
setlocal nowinfixwidth
setlocal wrap
setlocal wrapmargin=0
silent! normal! zE
let s:l = 37 - ((36 * winheight(0) + 28) / 57)
if s:l < 1 | let s:l = 1 | endif
exe s:l
normal! zt
37
normal! 065l
wincmd w
argglobal
edit test/com/jdbernard/pit/StatusTest.groovy
setlocal keymap=
setlocal noarabic
setlocal autoindent
setlocal balloonexpr=
setlocal nobinary
setlocal bufhidden=
setlocal buflisted
setlocal buftype=
setlocal nocindent
setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e
setlocal cinoptions=
setlocal cinwords=if,else,while,do,for,switch
setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-
setlocal commentstring=/*%s*/
setlocal complete=.,w,b,u,t,i
setlocal completefunc=
setlocal nocopyindent
setlocal nocursorcolumn
setlocal nocursorline
setlocal define=
setlocal dictionary=
setlocal nodiff
setlocal equalprg=
setlocal errorformat=
setlocal expandtab
if &filetype != 'groovy'
setlocal filetype=groovy
endif
setlocal foldcolumn=0
setlocal foldenable
setlocal foldexpr=0
setlocal foldignore=#
setlocal foldlevel=0
setlocal foldmarker={{{,}}}
setlocal foldmethod=manual
setlocal foldminlines=1
setlocal foldnestmax=20
setlocal foldtext=foldtext()
setlocal formatexpr=
setlocal formatoptions=tcq
setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s*
setlocal grepprg=
setlocal iminsert=2
setlocal imsearch=2
setlocal include=
setlocal includeexpr=
setlocal indentexpr=
setlocal indentkeys=0{,0},:,0#,!^F,o,O,e
setlocal noinfercase
setlocal iskeyword=@,48-57,_,192-255
setlocal keywordprg=
setlocal nolinebreak
setlocal nolisp
setlocal nolist
setlocal makeprg=
setlocal matchpairs=(:),{:},[:]
setlocal nomodeline
setlocal modifiable
setlocal nrformats=octal,hex
set number
setlocal number
setlocal numberwidth=4
setlocal omnifunc=
setlocal path=
setlocal nopreserveindent
setlocal nopreviewwindow
setlocal quoteescape=\\
setlocal noreadonly
setlocal norightleft
setlocal rightleftcmd=search
setlocal noscrollbind
setlocal shiftwidth=4
setlocal noshortname
setlocal nosmartindent
setlocal softtabstop=0
setlocal nospell
setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+
setlocal spellfile=
setlocal spelllang=en
setlocal statusline=
setlocal suffixesadd=
setlocal swapfile
setlocal synmaxcol=3000
if &syntax != 'groovy'
setlocal syntax=groovy
endif
setlocal tabstop=4
setlocal tags=
setlocal textwidth=0
setlocal thesaurus=
setlocal nowinfixheight
setlocal nowinfixwidth
setlocal wrap
setlocal wrapmargin=0
silent! normal! zE
let s:l = 1 - ((0 * winheight(0) + 28) / 57)
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
@ -597,7 +820,7 @@ setlocal nowinfixwidth
setlocal wrap setlocal wrap
setlocal wrapmargin=0 setlocal wrapmargin=0
silent! normal! zE silent! normal! zE
let s:l = 1 - ((0 * winheight(0) + 39) / 78) let s:l = 1 - ((0 * winheight(0) + 28) / 57)
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
@ -701,7 +924,7 @@ setlocal nowinfixwidth
setlocal wrap setlocal wrap
setlocal wrapmargin=0 setlocal wrapmargin=0
silent! normal! zE silent! normal! zE
let s:l = 1 - ((0 * winheight(0) + 39) / 78) let s:l = 1 - ((0 * winheight(0) + 28) / 57)
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
@ -818,7 +1041,7 @@ setlocal nowinfixwidth
setlocal wrap setlocal wrap
setlocal wrapmargin=0 setlocal wrapmargin=0
silent! normal! zE silent! normal! zE
let s:l = 1 - ((0 * winheight(0) + 39) / 78) let s:l = 1 - ((0 * winheight(0) + 28) / 57)
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
@ -922,7 +1145,7 @@ setlocal nowinfixwidth
setlocal wrap setlocal wrap
setlocal wrapmargin=0 setlocal wrapmargin=0
silent! normal! zE silent! normal! zE
let s:l = 1 - ((0 * winheight(0) + 39) / 78) let s:l = 1 - ((0 * winheight(0) + 28) / 57)
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
@ -1039,12 +1262,12 @@ setlocal nowinfixwidth
setlocal wrap setlocal wrap
setlocal wrapmargin=0 setlocal wrapmargin=0
silent! normal! zE silent! normal! zE
let s:l = 9 - ((8 * winheight(0) + 39) / 78) let s:l = 9 - ((6 * winheight(0) + 28) / 57)
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
9 9
normal! 010l normal! 0
wincmd w wincmd w
argglobal argglobal
edit test/com/jdbernard/pit/FileIssueTest.groovy edit test/com/jdbernard/pit/FileIssueTest.groovy
@ -1143,7 +1366,7 @@ setlocal nowinfixwidth
setlocal wrap setlocal wrap
setlocal wrapmargin=0 setlocal wrapmargin=0
silent! normal! zE silent! normal! zE
let s:l = 1 - ((0 * winheight(0) + 39) / 78) let s:l = 1 - ((0 * winheight(0) + 28) / 57)
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
@ -1260,7 +1483,7 @@ setlocal nowinfixwidth
setlocal wrap setlocal wrap
setlocal wrapmargin=0 setlocal wrapmargin=0
silent! normal! zE silent! normal! zE
let s:l = 1 - ((0 * winheight(0) + 39) / 78) let s:l = 1 - ((0 * winheight(0) + 28) / 57)
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
@ -1364,7 +1587,7 @@ setlocal nowinfixwidth
setlocal wrap setlocal wrap
setlocal wrapmargin=0 setlocal wrapmargin=0
silent! normal! zE silent! normal! zE
let s:l = 1 - ((0 * winheight(0) + 39) / 78) let s:l = 1 - ((0 * winheight(0) + 28) / 57)
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
@ -1373,7 +1596,7 @@ 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)
tabnext 1 tabnext 3
if exists('s:wipebuf') if exists('s:wipebuf')
silent exe 'bwipe ' . s:wipebuf silent exe 'bwipe ' . s:wipebuf
endif endif

View File

@ -3,8 +3,7 @@ package com.jdbernard.pit
public enum Category { public enum Category {
BUG, BUG,
FEATURE, FEATURE,
TASK, TASK
CLOSED
public static Category toCategory(String s) { public static Category toCategory(String s) {
for(c in Category.values()) for(c in Category.values())

View File

@ -5,19 +5,21 @@ import java.lang.IllegalArgumentException as IAE
public class FileIssue extends Issue { public class FileIssue extends Issue {
protected File source protected File source
public static final String fileExp = /(\d+)([bft])([ajnsv])(\d).*/
public FileIssue(File file) { public FileIssue(File file) {
super('REPLACE_ME') super('REPLACE_ME')
def matcher = file.name =~ /(\d{4})([bftc])(\d).*/ def matcher = file.name =~ fileExp
if (!matcher) if (!matcher)
throw new IllegalArgumentException("${file} " + throw new IllegalArgumentException("${file} " +
"is not a valid Issue file.") "is not a valid Issue file.")
super.@id = matcher[0][1] super.@id = matcher[0][1]
super.@category = Category.toCategory(matcher[0][2]) super.@category = Category.toCategory(matcher[0][2])
super.@priority = matcher[0][3].toInteger() super.@status = Status.toStatus(matcher[0][3])
super.@priority = matcher[0][4].toInteger()
this.source = file this.source = file
@ -29,12 +31,19 @@ public class FileIssue extends Issue {
source.renameTo(new File(source.canonicalFile.parentFile, getFilename())) source.renameTo(new File(source.canonicalFile.parentFile, getFilename()))
} }
public void setStatus(Status s) {
super.setStatus(s)
source.renameTo(new File(source.canonicalFile.parentFile, getFilename()))
}
public void setPriority(int p) { public void setPriority(int p) {
super.setPriority(p) super.setPriority(p)
source.renameTo(new File(source.canonicalFile.parentFile, getFilename())) source.renameTo(new File(source.canonicalFile.parentFile, getFilename()))
} }
public String getFilename() { return makeFilename(id, category, priority) } public String getFilename() {
return makeFilename(id, category, status, priority)
}
public void setText(String text) { public void setText(String text) {
super.setText(text) super.setText(text)
@ -44,11 +53,11 @@ public class FileIssue extends Issue {
public boolean delete() { return source.delete() } public boolean delete() { return source.delete() }
public static boolean isValidFilename(String name) { public static boolean isValidFilename(String name) {
return name ==~ /(\d+)([bcft])(\d).*/ return name ==~ fileExp
} }
public static String makeFilename(String id, Category category, public static String makeFilename(String id, Category category,
int priority) { Status status, int priority) {
// bounds check priority // bounds check priority
priority = Math.min(9, Math.max(0, priority)) priority = Math.min(9, Math.max(0, priority))
@ -56,10 +65,12 @@ public class FileIssue extends Issue {
//check for valid values of cateogry and id //check for valid values of cateogry and id
if (category == null) if (category == null)
throw new IAE("Category must be non-null.") throw new IAE("Category must be non-null.")
if (status == null)
throw new IAE("Status must be non-null.")
if (!(id ==~ /\d+/)) if (!(id ==~ /\d+/))
throw new IAE( "'${id}' is not a legal value for id.") throw new IAE( "'${id}' is not a legal value for id.")
return id + category.symbol + priority + ".rst"; return id + category.symbol + status.symbol + priority + ".rst";
} }
} }

View File

@ -17,7 +17,7 @@ class FileProject extends Project {
// add sub projects // add sub projects
if (child.isDirectory()) { if (child.isDirectory()) {
if ( child.name ==~ /\d{4}/) return // just an issue folder if ( child.name ==~ /\d+/) return // just an issue folder
// otherwise build and add to list // otherwise build and add to list
projects[(child.name)] = new FileProject(child) projects[(child.name)] = new FileProject(child)
@ -41,6 +41,7 @@ class FileProject extends Project {
public FileIssue createNewIssue(Map options) { public FileIssue createNewIssue(Map options) {
if (!options) options = [:] if (!options) options = [:]
if (!options.category) options.category = Category.TASK if (!options.category) options.category = Category.TASK
if (!options.status) options.status = Status.NEW
if (!options.priority) options.priority = 5 if (!options.priority) options.priority = 5
if (!options.text) options.text = "Default issue title.\n" + if (!options.text) options.text = "Default issue title.\n" +
"====================\n" "====================\n"
@ -52,7 +53,7 @@ class FileProject extends Project {
} }
def issueFile = new File(source, FileIssue.makeFilename(id, def issueFile = new File(source, FileIssue.makeFilename(id,
options.category, options.priority)) options.category, options.status, options.priority))
issueFile.createNewFile() issueFile.createNewFile()
issueFile.write(options.text) issueFile.write(options.text)

View File

@ -3,6 +3,7 @@ package com.jdbernard.pit
class Filter { class Filter {
List<Category> categories = null List<Category> categories = null
List<Status> status = null
List<String> projects = null List<String> projects = null
List<String> ids = null List<String> ids = null
int priority = 9 int priority = 9
@ -16,6 +17,7 @@ class Filter {
public boolean accept(Issue i) { public boolean accept(Issue i) {
return (i.priority <= priority && return (i.priority <= priority &&
(!categories || categories.contains(i.category)) && (!categories || categories.contains(i.category)) &&
(!status || status.contains(i.status)) &&
(!ids || ids.contains(i.id))) (!ids || ids.contains(i.id)))
} }

View File

@ -6,12 +6,15 @@ public abstract class Issue {
protected String id protected String id
protected Category category protected Category category
protected Status status
protected int priority protected int priority
protected String text protected String text
Issue(String id, Category c = Category.TASK, int p = 9) { Issue(String id, Category c = Category.TASK, Status s = Status.NEW,
int p = 9) {
this.id = id this.id = id
this.category = c this.category = c
this.status = s
this.priority = p this.priority = p
} }
@ -26,6 +29,15 @@ public abstract class Issue {
this.category = c this.category = c
} }
public Status getStatus() { return status }
public void setStatus(Status s) {
if (s == null)
throw new IAE("Status cannot be null.")
this.status = s
}
public int getPriority() { return priority } public int getPriority() { return priority }
public void setPriority(int p) { priority = Math.min(9, Math.max(0, p)) } public void setPriority(int p) { priority = Math.min(9, Math.max(0, p)) }
@ -37,7 +49,7 @@ public abstract class Issue {
public void setText(String t) { text = t } public void setText(String t) { text = t }
@Override @Override
public String toString() { return "${id}(${priority}): ${category} ${title}" } public String toString() { return "${id}(${priority}-${status}): ${category} ${title}" }
public abstract boolean delete() public abstract boolean delete()
} }

View File

@ -0,0 +1,41 @@
package com.jdbernard.pit
public enum Status {
REASSIGNED('a'),
REJECTED('j'),
NEW('n'),
RESOLVED('s'),
VALIDATION_REQUIRED('v')
String symbol
protected Status(String s) { symbol = s }
public static Status toStatus(String str) {
Status retVal = null
for(status in Status.values()) {
if (status.symbol.equalsIgnoreCase(str) ||
status.name().startsWith(str.toUpperCase())) {
if (retVal != null)
throw new IllegalArgumentException("Request string is" +
" ambigous, '${str}' could represent ${retVal} or " +
"${status}, possibly others.")
retVal = status
}
}
if (retVal == null)
throw new IllegalArgumentException("No status matches '${str}'")
return retVal
}
public String toString() {
def words = name().split("_")
String result = ""
words.each { result += "${it[0]}${it[1..-1].toLowerCase()} " }
return result[0..-2]
}
}

View File

@ -0,0 +1,36 @@
package com.jdbernard.pit.util
import com.jdbernard.pit.*
if (args.size() != 1) {
println "Usage: Convert1_2 [dir]"
System.exit(1)
}
File rootDir = new File(args[0])
Scanner scan = new Scanner(System.in)
rootDir.eachFileRecurse { file ->
def m = file.name =~ /(\d+)([bcft])(\d).*/
if (m && file.isFile()) {
println m[0][0]
def parentFile = file.canonicalFile.parentFile
def c
def s
switch(m[0][2]) {
case "c":
println file.readLines()[0]
print "Issue was closed, was category does it belong in?"
c = Category.toCategory(scan.nextLine())
s = Status.RESOLVED
break
default:
c = Category.toCategory(m[0][2])
s = Status.NEW
break
}
println "${m[0][2]}: ${c}"
file.renameTo(new File(parentFile,
FileIssue.makeFilename(m[0][1], c, s, m[0][3].toInteger())))
}
}

View File

@ -12,24 +12,20 @@ class CategoryTest {
assertEquals toCategory("BUG"), Category.BUG assertEquals toCategory("BUG"), Category.BUG
assertEquals toCategory("FEATURE"), Category.FEATURE assertEquals toCategory("FEATURE"), Category.FEATURE
assertEquals toCategory("TASK"), Category.TASK assertEquals toCategory("TASK"), Category.TASK
assertEquals toCategory("CLOSED"), Category.CLOSED
assertEquals toCategory("bug"), Category.BUG assertEquals toCategory("bug"), Category.BUG
assertEquals toCategory("feature"), Category.FEATURE assertEquals toCategory("feature"), Category.FEATURE
assertEquals toCategory("task"), Category.TASK assertEquals toCategory("task"), Category.TASK
assertEquals toCategory("closed"), Category.CLOSED
assertEquals toCategory("b"), Category.BUG assertEquals toCategory("b"), Category.BUG
assertEquals toCategory("f"), Category.FEATURE assertEquals toCategory("f"), Category.FEATURE
assertEquals toCategory("t"), Category.TASK assertEquals toCategory("t"), Category.TASK
assertEquals toCategory("c"), Category.CLOSED
} }
@Test void testGetSymbol() { @Test void testGetSymbol() {
assertEquals Category.BUG.symbol, "b" assertEquals Category.BUG.symbol, "b"
assertEquals Category.CLOSED.symbol, "c"
assertEquals Category.FEATURE.symbol, "f" assertEquals Category.FEATURE.symbol, "f"
assertEquals Category.TASK.symbol, "t" assertEquals Category.TASK.symbol, "t"
} }

View File

@ -17,14 +17,14 @@ class FileIssueTest {
testDir = new File('testdir') testDir = new File('testdir')
testDir.mkdirs() testDir.mkdirs()
issueFile = new File(testDir, '0001f1.rst') issueFile = new File(testDir, '0001fn1.rst')
issueFile.write( issueFile.write(
"Add the killer feature to the killer app.\n" + "Add the killer feature to the killer app.\n" +
"=========================================\n\n" + "=========================================\n\n" +
"Make our killer app shine!.") "Make our killer app shine!.")
issues << new FileIssue(issueFile) issues << new FileIssue(issueFile)
issueFile = new File(testDir, '0002t5.rst') issueFile = new File(testDir, '0002ts5.rst')
issueFile.write( issueFile.write(
"Obtain donuts.\n" + "Obtain donuts.\n" +
"==============\n\n" + "==============\n\n" +
@ -42,16 +42,30 @@ class FileIssueTest {
assertEquals issues[0].category, Category.FEATURE assertEquals issues[0].category, Category.FEATURE
assertEquals issues[1].category, Category.TASK assertEquals issues[1].category, Category.TASK
issues[0].category = Category.CLOSED issues[0].category = Category.TASK
issues[1].category = Category.BUG issues[1].category = Category.BUG
assertEquals issues[0].category, Category.CLOSED assertEquals issues[0].category, Category.TASK
assertEquals issues[1].category, Category.BUG assertEquals issues[1].category, Category.BUG
assertTrue new File(testDir, '0001c1.rst').exists() assertTrue new File(testDir, '0001tn1.rst').exists()
assertTrue new File(testDir, '0002b5.rst').exists() assertTrue new File(testDir, '0002bs5.rst').exists()
assertFalse new File(testDir, '0001f1.rst').exists() assertFalse new File(testDir, '0001fn1.rst').exists()
assertFalse new File(testDir, '0002t5.rst').exists() assertFalse new File(testDir, '0002ts5.rst').exists()
}
@Test void testSetStatus() {
assertEquals issues[0].status, Status.NEW
assertEquals issues[1].status, Status.RESOLVED
issues[0].status = Status.RESOLVED
issues[1].status = Status.REJECTED
assertTrue new File(testDir, '0001fs1.rst').exists()
assertTrue new File(testDir, '0002tj5.rst').exists()
assertFalse new File(testDir, '0001fn1.rst').exists()
assertFalse new File(testDir, '0002ts5.rst').exists()
} }
@Test void testSetPriority() { @Test void testSetPriority() {
@ -65,18 +79,19 @@ class FileIssueTest {
assertEquals issues[0].priority, 2 assertEquals issues[0].priority, 2
assertEquals issues[1].priority, 9 assertEquals issues[1].priority, 9
assertTrue new File(testDir, '0001f2.rst').exists() assertTrue new File(testDir, '0001fn2.rst').exists()
assertTrue new File(testDir, '0002t9.rst').exists() assertTrue new File(testDir, '0002ts9.rst').exists()
assertFalse new File(testDir, '0001f1.rst').exists() assertFalse new File(testDir, '0001fn1.rst').exists()
assertFalse new File(testDir, '0002t5.rst').exists() assertFalse new File(testDir, '0002ts5.rst').exists()
} }
@Test void testConstruction() { @Test void testConstruction() {
File issueFile = new File(testDir, '0001f1.rst') File issueFile = new File(testDir, '0001fn1.rst')
Issue issue = new FileIssue(issueFile) Issue issue = new FileIssue(issueFile)
assertEquals issue.id , "0001" assertEquals issue.id , "0001"
assertEquals issue.category , Category.FEATURE assertEquals issue.category , Category.FEATURE
assertEquals issue.status , Status.NEW
assertEquals issue.priority , 1 assertEquals issue.priority , 1
assertEquals issue.title , "Add the killer feature to the killer app." assertEquals issue.title , "Add the killer feature to the killer app."
assertEquals issue.text , "Add the killer feature to the killer app.\n" + assertEquals issue.text , "Add the killer feature to the killer app.\n" +
@ -86,21 +101,32 @@ class FileIssueTest {
} }
@Test void testMakeFilename() { @Test void testMakeFilename() {
assertEquals FileIssue.makeFilename('0001', Category.BUG, 5) , '0001b5.rst' assertEquals FileIssue.makeFilename('0001', Category.BUG,
assertEquals FileIssue.makeFilename('0010', Category.FEATURE, 1), '0010f1.rst' Status.NEW, 5), '0001bn5.rst'
assertEquals FileIssue.makeFilename('0002', Category.CLOSED, 3) , '0002c3.rst' assertEquals FileIssue.makeFilename('0010', Category.FEATURE,
assertEquals FileIssue.makeFilename('0001', Category.BUG, -2) , '0001b0.rst' Status.REASSIGNED, 1), '0010fa1.rst'
assertEquals FileIssue.makeFilename('0001', Category.TASK, 10) , '0001t9.rst' assertEquals FileIssue.makeFilename('0002', Category.FEATURE,
assertEquals FileIssue.makeFilename('00101', Category.BUG, 5) , '00101b5.rst' Status.REJECTED, 3), '0002fj3.rst'
assertEquals FileIssue.makeFilename('0001', Category.BUG,
Status.RESOLVED, -2), '0001bs0.rst'
assertEquals FileIssue.makeFilename('0001', Category.TASK,
Status.VALIDATION_REQUIRED, 10) , '0001tv9.rst'
assertEquals FileIssue.makeFilename('00101', Category.BUG,
Status.NEW, 5), '00101bn5.rst'
try { try {
FileIssue.makeFilename('badid', Category.BUG, 5) FileIssue.makeFilename('badid', Category.BUG, Status.NEW, 5)
assertTrue 'Issue.makeFilename() succeeded with bad id input.', false assertTrue 'Issue.makeFilename() succeeded with bad id input.', false
} catch (IllegalArgumentException iae) {} } catch (IllegalArgumentException iae) {}
try { try {
FileIssue.makeFilename('0002', null, 5) FileIssue.makeFilename('0002', null, Status.NEW, 5)
assertTrue 'Issue.makeFilename() succeeded given no Category.', false assertTrue 'Issue.makeFilename() succeeded given no Category.', false
} catch (IllegalArgumentException iae) {} } catch (IllegalArgumentException iae) {}
try {
FileIssue.makeFilename('0002', Category.BUG, null, 5)
assertTrue 'Issue.makeFilename() succeeded given no Status.', false
} catch (IllegalArgumentException iae) {}
} }
} }

View File

@ -33,19 +33,19 @@ class FileProjectTest {
*/ */
def issueFile = new File(testDir, '0001t5.rst') def issueFile = new File(testDir, '0001tn5.rst')
issueFile.createNewFile() issueFile.createNewFile()
issueFile.write('Test Issue 1\n' + issueFile.write('Test Issue 1\n' +
'============\n\n' + '============\n\n' +
'This is the first test issue.') 'This is the first test issue.')
issueFile = new File(testDir, '0002b5.rst') issueFile = new File(testDir, '0002ba5.rst')
issueFile.createNewFile() issueFile.createNewFile()
issueFile.write('Test Bug\n' + issueFile.write('Test Bug\n' +
'========\n\n' + '========\n\n' +
'Yeah, it is a test bug.') 'Yeah, it is a test bug.')
issueFile = new File(testDir, '0003c2.rst') issueFile = new File(testDir, '0003fs2.rst')
issueFile.createNewFile() issueFile.createNewFile()
issueFile.write('Important Feature Request\n' + issueFile.write('Important Feature Request\n' +
'=========================\n\n' + '=========================\n\n' +
@ -54,13 +54,13 @@ class FileProjectTest {
def subDir = new File(testDir, 'subproj1') def subDir = new File(testDir, 'subproj1')
subDir.mkdirs() subDir.mkdirs()
issueFile = new File(subDir, '0001f3.rst') issueFile = new File(subDir, '0001fv3.rst')
issueFile.createNewFile() issueFile.createNewFile()
issueFile.write('First feature in subproject\n' + issueFile.write('First feature in subproject\n' +
'===========================\n\n' + '===========================\n\n' +
'Please make the grubblers grobble.') 'Please make the grubblers grobble.')
issueFile = new File(subDir, '0002b4.rst') issueFile = new File(subDir, '0002bj4.rst')
issueFile.createNewFile() issueFile.createNewFile()
issueFile.write('Zippners are not zippning.\n' + issueFile.write('Zippners are not zippning.\n' +
'==========================\n\n' + '==========================\n\n' +
@ -129,11 +129,14 @@ class FileProjectTest {
// test correct increment of id, application of values // test correct increment of id, application of values
def newIssue = rootProj.createNewIssue(category: Category.BUG, def newIssue = rootProj.createNewIssue(category: Category.BUG,
priority: 4, text: 'A newly made bug report.\n'+ status: Status.REASSIGNED, priority: 4,
text: 'A newly made bug report.\n'+
'========================\n\n' + '========================\n\n' +
'Testing the Project.createNewIssue() method.') 'Testing the Project.createNewIssue() method.')
assertEquals newIssue.id, '0004' assertEquals newIssue.id, '0004'
assertEquals newIssue.category, Category.BUG
assertEquals newIssue.status, Status.REASSIGNED
assertEquals newIssue.priority, 4 assertEquals newIssue.priority, 4
assertEquals newIssue.text, 'A newly made bug report.\n'+ assertEquals newIssue.text, 'A newly made bug report.\n'+
'========================\n\n' + '========================\n\n' +
@ -145,6 +148,8 @@ class FileProjectTest {
assertEquals newIssue.id, '0000' assertEquals newIssue.id, '0000'
assertEquals newIssue.priority, 5 assertEquals newIssue.priority, 5
assertEquals newIssue.category, Category.TASK
assertEquals newIssue.status, Status.NEW
assertEquals newIssue.text, 'Default issue title.\n' + assertEquals newIssue.text, 'Default issue title.\n' +
'====================\n' '====================\n'

View File

@ -15,16 +15,16 @@ class FilterTest {
proj = new MockProject('proj1') proj = new MockProject('proj1')
def issue = new MockIssue( '0000', Category.TASK, 5) def issue = new MockIssue( '0000', Category.TASK, Status.NEW, 5)
proj.issues['0000'] = issue proj.issues['0000'] = issue
issue = new MockIssue('0001', Category.BUG, 3) issue = new MockIssue('0001', Category.BUG, Status.REJECTED, 3)
proj.issues['0001'] = issue proj.issues['0001'] = issue
issue = new MockIssue('0002', Category.CLOSED, 9) issue = new MockIssue('0002', Category.BUG, Status.RESOLVED, 9)
proj.issues['0002'] = issue proj.issues['0002'] = issue
issue = new MockIssue('0003', Category.FEATURE, 0) issue = new MockIssue('0003', Category.FEATURE, Status.REASSIGNED, 0)
proj.issues['0003'] = issue proj.issues['0003'] = issue
def subProj = new MockProject('subproj1') def subProj = new MockProject('subproj1')
@ -69,25 +69,47 @@ class FilterTest {
@Test void testCategoryFilter() { @Test void testCategoryFilter() {
Filter f = new Filter(categories: Filter f = new Filter(categories:
[Category.BUG, Category.FEATURE, Category.TASK]) [Category.BUG, Category.FEATURE])
assertFalse f.accept(proj.issues['0000'])
assertTrue f.accept(proj.issues['0001'])
assertTrue f.accept(proj.issues['0002'])
assertTrue f.accept(proj.issues['0003'])
f.categories = [ Category.TASK ]
assertTrue f.accept(proj.issues['0000'])
assertFalse f.accept(proj.issues['0001'])
assertFalse f.accept(proj.issues['0002'])
assertFalse f.accept(proj.issues['0003'])
f.categories = [ Category.BUG, Category.TASK ]
assertTrue f.accept(proj.issues['0000'])
assertTrue f.accept(proj.issues['0001'])
assertTrue f.accept(proj.issues['0002'])
assertFalse f.accept(proj.issues['0003'])
}
@Test void testStatusFilter() {
Filter f = new Filter(status:
[Status.NEW, Status.REASSIGNED, Status.REJECTED])
assertTrue f.accept(proj.issues['0000']) assertTrue f.accept(proj.issues['0000'])
assertTrue f.accept(proj.issues['0001']) assertTrue f.accept(proj.issues['0001'])
assertFalse f.accept(proj.issues['0002']) assertFalse f.accept(proj.issues['0002'])
assertTrue f.accept(proj.issues['0003']) assertTrue f.accept(proj.issues['0003'])
f.categories = [ Category.CLOSED ] f.status = [ Status.RESOLVED ]
assertFalse f.accept(proj.issues['0000']) assertFalse f.accept(proj.issues['0000'])
assertFalse f.accept(proj.issues['0001']) assertFalse f.accept(proj.issues['0001'])
assertTrue f.accept(proj.issues['0002']) assertTrue f.accept(proj.issues['0002'])
assertFalse f.accept(proj.issues['0003']) assertFalse f.accept(proj.issues['0003'])
f.categories = [ Category.BUG, Category.FEATURE ] f.status = [ Status.NEW, Status.RESOLVED ]
assertFalse f.accept(proj.issues['0000']) assertTrue f.accept(proj.issues['0000'])
assertTrue f.accept(proj.issues['0001']) assertFalse f.accept(proj.issues['0001'])
assertFalse f.accept(proj.issues['0002']) assertTrue f.accept(proj.issues['0002'])
assertTrue f.accept(proj.issues['0003']) assertFalse f.accept(proj.issues['0003'])
} }
@Test void testProjectFilter() { @Test void testProjectFilter() {

View File

@ -1,6 +1,8 @@
package com.jdbernard.pit package com.jdbernard.pit
public class MockIssue extends Issue { public class MockIssue extends Issue {
public MockIssue(String id, Category c, int p) { super (id, c, p) } public MockIssue(String id, Category c, Status s, int p) {
super (id, c, s, p)
}
public boolean delete() { return true } public boolean delete() { return true }
} }

View File

@ -0,0 +1,54 @@
package com.jdbernard.pit
import org.junit.Test
import static org.junit.Assert.assertEquals
import static com.jdbernard.pit.Status.toStatus
public class StatusTest {
@Test void testToStatus() {
assertEquals Status.REASSIGNED, toStatus('REASSIGNED')
assertEquals Status.REJECTED, toStatus('REJECTED')
assertEquals Status.NEW, toStatus('NEW')
assertEquals Status.RESOLVED , toStatus('RESOLVED')
assertEquals Status.VALIDATION_REQUIRED,
toStatus('VALIDATION_REQUIRED')
assertEquals Status.REASSIGNED, toStatus('REA')
assertEquals Status.REJECTED, toStatus('REJ')
assertEquals Status.NEW, toStatus('NEW')
assertEquals Status.RESOLVED , toStatus('RES')
assertEquals Status.VALIDATION_REQUIRED,
toStatus('VAL')
assertEquals Status.REASSIGNED, toStatus('reassigned')
assertEquals Status.REJECTED, toStatus('rejected')
assertEquals Status.NEW, toStatus('new')
assertEquals Status.RESOLVED , toStatus('resolved')
assertEquals Status.VALIDATION_REQUIRED,
toStatus('validation_required')
assertEquals Status.REASSIGNED, toStatus('rea')
assertEquals Status.REJECTED, toStatus('rej')
assertEquals Status.NEW, toStatus('new')
assertEquals Status.RESOLVED , toStatus('res')
assertEquals Status.VALIDATION_REQUIRED,
toStatus('val')
assertEquals Status.REASSIGNED, toStatus('A')
assertEquals Status.REJECTED, toStatus('J')
assertEquals Status.NEW, toStatus('N')
assertEquals Status.RESOLVED , toStatus('S')
assertEquals Status.VALIDATION_REQUIRED, toStatus('V')
assertEquals Status.REASSIGNED, toStatus('a')
assertEquals Status.REJECTED, toStatus('j')
assertEquals Status.NEW, toStatus('n')
assertEquals Status.RESOLVED , toStatus('s')
assertEquals Status.VALIDATION_REQUIRED, toStatus('v')
}
}

Binary file not shown.

BIN
pit-cli/lib/pit-2.0.1.jar Normal file

Binary file not shown.

View File

@ -1,9 +1,9 @@
#Thu Feb 25 17:41:36 CST 2010 #Fri Feb 26 11:46:27 CST 2010
build.dir=build build.dir=build
src.dir=src src.dir=src
build.jar=pit-cli-${application.version}.${build.number}.jar build.jar=pit-cli-${application.version}.${build.number}.jar
build.number=1 build.number=2
expected.application.version=1.1.8 expected.application.version=2.0.1
lib.dir=lib lib.dir=lib
release.dir=release release.dir=release
release.jar=pit-cli-${application.version}.jar release.jar=pit-cli-${application.version}.jar

View File

@ -11,8 +11,11 @@ cli.l(longOpt: 'list', 'List issues. Unless otherwise specified it lists all '
cli.i(argName: 'id', longOpt: 'id', args: 1, cli.i(argName: 'id', longOpt: 'id', args: 1,
'Filter issues by id. Accepts a comma-delimited list.') 'Filter issues by id. Accepts a comma-delimited list.')
cli.c(argName: 'category', longOpt: 'category', args: 1, cli.c(argName: 'category', longOpt: 'category', args: 1,
'Filter issues by category (bug, feature, task, closed). Accepts a ' 'Filter issues by category (bug, feature, task). Accepts a '
+ 'comma-delimited list.') + 'comma-delimited list.')
cli.t(argName: 'status', longOpt: 'status', args: 1,
'Filter issues by status (new, reassigned, rejected, resolved, ' +
'validation_required)')
cli.p(argName: 'priority', longOpt: 'priority', args: 1, cli.p(argName: 'priority', longOpt: 'priority', args: 1,
'Filter issues by priority. This acts as a threshhold, listing all issues ' 'Filter issues by priority. This acts as a threshhold, listing all issues '
+ 'greater than or equal to the given priority.') + 'greater than or equal to the given priority.')
@ -26,6 +29,8 @@ cli.P(argName: 'new-priority', longOpt: 'set-priority', args: 1,
required: false, 'Modify the priority of the selected issues.') required: false, 'Modify the priority of the selected issues.')
cli.C(argName: 'new-category', longOpt: 'set-category', args: 1, cli.C(argName: 'new-category', longOpt: 'set-category', args: 1,
required: false, 'Modify the category of the selected issues.') required: false, 'Modify the category of the selected issues.')
cli.T(argName: 'new-status', longOpt: 'set-status', args: 1,
required: false, 'Modify the status of the selected issues.')
cli.n(longOpt: 'new-issue', 'Create a new issue.') cli.n(longOpt: 'new-issue', 'Create a new issue.')
def opts = cli.parse(args) def opts = cli.parse(args)
@ -39,6 +44,10 @@ def categories = ['bug','feature','task']
if (opts.c) categories = opts.c.split(/[,\s]/) if (opts.c) categories = opts.c.split(/[,\s]/)
categories = categories.collect { Category.toCategory(it) } categories = categories.collect { Category.toCategory(it) }
def statusList = ['new', 'validation_required']
if (opts.t) statusList = opts.t.split(/[,\s]/)
statusList = statusList.collect { Status.toStatus(it) }
def EOL = System.getProperty('line.separator') def EOL = System.getProperty('line.separator')
// build issue list // build issue list
@ -46,6 +55,7 @@ issuedb = new FileProject(new File('.'))
// build filter from options // build filter from options
def filter = new Filter('categories': categories, def filter = new Filter('categories': categories,
'status': statusList,
'priority': (opts.p ? opts.p.toInteger() : 9), 'priority': (opts.p ? opts.p.toInteger() : 9),
'projects': (opts.r ? opts.r.toLowerCase().split(/[,\s]/).asType(List.class) : []), 'projects': (opts.r ? opts.r.toLowerCase().split(/[,\s]/).asType(List.class) : []),
'ids': (opts.i ? opts.i.split(/[,\s]/).asType(List.class) : []), 'ids': (opts.i ? opts.i.split(/[,\s]/).asType(List.class) : []),
@ -88,7 +98,15 @@ else if (opts.C) {
try { cat = Category.toCategory(opts.C) } try { cat = Category.toCategory(opts.C) }
catch (e) { println "Invalid category: ${opts.C}"; return 1 } catch (e) { println "Invalid category: ${opts.C}"; return 1 }
walkProject(issuedb, filterb) { it.category = cat } walkProject(issuedb, filter) { it.category = cat }
}
// change status fourth
else if (opts.T) {
def status
try { status = Status.toStatus(opts.T) }
catch (e) { println "Invalid status: ${opts.T}"; return 1 }
walkProject(issuedb, filter) { it.status = status }
} }
// new entry last // new entry last
else if (opts.n) { else if (opts.n) {

BIN
pit-swing/CHANGE ME Normal file

Binary file not shown.

View File

@ -1,4 +1,4 @@
#Sat Feb 13 08:41:16 CST 2010 #Sat Feb 13 08:41:16 CST 2010
app.version=1.1.8 app.version=2.0.1
app.griffon.version=0.2.1 app.griffon.version=0.2.1
app.name=pit-swing app.name=pit-swing

View File

@ -8,7 +8,6 @@ class PITController {
def view def view
void mvcGroupInit(Map args) { void mvcGroupInit(Map args) {
model.rootProject = new FileProject(new File('.'))
} }
/* /*

Binary file not shown.

Before

Width:  |  Height:  |  Size: 537 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 559 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

View File

@ -1,12 +1,14 @@
package com.jdbernard.pit.swing package com.jdbernard.pit.swing
import com.jdbernard.pit.Category import com.jdbernard.pit.Category
import com.jdbernard.pit.Status
import com.jdbernard.pit.Filter 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 groovy.beans.Bindable
import java.awt.GridBagConstraints as GBC import java.awt.GridBagConstraints as GBC
import java.awt.Font
import java.awt.Point import java.awt.Point
import java.awt.event.MouseEvent import java.awt.event.MouseEvent
import javax.swing.DefaultComboBoxModel import javax.swing.DefaultComboBoxModel
@ -33,8 +35,11 @@ projectListModels = [:]
// map of category -> list icon // map of category -> list icon
categoryIcons = [:] categoryIcons = [:]
statusIcons = [:]
// filter for projects and issues // filter for projects and issues
filter = new Filter(categories: []) filter = new Filter(categories: [],
status: [Status.NEW, Status.VALIDATION_REQUIRED])
popupProject = null popupProject = null
selectedProject = model.rootProject selectedProject = model.rootProject
@ -47,6 +52,10 @@ Category.values().each {
filter.categories.add(it) filter.categories.add(it)
} }
Status.values().each {
statusIcons[(it)] = imageIcon("/${it.name().toLowerCase()}.png")
}
/* *************** /* ***************
* event methods * event methods
* ***************/ * ***************/
@ -111,23 +120,32 @@ newIssueDialog = dialog(title: 'New Task...', modal: true, pack: true,//size: [3
fill: GBC.HORIZONTAL), fill: GBC.HORIZONTAL),
model: new DefaultComboBoxModel(Category.values())) model: new DefaultComboBoxModel(Category.values()))
label('Priority (0-9, 0 is highest priority):', label('Status:',
constraints: gbc(gridx: 0, gridy: 3, insets: [5, 5, 0, 0], constraints: gbc(gridx: 0, gridy: 3, insets: [5, 5, 0, 0],
fill: GBC.HORIZONTAL)) fill: GBC.HORIZONTAL))
statusComboBox = comboBox(
constraints: gbc(gridx: 1, gridy: 3, insets: [5, 5, 0, 5],
fill: GBC.HORIZONTAL),
model: new DefaultComboBoxModel(Status.values()))
label('Priority (0-9, 0 is highest priority):',
constraints: gbc(gridx: 0, gridy: 4, insets: [5, 5, 0, 0],
fill: GBC.HORIZONTAL))
prioritySpinner = spinner( prioritySpinner = spinner(
constraints: gbc( gridx: 1, gridy: 3, insets: [5, 5, 0, 5], constraints: gbc( gridx: 1, gridy: 4, insets: [5, 5, 0, 5],
fill: GBC.HORIZONTAL), fill: GBC.HORIZONTAL),
model: spinnerNumberModel(maximum: 9, minimum: 0)) model: spinnerNumberModel(maximum: 9, minimum: 0))
button('Cancel', actionPerformed: { newIssueDialog.visible = false }, button('Cancel', actionPerformed: { newIssueDialog.visible = false },
constraints: gbc(gridx: 0, gridy: 4, insets: [5, 5, 5, 5], constraints: gbc(gridx: 0, gridy: 5, insets: [5, 5, 5, 5],
anchor: GBC.EAST)) anchor: GBC.EAST))
button('Create Issue', button('Create Issue',
constraints: gbc(gridx: 1, gridy: 4, insets: [5, 5, 5, 5], constraints: gbc(gridx: 1, gridy: 5, insets: [5, 5, 5, 5],
anchor: GBC.WEST), anchor: GBC.WEST),
actionPerformed: { actionPerformed: {
def issue = selectedProject.createNewIssue( def issue = selectedProject.createNewIssue(
category: categoryComboBox.selectedItem, category: categoryComboBox.selectedItem,
status: statusComboBox.selectedItem,
priority: prioritySpinner.value, priority: prioritySpinner.value,
text: titleTextField.text) text: titleTextField.text)
projectListModels[(selectedProject.name)] = null projectListModels[(selectedProject.name)] = null
@ -160,7 +178,13 @@ projectPopupMenu = popupMenu() {
issuePopupMenu = popupMenu() { issuePopupMenu = popupMenu() {
menuItem('New Issue...', menuItem('New Issue...',
actionPerformed: { newIssueDialog.visible = true }) actionPerformed: {
titleTextField.text = ""
categoryComboBox.selectedIndex = 0
statusComboBox.selectedIndex = 0
prioritySpinner.setValue(5)
newIssueDialog.visible = true
})
menuItem('Delete Issue', menuItem('Delete Issue',
actionPerformed: { actionPerformed: {
@ -180,6 +204,20 @@ issuePopupMenu = popupMenu() {
if (!popupIssue) return if (!popupIssue) return
popupIssue.category = category popupIssue.category = category
issueList.invalidate() issueList.invalidate()
issueList.repaint()
})
}
}
menu('Change Status') {
Status.values().each { status ->
menuItem(status.toString(),
icon: statusIcons[(status)],
actionPerformed: {
if (!popupIssue) return
popupIssue.status = status
issueList.invalidate()
issueList.repaint()
}) })
} }
} }
@ -198,12 +236,13 @@ issuePopupMenu = popupMenu() {
return return
} }
issueList.invalidate() issueList.invalidate()
issueList.repaint()
}) })
} }
frame = application(title:'Personal Issue Tracker', frame = application(title:'Personal Issue Tracker',
locationRelativeTo: null, locationRelativeTo: null,
minimumSize: [600, 400], minimumSize: [800, 500],
//size:[320,480], //size:[320,480],
pack:true, pack:true,
//location:[50,50], //location:[50,50],
@ -231,6 +270,7 @@ frame = application(title:'Personal Issue Tracker',
} }
menu('View') { menu('View') {
menu('Category') {
Category.values().each { Category.values().each {
checkBoxMenuItem(it.toString(), checkBoxMenuItem(it.toString(),
selected: filter.categories.contains(it), selected: filter.categories.contains(it),
@ -247,6 +287,26 @@ frame = application(title:'Personal Issue Tracker',
displayProject(selectedProject) displayProject(selectedProject)
}) })
} }
}
menu('Status') {
Status.values().each {
checkBoxMenuItem(it.toString(),
selected: filter.status.contains(it),
actionPerformed: { evt ->
def st = Status.toStatus(evt.source.text[0..5])
if (filter.status.contains(st)) {
filter.status.remove(st)
evt.source.selected = false
} else {
filter.status.add(st)
evt.source.selected = true
}
projectListModels.clear()
displayProject(selectedProject)
})
}
}
} }
} }
@ -266,7 +326,10 @@ frame = application(title:'Personal Issue Tracker',
if (model.rootProject) { if (model.rootProject) {
projectTree.rootVisible = model.rootProject.issues.size() projectTree.rootVisible = model.rootProject.issues.size()
new DefaultTreeModel(makeNodes(model.rootProject)) new DefaultTreeModel(makeNodes(model.rootProject))
} else new DefaultTreeModel() } else {
projectTree.rootVisible = false
new DefaultTreeModel(new DefaultMutableTreeNode())
}
}), }),
valueChanged: { evt -> valueChanged: { evt ->
selectedProject = evt?.newLeadSelectionPath?.lastPathComponent?.userObject ?: model.rootProject selectedProject = evt?.newLeadSelectionPath?.lastPathComponent?.userObject ?: model.rootProject
@ -280,6 +343,8 @@ frame = application(title:'Personal Issue Tracker',
evt.x, evt.y) evt.x, evt.y)
} }
}) })
projectTree.model = new DefaultTreeModel(new DefaultMutableTreeNode())
projectTree.rootVisible = false
projectTree.selectionModel.selectionMode = projectTree.selectionModel.selectionMode =
TreeSelectionModel.SINGLE_TREE_SELECTION TreeSelectionModel.SINGLE_TREE_SELECTION
@ -292,7 +357,8 @@ frame = application(title:'Personal Issue Tracker',
scrollPane(constraints: "top") { scrollPane(constraints: "top") {
issueList = list( issueList = list(
cellRenderer: new IssueListCellRenderer( cellRenderer: new IssueListCellRenderer(
issueIcons: categoryIcons), categoryIcons: categoryIcons,
statusIcons: statusIcons),
selectionMode: ListSelectionModel.SINGLE_SELECTION, selectionMode: ListSelectionModel.SINGLE_SELECTION,
valueChanged: { displayIssue(issueList.selectedValue) }, valueChanged: { displayIssue(issueList.selectedValue) },
mouseClicked: { evt -> mouseClicked: { evt ->
@ -306,7 +372,19 @@ frame = application(title:'Personal Issue Tracker',
}) })
} }
scrollPane(constraints: "bottom") { scrollPane(constraints: "bottom") {
issueTextArea = textArea() issueTextArea = textArea(
font: new Font(Font.MONOSPACED, Font.PLAIN, 12),
focusGained: {},
focusLost: {
if (!issueList?.selectedValue) return
if (issueTextArea.text != issueList.selectedValue.text)
issueList.selectedValue.text = issueTextArea.text
},
mouseExited: {
if (!issueList?.selectedValue) return
if (issueTextArea.text != issueList.selectedValue.text)
issueList.selectedValue.text = issueTextArea.text
})
} }
} }
} }

Binary file not shown.

BIN
pit-swing/lib/pit-2.0.1.jar Normal file

Binary file not shown.

View File

@ -0,0 +1,60 @@
package com.jdbernard.pit.swing
import java.awt.Component
import java.awt.Graphics
import javax.swing.Icon
/**
* This class provides a composite icon. A composite icon
* draws its parts one on the other, all aligned to the
* left top corner. The size of the compsite icon is the
* max size of its parts.
*
*/
public class CompositeIcon implements Icon {
List<Icon> icons
/**
* Construct a composite icon.
*
* @param i The parts.
*/
public CompositeIcon(List<Icon> i) { icons = i; }
/**
* Draw the icon at the specified location. Icon implementations
* may use the Component argument to get properties useful for
* painting, e.g. the foreground or background color.
*
* @param c The component to take attributes from.
* @param g The graphics port to draw into.
* @param x The x drawing coordinate.
* @param y The y drawing coordinate.
*/
public void paintIcon(Component c, Graphics g, int x, int y) {
icons.each { it.paintIcon(c, g, x, y) }
}
/**
* Returns the icon's width.
*
* @return an int specifying the fixed width of the icon.
*/
public int getIconWidth() {
int width = 0;
icons.each { width = Math.max(width, it.iconWidth) }
return width;
}
/**
* Returns the icon's height.
*
* @return an int specifying the fixed height of the icon.
*/
public int getIconHeight() {
int height = 0;
icons.each { height = Math.max(height, it.iconHeight) }
return height;
}
}

View File

@ -1,5 +1,7 @@
package com.jdbernard.pit.swing package com.jdbernard.pit.swing
import com.jdbernard.pit.Category
import com.jdbernard.pit.Status
import java.awt.Component import java.awt.Component
import javax.swing.Icon import javax.swing.Icon
import javax.swing.JList import javax.swing.JList
@ -7,14 +9,23 @@ import javax.swing.DefaultListCellRenderer
public class IssueListCellRenderer extends DefaultListCellRenderer { public class IssueListCellRenderer extends DefaultListCellRenderer {
Map<Category, Icon> issueIcons Map<Category, Icon> categoryIcons
Map<Status, Icon> statusIcons
public Component getListCellRendererComponent(JList list, Object value, public Component getListCellRendererComponent(JList list, Object value,
int index, boolean selected, boolean hasFocus) { int index, boolean selected, boolean hasFocus) {
def component = super.getListCellRendererComponent(list, value, index, def component = super.getListCellRendererComponent(list, value, index,
selected, hasFocus) selected, hasFocus)
if (issueIcons[(value.category)]) def icon
component.setIcon(issueIcons[(value.category)]) if (categoryIcons[(value.category)]) {
icon = categoryIcons[(value.category)]
if (statusIcons[(value.status)])
icon = new CompositeIcon([icon, statusIcons[(value.status)]])
}
if (icon) setIcon(icon)
component.text = "<html><tt>${value.id} (${value.priority}): </tt>" + component.text = "<html><tt>${value.id} (${value.priority}): </tt>" +
"${value.title}</html>" "${value.title}</html>"
return component return component

0
pit-swing/stacktrace.log Normal file
View File

Binary file not shown.

BIN
release/lib/pit-2.0.1.jar Normal file

Binary file not shown.

BIN
release/pit-swing-2.0.1.jar Normal file

Binary file not shown.

View File

@ -1 +1 @@
application.version=1.1.8 application.version=2.0.1