pit-swing 2.3.1: switched to using a table for the issue list.

This commit is contained in:
Jonathan Bernard 2010-05-21 14:25:21 -05:00
parent b7670e69f3
commit a5d01b05d2
9 changed files with 201 additions and 39 deletions

Binary file not shown.

View File

@ -2,5 +2,5 @@
#Thu May 13 17:04:40 CDT 2010
app.griffon.version=0.3
app.name=pit-swing
app.version=2.2.0
app.version=2.3.1
plugins.fest=0.3

View File

@ -13,9 +13,7 @@ class PITController {
void mvcGroupInit(Map args) {
SwingUtilities.invokeAndWait {
model.issueListRenderer = new IssueListCellRenderer()
model.issueListRenderer.categoryIcons = model.categoryIcons
model.issueListRenderer.statusIcons = model.statusIcons
model.issueListRenderer = new IssueTableCellRenderer()
def config = new File(System.getProperty('user.home'), '.pit')
config = new File(config, 'pit_swing.groovy')

View File

@ -29,14 +29,22 @@ class ProjectPanelController {
view.issueTextArea.text = ""
if (!project) return
if (!model.projectListModels[(project.name)]) {
def dlm = new DefaultListModel()
project.eachIssue(model.filter ?: model.mainMVC.model.filter)
{ dlm.addElement(it) }
model.projectListModels[(project.name)] = dlm
if (!model.projectTableModels[(project.name)]) {
def itm = new IssueTableModel(project,
model.filter ?: model.mainMVC.model.filter)
itm.categoryIcons = model.mainMVC.model.categoryIcons
itm.statusIcons = model.mainMVC.model.statusIcons
model.projectTableModels[(project.name)] = itm
}
view.issueList.setModel(model.projectListModels[(project.name)])
view.issueTable.setModel(model.projectTableModels[(project.name)])
def tcm = view.issueTable.columnModel
tcm.getColumn(0).maxWidth = 24
tcm.getColumn(1).maxWidth = 40
tcm.getColumn(2).maxWidth = 35
if (view.issueTable.model.columnCount == 5)
tcm.getColumn(4).maxWidth = 150
}
void displayIssue(Issue issue) {
@ -58,7 +66,7 @@ class ProjectPanelController {
void showIssuePopup(Issue issue, def x, def y) {
model.popupIssue = issue
view.issuePopupMenu.show(view.issueList, x, y)
view.issuePopupMenu.show(view.issueTable, x, y)
}
void refreshProject() {
@ -76,7 +84,7 @@ class ProjectPanelController {
}
void refreshIssues() {
model.projectListModels.clear()
model.projectTableModels.clear()
displayProject(model.selectedProject)
}
@ -131,7 +139,7 @@ class ProjectPanelController {
status: nidModel.status,
priority: nidModel.priority,
text: issueText)
model.projectListModels[(model.selectedProject.name)] = null
model.projectTableModels[(model.selectedProject.name)] = null
displayProject(model.selectedProject)
}
}
@ -139,20 +147,21 @@ class ProjectPanelController {
def deleteIssue = { evt ->
def issue
if (evt.source == view.deleteIssueButton)
issue = view.issueList.selectedValue
issue = getSelectedIssue()
else issue = model.popupIssue
model.selectedProject.issues.remove(issue.id)
model.projectListModels[(model.selectedProject.name)]
.removeElement(issue)
view.issueTable.model.issues.remove(issue)
issue.delete()
view.issueTable.invlidate()
}
def changeCategory = { evt ->
model.popupIssue.status = status
view.issueList.invalidate()
view.issueList.repaint()
}
def getSelectedIssue() {
if (view.issueTable.selectionModel.isSelectionEmpty())
return null
return view.issueTable.model.issues[view.issueTable.
convertRowIndexToModel(view.issueTable.selectedRow)]
}
}

View File

@ -19,7 +19,7 @@ class ProjectPanelModel {
@Bindable Issue popupIssue = null
// cache the ListModels
def projectListModels = [:]
def projectTableModels = [:]
def issueCellRenderer
// local filter for projects and issues

View File

@ -10,8 +10,10 @@ import java.awt.Point
import java.awt.event.MouseEvent
import javax.swing.JOptionPane
import javax.swing.JSplitPane
import javax.swing.JTable
import javax.swing.JTextField
import javax.swing.ListSelectionModel
import javax.swing.table.TableCellRenderer
import javax.swing.tree.DefaultMutableTreeNode
import javax.swing.tree.DefaultTreeCellRenderer
import javax.swing.tree.DefaultTreeModel
@ -83,8 +85,14 @@ issuePopupMenu = popupMenu() {
icon: model.mainMVC.model.categoryIcons[(category)],
enabled: bind { model.popupIssue != null },
actionPerformed: {
model.popupIssue.category = category
controller.refreshIssues()
try {
model.popupIssue.category = category
controller.refreshIssues()
} catch (IOException ioe) {
JOptionPane.showMessageDialog(mainMVC.view.frame,
ioe.getLocalizedMessage(), 'Change Category',
JOptionPane.ERROR_MESSAGE)
}
})
}
}
@ -95,8 +103,14 @@ issuePopupMenu = popupMenu() {
icon: model.mainMVC.model.statusIcons[(status)],
enabled: bind { model.popupIssue != null },
actionPerformed: {
model.popupIssue.status = status
controller.refreshIssues()
try {
model.popupIssue.status = status
controller.refreshIssues()
} catch (IOException ioe) {
JOptionPane.showMessageDialog(mainMVC.view.frame,
ioe.getLocalizedMessage(), 'Change Status',
JOptionPane.ERROR_MESSAGE)
}
})
}
}
@ -108,11 +122,15 @@ issuePopupMenu = popupMenu() {
'New priority (0-9)', 'Change Priority...',
JOptionPane.QUESTION_MESSAGE)
try { model.popupIssue.priority = newPriority.toInteger() }
catch (exception) {
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,
ioe.getLocalizedMessage(), 'Change Priority...',
JOptionPane.ERROR_MESSAGE)
}
controller.refreshIssues()
})
@ -188,7 +206,37 @@ panel = splitPane(orientation: JSplitPane.HORIZONTAL_SPLIT,
scrollPane(constraints: gbc(fill: GBC.BOTH, weightx: 2,
weighty: 2, gridx: 0, gridy: 0, gridwidth: 3)) {
issueList = list(
issueTable = table(
autoCreateRowSorter: true,
autoResizeMode: JTable.AUTO_RESIZE_LAST_COLUMN,
cellSelectionEnabled: false,
columnSelectionAllowed: false,
dragEnabled: false,
rowSelectionAllowed: true,
showHorizontalLines: false,
showVerticalLines: false,
mouseClicked: { evt ->
if (evt.button == MouseEvent.BUTTON3) {
def translatedPoint = evt.locationOnScreen.clone()
translatedPoint.translate(-issueTable.locationOnScreen.@x,
-issueTable.locationOnScreen.@y)
def row = issueTable.rowAtPoint(translatedPoint)
issueTable.setRowSelectionInterval(row, row)
controller.showIssuePopup(
controller.getSelectedIssue(), evt.x, evt.y)
}
})
issueTable.setDefaultRenderer(Object.class,
model.issueCellRenderer)
issueTable.selectionModel.valueChanged = { evt ->
if (evt.valueIsAdjusting) return
controller.displayIssue(controller.getSelectedIssue())
}
/*issueList = list(
cellRenderer: model.issueCellRenderer,
selectionMode: ListSelectionModel.SINGLE_SELECTION,
valueChanged: { evt ->
@ -202,7 +250,7 @@ panel = splitPane(orientation: JSplitPane.HORIZONTAL_SPLIT,
controller.showIssuePopup(
issueList.selectedValue, evt.x, evt.y)
}
})
})*/
}
wordWrapCheckBox = checkBox('Word wrap',
@ -213,8 +261,8 @@ panel = splitPane(orientation: JSplitPane.HORIZONTAL_SPLIT,
deleteIssueButton = button(deleteIssue,
constraints: gbc(gridx: 2, gridy: 1, anchor: GBC.EAST),
enabled: bind(source: issueList, sourceEvent: 'valueChanged',
sourceValue: { issueList.selectedValue != null }))
enabled: bind(source: issueTable.selectionModel, sourceEvent: 'valueChanged',
sourceValue: { !issueTable.selectionModel.isSelectionEmpty() }))
}
@ -223,19 +271,21 @@ panel = splitPane(orientation: JSplitPane.HORIZONTAL_SPLIT,
wrapStyleWord: true,
lineWrap: bind(source: wordWrapCheckBox,
sourceProperty: 'selected'),
editable: bind( source: issueList, sourceEvent: 'valueChanged',
sourceValue: { issueList.selectedValue != null }),
editable: bind( source: issueTable.selectionModel, sourceEvent: 'valueChanged',
sourceValue: { !issueTable.selectionModel.isSelectionEmpty() }),
font: model.mainMVC.model.issueDetailFont,
focusGained: {},
focusLost: {
if (!issueList?.selectedValue) return
if (issueTextArea.text != issueList.selectedValue.text)
issueList.selectedValue.text = issueTextArea.text
def issue = controller.getSelectedIssue()
if (issue == null) return
if (issueTextArea.text != issue.text)
issue.text = issueTextArea.text
},
mouseExited: {
if (!issueList?.selectedValue) return
if (issueTextArea.text != issueList.selectedValue.text)
issueList.selectedValue.text = issueTextArea.text
def issue = controller.getSelectedIssue()
if (issue == null) return
if (issueTextArea.text != issue.text)
issue.text = issueTextArea.text
})
}
}

View File

@ -0,0 +1,30 @@
package com.jdbernard.pit.swing
import java.awt.Component
import java.awt.Dimension
import javax.swing.Icon
import javax.swing.JLabel
import javax.swing.JTable
import javax.swing.table.DefaultTableCellRenderer
public class IssueTableCellRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
super.getTableCellRendererComponent(table, value, isSelected,
hasFocus, row, col)
if (value instanceof String) {
if (col > 2) {
setHorizontalAlignment(JLabel.LEADING)
} else {
setText("<html><tt>" + getText() + "</tt></html>")
setHorizontalAlignment(JLabel.TRAILING)
}
}
return this
}
}

View File

@ -0,0 +1,75 @@
package com.jdbernard.pit.swing
import com.jdbernard.pit.Filter
import com.jdbernard.pit.Issue
import com.jdbernard.pit.Project
import javax.swing.Icon
import javax.swing.table.AbstractTableModel
public class IssueTableModel extends AbstractTableModel {
def issues = []
boolean projectsVisible = false
def categoryIcons = [:]
def statusIcons = [:]
public IssueTableModel(Project p, Filter f = null) {
p.eachIssue(f) { issues << it }
}
public int getRowCount() {
return issues.size
}
public int getColumnCount() {
if (projectsVisible) return 5
else return 4
}
public Object getValueAt(int row, int column) {
if (row >= getRowCount() || column > getColumnCount())
return null
switch(column) {
case 0: return getIcon(issues[row]); break
case 1: return issues[row].id; break
case 2: return "(" + issues[row].priority + "): "; break
case 3: return issues[row].title; break
case 4: return issues[row].project.name; break
default: return "Invalid row index."; break
}
}
public Class<?> getColumnClass(int column) {
switch (column) {
case 0: return Icon.class; break
default: return String.class; break
}
}
public String getColumnName(int column) {
switch (column) {
case 0: return "C/S"; break
case 1: return "ID"; break
case 2: return "P"; break
case 3: return "Title/Summary"; break
case 4: return "Project"; break
default: return "ERR"; break
}
}
public boolean isCellEditable(int row, int col) { return false }
private Icon getIcon(Issue issue) {
def icon
if (categoryIcons[(issue.category)]) {
icon = categoryIcons[(issue.category)]
if (statusIcons[(issue.status)])
icon = new CompositeIcon([icon, statusIcons[(issue.status)]])
}
return icon
}
}

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

Binary file not shown.