/*
* Copyright 2013 Hewlett-Packard Development Company, L.P
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hp.alm.ali.idea.content.devmotive;
import com.hp.alm.ali.idea.content.AliContentFactory;
import com.hp.alm.ali.idea.content.CloseableContent;
import com.hp.alm.ali.idea.entity.EntityAdapter;
import com.hp.alm.ali.idea.entity.EntityRef;
import com.hp.alm.ali.idea.model.Entity;
import com.hp.alm.ali.idea.services.DevMotiveService;
import com.hp.alm.ali.idea.services.EntityService;
import com.hp.alm.ali.idea.ui.DateSelectorLabel;
import com.hp.alm.ali.idea.ui.MultiValueSelectorLabel;
import com.hp.alm.ali.idea.util.ApplicationUtil;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ChangeList;
import com.intellij.openapi.vcs.changes.committed.RepositoryChangesBrowser;
import com.intellij.openapi.vcs.history.VcsFileRevision;
import com.intellij.openapi.vcs.history.VcsFileRevisionEx;
import com.intellij.openapi.vcs.history.VcsHistoryProvider;
import com.intellij.openapi.vcs.history.VcsHistorySession;
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
import com.intellij.openapi.vcs.vfs.VcsVirtualFile;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.JBSplitter;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.labels.LinkLabel;
import com.intellij.ui.components.labels.LinkListener;
import com.intellij.ui.table.JBTable;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.text.DateFormatUtil;
import com.intellij.util.ui.ComponentWithEmptyText;
import com.intellij.util.ui.UIUtil;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class DevMotivePanel extends JPanel implements CloseableContent, LinkListener, ChangeListener, HyperlinkListener, DevMotive {
private static final int REVISION_BATCH_SIZE = 100;
private final Project project;
private final VirtualFile file;
private final String vcsName;
private final DevMotiveService devMotiveService;
private final EntityService entityService;
private final IncompleteWarningPanel incompleteWarningPanel;
private final List<ChangeListener> listeners;
private JPanel filterPanel;
private MultiValueSelectorLabel userSelector;
private DateSelectorLabel dateSelector;
private Object filterId = new Object();
private Object selectId = new Object();
private JTable workItemsTable;
private WorkItemsTableModel workItemsTableModel;
private JTable commitsTable;
private CommitsTableModel commitsTableModel;
private String emptyText;
private RepositoryChangesBrowser fileChanges;
private Map<VcsRevisionNumber, List<Change>> vcsCache;
private Map<EntityRef, WorkItem> workItemMap;
private MultiMap<WorkItem, Commit> workItemToCommits;
private MultiMap<Commit, WorkItem> commitToWorkItems;
private LinkedHashMap<VcsRevisionNumber, Commit> allCommits;
private List<Commit> filteredCommits;
private Set<Commit> processedCommits;
private Set<Commit> processingCommits;
public DevMotivePanel(final Project project, final VirtualFile file, List<VcsFileRevision> revisions, String vcsName) {
super(new BorderLayout());
this.project = project;
this.file = file;
this.vcsName = vcsName;
listeners = new LinkedList<ChangeListener>();
devMotiveService = project.getComponent(DevMotiveService.class);
entityService = project.getComponent(EntityService.class);
workItemToCommits = new MultiMap<WorkItem, Commit>();
commitToWorkItems = new MultiMap<Commit, WorkItem>();
workItemMap = new HashMap<EntityRef, WorkItem>();
vcsCache = new HashMap<VcsRevisionNumber, List<Change>>();
commitsTableModel = new CommitsTableModel();
commitsTable = new JBTable(commitsTableModel);
commitsTable.setDefaultRenderer(Date.class, new DateRenderer());
commitsTable.setAutoCreateRowSorter(true);
commitsTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
setColumn(commitsTable, 0, 150, true);
setColumn(commitsTable, 1, 250, true);
setColumn(commitsTable, 2, 1000, false);
commitsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
List<VcsRevisionNumber> selectedRevisions = new LinkedList<VcsRevisionNumber>();
ListSelectionModel selectionModel = commitsTable.getSelectionModel();
if (!selectionModel.isSelectionEmpty()) {
for (int i = selectionModel.getMinSelectionIndex(); i <= selectionModel.getMaxSelectionIndex(); i++) {
boolean selected = selectionModel.isSelectedIndex(i);
if (selected) {
Commit commit = commitsTableModel.getCommit(i);
selectedRevisions.add(commit.getRevisionNumber());
}
}
}
showRevisions(selectedRevisions);
}
}
});
workItemsTableModel = new WorkItemsTableModel();
workItemsTable = new JBTable(workItemsTableModel);
// TODO: show detail action into toolbar
workItemsTable.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() > 1) {
int selectedRow = workItemsTable.getSelectedRow();
if (selectedRow >= 0) {
int idx = workItemsTable.convertRowIndexToModel(selectedRow);
WorkItem workItem = workItemsTableModel.getWorkItem(idx);
if (workItem.getType() != WorkItem.Type.NONE) {
EntityRef entityRef = workItem.toEntityRef();
AliContentFactory.loadDetail(project, entityRef.toEntity(), true, true);
}
}
}
}
});
workItemsTable.setDefaultRenderer(WorkItem.class, new WorkItemRenderer());
workItemsTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
setColumn(workItemsTable, 0, 75, true);
setColumn(workItemsTable, 1, 75, true);
setColumn(workItemsTable, 2, 1000, false);
workItemsTable.setAutoCreateRowSorter(true);
workItemsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
for (int i = 0; i < workItemsTableModel.getRowCount(); i++) {
WorkItem workItem = workItemsTableModel.getWorkItem(i);
List<Commit> filteredCommits = new LinkedList<Commit>();
filterCommits(workItemToCommits.get(workItem), filteredCommits, null);
boolean selected = workItemsTable.getSelectionModel().isSelectedIndex(i);
if (selected) {
commitsTableModel.add(filteredCommits);
} else {
commitsTableModel.remove(filteredCommits);
}
}
}
}
});
fileChanges = new RepositoryChangesBrowser(project, Collections.<CommittedChangeList>emptyList());
emptyText = ((ComponentWithEmptyText) fileChanges.getViewer().getPreferredFocusedComponent()).getEmptyText().getText();
incompleteWarningPanel = new IncompleteWarningPanel(getBackground());
incompleteWarningPanel.addHyperLinkListener(this);
filterPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
JPanel statusAndFilter = new JPanel(new BorderLayout());
statusAndFilter.add(incompleteWarningPanel, BorderLayout.NORTH);
statusAndFilter.add(filterPanel, BorderLayout.SOUTH);
JPanel upPanel = new JPanel(new BorderLayout());
upPanel.add(statusAndFilter, BorderLayout.NORTH);
upPanel.add(new JBScrollPane(workItemsTable), BorderLayout.CENTER);
JBSplitter upAndDown = new JBSplitter(true);
upAndDown.setFirstComponent(upPanel);
upAndDown.setSecondComponent(new JBScrollPane(commitsTable));
JBSplitter leftAndRight = new JBSplitter(false);
leftAndRight.setFirstComponent(upAndDown);
leftAndRight.setSecondComponent(fileChanges);
add(leftAndRight, BorderLayout.CENTER);
filteredCommits = new ArrayList<Commit>();
allCommits = new LinkedHashMap<VcsRevisionNumber, Commit>();
processedCommits = new HashSet<Commit>();
processingCommits = new HashSet<Commit>();
if (revisions == null) {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
public void run() {
List<VcsFileRevision> revisions = loadRevisions();
if (revisions != null) {
initializeRevisions(revisions);
} else {
incompleteWarningPanel.markFailed();
}
}
});
} else {
initializeRevisions(revisions);
}
}
private void showRevisions(final List<VcsRevisionNumber> selectedRevisions) {
ApplicationManager.getApplication().assertIsDispatchThread();
final Object selectId = new Object();
this.selectId = selectId;
fileChanges.setChangesToDisplay(Collections.<Change>emptyList());
fileChanges.getViewer().setEmptyText("Loading...");
ApplicationUtil.executeOnPooledThread(new Runnable() {
@Override
public void run() {
final List<Change> allChanges = new LinkedList<Change>();
for (VcsRevisionNumber revisionNumber: selectedRevisions) {
List<Change> changes = getChangeList(revisionNumber);
allChanges.addAll(changes);
}
ApplicationUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
if (selectId.equals(DevMotivePanel.this.selectId)) {
fileChanges.setChangesToDisplay(allChanges);
fileChanges.getViewer().setEmptyText(emptyText);
}
}
});
}
});
}
public String getName() {
String name = "Dev: " + file.getName();
if (file instanceof VcsVirtualFile) {
return name + "(+)";
} else {
return name;
}
}
private List<Change> getChangeList(VcsRevisionNumber revisionNumber) {
List<Change> changes = vcsCache.get(revisionNumber);
if (changes == null) {
try {
changes = new LinkedList<Change>();
AbstractVcs vcs = ProjectLevelVcsManager.getInstance(project).getVcsFor(file);
if (vcs == null) { // VcsVirtualFile
vcs = ProjectLevelVcsManager.getInstance(project).findVcsByName(vcsName);
}
Pair oneList = vcs.getCommittedChangesProvider().getOneList(file, revisionNumber);
changes.addAll(((ChangeList) oneList.getFirst()).getChanges());
} catch (VcsException ex) {
}
vcsCache.put(revisionNumber, changes);
}
return changes;
}
private void filterCommits(Collection<Commit> commits, List<Commit> filtered, List<Commit> unfiltered) {
HashSet<String> users = new HashSet<String>(userSelector.getSelectedValues());
Long lowerBound = dateSelector.getLowerBound();
Long upperBound = dateSelector.getUpperBound();
for (Commit commit: commits) {
if (!revisionMatches(commit.getRevision(), users)) {
if (unfiltered != null) {
unfiltered.add(commit);
}
continue;
}
if (lowerBound != null && commit.getDate().getTime() < lowerBound) {
if (unfiltered != null) {
unfiltered.add(commit);
}
continue;
}
if (upperBound != null && commit.getDate().getTime() > upperBound) {
if (unfiltered != null) {
unfiltered.add(commit);
}
continue;
}
filtered.add(commit);
}
}
private synchronized void applyFilter() {
filterId = new Object();
filteredCommits.clear();
filterCommits(allCommits.values(), filteredCommits, null);
for (WorkItem workItem: workItemToCommits.keySet()) {
Collection<Commit> commits = workItemToCommits.getModifiable(workItem);
LinkedList<Commit> matched = new LinkedList<Commit>();
LinkedList<Commit> unmatched = new LinkedList<Commit>();
filterCommits(commits, matched, unmatched);
if (!matched.isEmpty()) {
// work item should be visible, some commits may no longer apply though
addWorkItem(workItem, matched, unmatched);
} else {
// work item is filtered out, remove all commits from the table
workItemsTableModel.removeWorkItem(workItem);
commitsTableModel.remove(commits);
}
}
int processed = countProcessed();
incompleteWarningPanel.setState(processed, filteredCommits.size());
if (processed < REVISION_BATCH_SIZE && filteredCommits.size() > processed) {
loadNext();
}
}
private void addWorkItem(WorkItem workItem, Commit commit) {
addWorkItem(workItem, Arrays.asList(commit), Collections.<Commit>emptyList());
}
private void addWorkItem(WorkItem workItem, Collection<Commit> matched, Collection<Commit> unmatched) {
int idx = workItemsTableModel.addWorkItem(workItem);
int row = workItemsTable.convertRowIndexToView(idx);
if (workItemsTable.getSelectionModel().isSelectedIndex(row)) {
// and it is selected
commitsTableModel.add(matched);
commitsTableModel.remove(unmatched);
}
}
private boolean revisionMatches(VcsFileRevision revision, Set<String> selectedUsers) {
if (!selectedUsers.isEmpty() && !selectedUsers.contains(revision.getAuthor())) {
return false;
}
return true;
}
private void setColumn(JTable table, int index, int width, boolean setMinimum) {
table.getColumnModel().getColumn(index).setPreferredWidth(width);
if (setMinimum) {
table.getColumnModel().getColumn(index).setMinWidth(width);
}
}
private void initializeRevisions(List<VcsFileRevision> revisions) {
for (VcsFileRevision revision: revisions) {
allCommits.put(revision.getRevisionNumber(), revisionToCommit(revision));
}
filteredCommits.addAll(allCommits.values());
final Set<String> users = new HashSet<String>();
if (!filteredCommits.isEmpty()) {
for (Commit commit: filteredCommits) {
users.add(commit.getAuthorName());
}
handleNextBatch();
}
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
initFilterPanel(users);
}
});
}
private List<VcsFileRevision> loadRevisions() {
try {
AbstractVcs vcs = ProjectLevelVcsManager.getInstance(project).getVcsFor(file);
if (vcs == null) {
return null;
}
VcsHistoryProvider vcsHistoryProvider = vcs.getVcsHistoryProvider();
if (vcsHistoryProvider == null) {
return null;
}
VcsHistorySession historySession = vcsHistoryProvider.createSessionFor(new FilePathImpl(file));
if (historySession == null) {
return null;
}
return historySession.getRevisionList();
} catch (VcsException e) {
return null;
}
}
private void initFilterPanel(Set<String> users) {
if (userSelector == null) {
userSelector = new MultiValueSelectorLabel(project, "Author", users, new ArrayList<String>(users));
userSelector.setMaximumWidth(20);
userSelector.addChangeListener(this);
filterPanel.add(userSelector);
dateSelector = new DateSelectorLabel(project, "Date");
dateSelector.addChangeListener(this);
filterPanel.add(dateSelector);
} else {
userSelector.addItems(users);
}
}
@Override
public void load(final List<VcsFileRevision> revisions) {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
public void run() {
handleRevisions(revisions);
}
});
}
public void handleRevisions(List<VcsFileRevision> revisions) {
List<Commit> commits = new LinkedList<Commit>();
Object filterId;
synchronized (this) {
for (VcsFileRevision revision: revisions) {
Commit commit = allCommits.get(revision.getRevisionNumber());
if (commit == null) {
commit = revisionToCommit(revision);
allCommits.put(revision.getRevisionNumber(), commit);
}
if (processedCommits.contains(commit)) {
continue;
}
if (!processingCommits.add(commit)) {
continue;
}
commits.add(commit);
if (commits.size() == REVISION_BATCH_SIZE) {
break;
}
}
filterId = this.filterId;
}
if (commits.isEmpty()) {
return;
}
Map<Commit, List<EntityRef>> result = devMotiveService.getRelatedEntities(commits);
processResult(filterId, result);
}
private Commit revisionToCommit(VcsFileRevision revision) {
String committer = null;
String committerEmail = null;
String authorEmail = null;
if (revision instanceof VcsFileRevisionEx) {
committer = ((VcsFileRevisionEx) revision).getCommitterName();
committerEmail = ((VcsFileRevisionEx) revision).getCommitterEmail();
authorEmail = ((VcsFileRevisionEx) revision).getAuthorEmail();
}
String author = revision.getAuthor();
return new Commit(
revision,
author,
authorEmail,
committer,
committerEmail);
}
private void handleNextBatch() {
List<Commit> commits = new LinkedList<Commit>();
final Object filterId;
synchronized (this) {
filterId = this.filterId;
for (Commit commit: filteredCommits) {
if (processedCommits.contains(commit)) {
continue;
}
if (!processingCommits.add(commit)) {
continue;
}
commits.add(commit);
if (commits.size() == REVISION_BATCH_SIZE) {
break;
}
}
}
if (commits.isEmpty()) {
return;
}
Map<Commit, List<EntityRef>> result = devMotiveService.getRelatedEntities(commits);
processResult(filterId, result);
}
private void processResult(final Object filterId, final Map<Commit, List<EntityRef>> result) {
if (result.isEmpty()) {
return;
}
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
synchronized (DevMotivePanel.this) {
boolean myQuery = filterId.equals(DevMotivePanel.this.filterId);
Set<String> users = new HashSet<String>();
for (Commit commit : result.keySet()) {
processedCommits.add(commit);
processingCommits.remove(commit);
users.add(commit.getAuthorName());
List<EntityRef> workItemRefs = result.get(commit);
if (workItemRefs == null) {
WorkItem unresolved = WorkItem.unresolved();
workItemToCommits.getModifiable(unresolved).add(commit);
if (myQuery) {
addWorkItem(unresolved, commit);
}
} else if (workItemRefs.isEmpty()) {
WorkItem unassigned = WorkItem.unassigned();
workItemToCommits.getModifiable(unassigned).add(commit);
if (myQuery) {
addWorkItem(unassigned, commit);
}
} else {
for (EntityRef workItemRef : workItemRefs) {
WorkItem item = workItemMap.get(workItemRef);
if (item == null) {
item = new WorkItem(workItemRef.type, workItemRef.id);
workItemMap.put(workItemRef, item);
}
workItemToCommits.getModifiable(item).add(commit);
commitToWorkItems.getModifiable(commit).add(item);
if (myQuery) {
addWorkItem(item, commit);
}
}
}
}
initFilterPanel(users);
incompleteWarningPanel.setState(countProcessed(), filteredCommits.size());
fireChangeEvent(this);
}
}
});
}
@Override
public void linkSelected(LinkLabel aSource, Object aLinkData) {
loadNext();
}
private void loadNext() {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
public void run() {
handleNextBatch();
}
});
}
@Override
public void stateChanged(ChangeEvent e) {
applyFilter();
}
private int countProcessed() {
int processed = 0;
for (Commit commit: filteredCommits) {
if (processedCommits.contains(commit)) {
++processed;
}
}
return processed;
}
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
loadNext();
}
}
public void selectRevision(VcsRevisionNumber revisionNumber) {
Collection<WorkItem> workItems = getWorkItemsByRevisionNumber(revisionNumber, true);
if (workItems != null && !workItems.isEmpty()) {
List<WorkItem> modelItems = workItemsTableModel.getWorkItems();
boolean first = true;
for (WorkItem workItem: workItems) {
int idx = modelItems.indexOf(workItem);
if (idx >= 0) {
int row = workItemsTable.convertRowIndexToView(idx);
if (first) {
workItemsTable.getSelectionModel().setSelectionInterval(row, row);
workItemsTable.scrollRectToVisible(workItemsTable.getCellRect(row, 0, true));
first = false;
} else {
workItemsTable.getSelectionModel().addSelectionInterval(row, row);
}
}
if (!WorkItem.Type.NONE.equals(workItem.getType())) {
AliContentFactory.loadDetail(project, workItem.toEntityRef().toEntity(), true, true);
}
}
}
Commit commit = allCommits.get(revisionNumber);
int idx = commitsTableModel.getCommits().indexOf(commit);
if (idx >= 0) {
int row = commitsTable.convertRowIndexToView(idx);
commitsTable.getSelectionModel().addSelectionInterval(row, row);
commitsTable.scrollRectToVisible(commitsTable.getCellRect(row, 0, true));
}
}
public void addChangeListener(ChangeListener changeListener) {
synchronized (listeners) {
listeners.add(changeListener);
}
}
public void removeChangeListener(ChangeListener changeListener) {
synchronized (listeners) {
listeners.remove(changeListener);
}
}
public Collection<WorkItem> getWorkItemsByRevisionNumber(VcsRevisionNumber revisionNumber, boolean all) {
Commit commit = allCommits.get(revisionNumber);
if (!processedCommits.contains(commit)) {
return null;
} else {
Collection<WorkItem> items = commitToWorkItems.get(commit);
if (all && items.isEmpty()) {
for (WorkItem auxItem: Arrays.asList(WorkItem.unassigned(), WorkItem.unresolved())) {
if (workItemToCommits.getModifiable(auxItem).contains(commit)) {
return Collections.singleton(auxItem);
}
}
}
return items;
}
}
private void fireChangeEvent(Object source) {
synchronized (listeners) {
for(ChangeListener listener: listeners) {
listener.stateChanged(new ChangeEvent(source));
}
}
}
@Override
public VirtualFile getFile() {
return file;
}
private static class DateRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
String dateStr = DateFormatUtil.formatPrettyDateTime((Date) value);
return super.getTableCellRendererComponent(table, dateStr, isSelected, hasFocus, row, column);
}
}
private class WorkItemRenderer extends DefaultTableCellRenderer {
public DefaultTableCellRenderer getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
final WorkItem workItem = (WorkItem) value;
String name = workItem.getName();
if (name == null) {
name = "Loading...";
workItem.setName(name);
final int modelRow = workItemsTable.convertRowIndexToModel(row);
entityService.requestCachedEntity(workItem.toEntityRef(), Arrays.asList("name"), new EntityAdapter() {
@Override
public void entityLoaded(final Entity entity, Event event) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
workItem.setName(entity.getPropertyValue("name"));
workItemsTableModel.fireTableRowsUpdated(modelRow, modelRow);
}
});
}
@Override
public void entityNotFound(EntityRef ref, boolean removed) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
workItem.setName("Error: Entity not found");
workItemsTableModel.fireTableRowsUpdated(modelRow, modelRow);
}
});
}
});
}
DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) super.getTableCellRendererComponent(table, name, isSelected, hasFocus, row, column);
if (workItem.getType() == WorkItem.Type.NONE) {
renderer.setFont(renderer.getFont().deriveFont(Font.ITALIC));
}
return renderer;
}
}
}