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 #Thu May 13 17:04:40 CDT 2010
app.griffon.version=0.3 app.griffon.version=0.3
app.name=pit-swing app.name=pit-swing
app.version=2.2.0 app.version=2.3.1
plugins.fest=0.3 plugins.fest=0.3

View File

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

View File

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

View File

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

View File

@ -10,8 +10,10 @@ import java.awt.Point
import java.awt.event.MouseEvent import java.awt.event.MouseEvent
import javax.swing.JOptionPane import javax.swing.JOptionPane
import javax.swing.JSplitPane import javax.swing.JSplitPane
import javax.swing.JTable
import javax.swing.JTextField import javax.swing.JTextField
import javax.swing.ListSelectionModel import javax.swing.ListSelectionModel
import javax.swing.table.TableCellRenderer
import javax.swing.tree.DefaultMutableTreeNode import javax.swing.tree.DefaultMutableTreeNode
import javax.swing.tree.DefaultTreeCellRenderer import javax.swing.tree.DefaultTreeCellRenderer
import javax.swing.tree.DefaultTreeModel import javax.swing.tree.DefaultTreeModel
@ -83,8 +85,14 @@ issuePopupMenu = popupMenu() {
icon: model.mainMVC.model.categoryIcons[(category)], icon: model.mainMVC.model.categoryIcons[(category)],
enabled: bind { model.popupIssue != null }, enabled: bind { model.popupIssue != null },
actionPerformed: { actionPerformed: {
model.popupIssue.category = category try {
controller.refreshIssues() 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)], icon: model.mainMVC.model.statusIcons[(status)],
enabled: bind { model.popupIssue != null }, enabled: bind { model.popupIssue != null },
actionPerformed: { actionPerformed: {
model.popupIssue.status = status try {
controller.refreshIssues() 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...', 'New priority (0-9)', 'Change Priority...',
JOptionPane.QUESTION_MESSAGE) JOptionPane.QUESTION_MESSAGE)
try { model.popupIssue.priority = newPriority.toInteger() } try { model.popupIssue.priority = newPriority.toInteger() }
catch (exception) { catch (NumberFormatException nfe) {
JOptionPane.showMessageDialog(mainMVC.view.frame, JOptionPane.showMessageDialog(mainMVC.view.frame,
'The priority value must be an integer in [0-9].', 'The priority value must be an integer in [0-9].',
'Change Priority...', JOptionPane.ERROR_MESSAGE) 'Change Priority...', JOptionPane.ERROR_MESSAGE)
return return
} catch (IOException ioe) {
JOptionPane.showMessageDialog(mainMVC.view.fraw,
ioe.getLocalizedMessage(), 'Change Priority...',
JOptionPane.ERROR_MESSAGE)
} }
controller.refreshIssues() controller.refreshIssues()
}) })
@ -188,7 +206,37 @@ panel = splitPane(orientation: JSplitPane.HORIZONTAL_SPLIT,
scrollPane(constraints: gbc(fill: GBC.BOTH, weightx: 2, scrollPane(constraints: gbc(fill: GBC.BOTH, weightx: 2,
weighty: 2, gridx: 0, gridy: 0, gridwidth: 3)) { 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, cellRenderer: model.issueCellRenderer,
selectionMode: ListSelectionModel.SINGLE_SELECTION, selectionMode: ListSelectionModel.SINGLE_SELECTION,
valueChanged: { evt -> valueChanged: { evt ->
@ -202,7 +250,7 @@ panel = splitPane(orientation: JSplitPane.HORIZONTAL_SPLIT,
controller.showIssuePopup( controller.showIssuePopup(
issueList.selectedValue, evt.x, evt.y) issueList.selectedValue, evt.x, evt.y)
} }
}) })*/
} }
wordWrapCheckBox = checkBox('Word wrap', wordWrapCheckBox = checkBox('Word wrap',
@ -213,8 +261,8 @@ panel = splitPane(orientation: JSplitPane.HORIZONTAL_SPLIT,
deleteIssueButton = button(deleteIssue, deleteIssueButton = button(deleteIssue,
constraints: gbc(gridx: 2, gridy: 1, anchor: GBC.EAST), constraints: gbc(gridx: 2, gridy: 1, anchor: GBC.EAST),
enabled: bind(source: issueList, sourceEvent: 'valueChanged', enabled: bind(source: issueTable.selectionModel, sourceEvent: 'valueChanged',
sourceValue: { issueList.selectedValue != null })) sourceValue: { !issueTable.selectionModel.isSelectionEmpty() }))
} }
@ -223,19 +271,21 @@ panel = splitPane(orientation: JSplitPane.HORIZONTAL_SPLIT,
wrapStyleWord: true, wrapStyleWord: true,
lineWrap: bind(source: wordWrapCheckBox, lineWrap: bind(source: wordWrapCheckBox,
sourceProperty: 'selected'), sourceProperty: 'selected'),
editable: bind( source: issueList, sourceEvent: 'valueChanged', editable: bind( source: issueTable.selectionModel, sourceEvent: 'valueChanged',
sourceValue: { issueList.selectedValue != null }), sourceValue: { !issueTable.selectionModel.isSelectionEmpty() }),
font: model.mainMVC.model.issueDetailFont, font: model.mainMVC.model.issueDetailFont,
focusGained: {}, focusGained: {},
focusLost: { focusLost: {
if (!issueList?.selectedValue) return def issue = controller.getSelectedIssue()
if (issueTextArea.text != issueList.selectedValue.text) if (issue == null) return
issueList.selectedValue.text = issueTextArea.text if (issueTextArea.text != issue.text)
issue.text = issueTextArea.text
}, },
mouseExited: { mouseExited: {
if (!issueList?.selectedValue) return def issue = controller.getSelectedIssue()
if (issueTextArea.text != issueList.selectedValue.text) if (issue == null) return
issueList.selectedValue.text = issueTextArea.text 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.