Skip to content

Commit bda8981

Browse files
ctruedenclaude
andcommitted
Show each task's log from the task monitor
Each row of the task table gains a log icon, which opens a window showing the output logged to the task's Logger from that moment on. The window stays open after the task finishes, until closed. This requires scijava-common's new Task#log(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent dcbc72f commit bda8981

2 files changed

Lines changed: 83 additions & 20 deletions

File tree

‎pom.xml‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@
113113
<jdatepicker.version>1.3.2</jdatepicker.version>
114114
<object-inspector.version>0.1</object-inspector.version>
115115

116-
<scijava-common.version>2.100.0</scijava-common.version>
116+
<!-- TEMP: for Task#log(); drop once propagated to pom-scijava. -->
117+
<scijava-common.version>2.101.0</scijava-common.version>
117118
</properties>
118119

119120
<repositories>

‎src/main/java/org/scijava/ui/swing/task/SwingTaskMonitorComponent.java‎

Lines changed: 81 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@
3131
import net.miginfocom.swing.MigLayout;
3232
import org.scijava.Context;
3333
import org.scijava.event.EventHandler;
34+
import org.scijava.log.Logger;
3435
import org.scijava.task.Task;
3536
import org.scijava.task.event.TaskEvent;
37+
import org.scijava.ui.swing.console.LoggingPanel;
3638

3739
import javax.swing.JComponent;
3840
import javax.swing.JFrame;
@@ -58,6 +60,8 @@
5860
import java.awt.Shape;
5961
import java.awt.event.MouseAdapter;
6062
import java.awt.event.MouseEvent;
63+
import java.awt.event.WindowAdapter;
64+
import java.awt.event.WindowEvent;
6165
import java.awt.geom.Arc2D;
6266
import java.awt.geom.Area;
6367
import java.awt.geom.Ellipse2D;
@@ -95,6 +99,14 @@
9599
* Second column:
96100
* </p>
97101
* <ul>
102+
* <li>a log icon, clickable and which opens a window showing the output
103+
* logged to the displayed task's {@link Task#log() logger} from then
104+
* on</li>
105+
* </ul>
106+
* <p>
107+
* Third column:
108+
* </p>
109+
* <ul>
98110
* <li>a stop icon, clickable and which calls {@link Task#cancel(String)} for
99111
* the displayed task</li>
100112
* </ul>
@@ -109,6 +121,17 @@
109121

110122
public class SwingTaskMonitorComponent {
111123

124+
/** Column of the {@link #taskTable} with the log icon. */
125+
private static final int LOG_COLUMN = 1;
126+
127+
/** Column of the {@link #taskTable} with the stop icon. */
128+
private static final int STOP_COLUMN = 2;
129+
130+
private final Context context;
131+
132+
/** Open log windows, by task. Accessed from the event dispatch thread only. */
133+
private final Map<Task, JFrame> logFrames = new HashMap<>();
134+
112135
/**
113136
* Progress bar showing the global progression ( = progression of all tasks ).
114137
* Clicking it toggles taskFrame visibility.
@@ -169,6 +192,7 @@ public SwingTaskMonitorComponent(final Context context,
169192
int size,
170193
boolean undecorated) {
171194
context.inject(this); // register event handler (this#onEvent)
195+
this.context = context;
172196

173197
this.sizeGlobalProgressBar = size;
174198
this.confirmBeforeCancel = confirmBeforeCancel;
@@ -210,8 +234,9 @@ public void mouseClicked(MouseEvent e) {
210234
taskTable.setTableHeader(null); // no header
211235
taskTable.setRowMargin(2);
212236
taskTable.setDefaultRenderer(Task.class, new TaskRenderer(false));
213-
// restrict size of second column to the size of the stop icon
214-
taskTable.getColumnModel().getColumn(1).setMaxWidth(30);
237+
// restrict size of icon columns to the size of the icons
238+
taskTable.getColumnModel().getColumn(LOG_COLUMN).setMaxWidth(30);
239+
taskTable.getColumnModel().getColumn(STOP_COLUMN).setMaxWidth(30);
215240

216241
// Scroll pane containing the JTable -> necessary when many tasks are displayed
217242
JScrollPane scrollPane = new JScrollPane(taskTable);
@@ -222,13 +247,17 @@ public void mouseClicked(MouseEvent e) {
222247
scrollPane.setColumnHeaderView(null);
223248
taskFrame.pack();
224249

225-
// enable canceling when the user clicks on the second column (of index 1)
250+
// show the log or cancel when the user clicks on the corresponding icon
226251
taskTable.addMouseListener(new java.awt.event.MouseAdapter() {
227252
@Override
228253
public void mouseClicked(java.awt.event.MouseEvent evt) {
229254
int row = taskTable.rowAtPoint(evt.getPoint());
230255
int col = taskTable.columnAtPoint(evt.getPoint());
231-
if (row >= 0 && col == 1) {
256+
if (row >= 0 && col == LOG_COLUMN) {
257+
Task selectedTask = taskTableModel.getTask(row);
258+
if (selectedTask != null) showLog(selectedTask);
259+
}
260+
if (row >= 0 && col == STOP_COLUMN) {
232261
Task selectedTask = taskTableModel.getTask(row);
233262
if (selectedTask!=null) {
234263
if (SwingTaskMonitorComponent.this.confirmBeforeCancel) {
@@ -274,6 +303,37 @@ private void onEvent(final TaskEvent evt) {
274303
globalProgressBar.setValue((int)(globalProgression*100));
275304
}
276305

306+
/**
307+
* Shows a window with the output logged to the given task's logger. The
308+
* window shows output from the moment it is first opened, and remains
309+
* available after the task finishes, until closed.
310+
*/
311+
private void showLog(final Task task) {
312+
JFrame frame = logFrames.get(task);
313+
if (frame == null) {
314+
final LoggingPanel panel = new LoggingPanel(context);
315+
panel.setSourcesPanelVisible(false);
316+
final Logger logger = task.log();
317+
logger.addLogListener(panel);
318+
final JFrame logFrame = new JFrame("Log: " + task.getName());
319+
logFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
320+
logFrame.add(panel);
321+
logFrame.setSize(640, 400);
322+
logFrame.setLocationRelativeTo(taskFrame);
323+
logFrame.addWindowListener(new WindowAdapter() {
324+
@Override
325+
public void windowClosed(WindowEvent e) {
326+
logger.removeLogListener(panel);
327+
logFrames.remove(task);
328+
}
329+
});
330+
logFrames.put(task, logFrame);
331+
frame = logFrame;
332+
}
333+
frame.setVisible(true);
334+
frame.toFront();
335+
}
336+
277337
/**
278338
* User confirmation required when canceling a task by clicking the task table.
279339
*/
@@ -388,25 +448,22 @@ public synchronized int getRowCount() {
388448

389449
@Override
390450
public int getColumnCount() {
391-
return 2;
451+
return 3;
392452
}
393453

394454
@Override
395455
public String getColumnName(int columnIndex) {
396456
switch (columnIndex) {
397457
case 0: return "Task";
398-
case 1: return "Stop";
458+
case LOG_COLUMN: return "Log";
459+
case STOP_COLUMN: return "Stop";
399460
}
400461
return null;
401462
}
402463

403464
@Override
404465
public Class<?> getColumnClass(int columnIndex) {
405-
switch (columnIndex) {
406-
case 0: return Task.class;
407-
case 1: return Task.class;
408-
}
409-
return null;
466+
return columnIndex >= 0 && columnIndex < getColumnCount() ? Task.class : null;
410467
}
411468

412469
@Override
@@ -416,12 +473,8 @@ public boolean isCellEditable(int rowIndex, int columnIndex) {
416473

417474
@Override
418475
public Object getValueAt(int rowIndex, int columnIndex) {
419-
if (rowIndex<monitoredTasks.size()) {
420-
Task task = monitoredTasks.get(rowIndex);
421-
switch (columnIndex) {
422-
case 0: return task;
423-
case 1: return task;
424-
}
476+
if (rowIndex<monitoredTasks.size() && getColumnClass(columnIndex) != null) {
477+
return monitoredTasks.get(rowIndex);
425478
}
426479
return null;
427480
}
@@ -488,6 +541,7 @@ class TaskRenderer implements TableCellRenderer {
488541
JLabel labelTop = new JLabel(); // top label : task name and status
489542
JProgressBar progressBar = new JProgressBar(); // standard linear progress bar
490543
JLabel labelBottom = new JLabel(); // bottom label : task completion, and optionally time left
544+
JLabel showLog; // log icon
491545
JLabel cancelTask; // cancel icon
492546

493547
public TaskRenderer(boolean isBordered) {
@@ -501,6 +555,9 @@ public TaskRenderer(boolean isBordered) {
501555
cell.add(labelTop,"height ::14, span");
502556
cell.add(progressBar,"height ::3, span");
503557
cell.add(labelBottom, "height ::14");
558+
showLog = new JLabel("\u2261", SwingConstants.CENTER);
559+
showLog.setOpaque(true);
560+
showLog.setToolTipText("Show log");
504561
cancelTask = new JLabel("\u2715", SwingConstants.CENTER);
505562
cancelTask.setOpaque(true);
506563
}
@@ -515,10 +572,15 @@ public Component getTableCellRendererComponent(
515572
cell.setForeground(table.getForeground());
516573
labelTop.setForeground(table.getForeground());
517574
labelBottom.setForeground(table.getForeground());
575+
showLog.setBackground(table.getBackground());
576+
showLog.setForeground(table.getForeground());
518577
cancelTask.setBackground(table.getBackground());
519578
cancelTask.setForeground(table.getForeground());
520-
if (column==1) {
521-
return cancelTask; // second column : stop icon
579+
if (column == LOG_COLUMN) {
580+
return showLog;
581+
}
582+
if (column == STOP_COLUMN) {
583+
return cancelTask;
522584
}
523585
// first column : task information
524586
Task task = (Task) tk;

0 commit comments

Comments
 (0)