1 package ini
.trakem2
.display
;
3 import ini
.trakem2
.utils
.Bureaucrat
;
4 import ini
.trakem2
.utils
.IJError
;
5 import ini
.trakem2
.utils
.Utils
;
6 import ini
.trakem2
.utils
.Worker
;
8 import java
.awt
.Dimension
;
9 import java
.awt
.event
.ActionEvent
;
10 import java
.awt
.event
.ActionListener
;
11 import java
.awt
.event
.MouseAdapter
;
12 import java
.awt
.event
.MouseEvent
;
13 import java
.awt
.event
.WindowAdapter
;
14 import java
.awt
.event
.WindowEvent
;
15 import java
.util
.ArrayList
;
16 import java
.util
.Collection
;
17 import java
.util
.Collections
;
18 import java
.util
.Comparator
;
19 import java
.util
.HashMap
;
20 import java
.util
.Iterator
;
21 import java
.util
.List
;
25 import javax
.swing
.JFrame
;
26 import javax
.swing
.JMenuItem
;
27 import javax
.swing
.JPopupMenu
;
28 import javax
.swing
.JScrollPane
;
29 import javax
.swing
.JTabbedPane
;
30 import javax
.swing
.JTable
;
31 import javax
.swing
.SwingUtilities
;
32 import javax
.swing
.table
.AbstractTableModel
;
34 /** List all connectors whose origins intersect with the given tree. */
35 public class TreeConnectorsView
{
37 static private Map
<Tree
<?
>,TreeConnectorsView
> open
= Collections
.synchronizedMap(new HashMap
<Tree
<?
>,TreeConnectorsView
>());
40 private TargetsTableModel outgoing_model
= new TargetsTableModel(),
41 incoming_model
= new TargetsTableModel();
44 public TreeConnectorsView(final Tree
<?
> tree
) {
51 static public Bureaucrat
create(final Tree
<?
> tree
) {
52 return Bureaucrat
.createAndStart(new Worker
.Task("Opening connectors table") {
54 TreeConnectorsView tcv
= open
.get(tree
);
57 tcv
.frame
.setVisible(true);
60 // Create and store in the Map of 'open'
61 new TreeConnectorsView(tree
);
64 }, tree
.getProject());
67 static public void dispose(final Tree
<?
> tree
) {
68 TreeConnectorsView tcv
= open
.remove(tree
);
69 if (null == tcv
) return;
73 static private final Comparator
<Displayable
> IDSorter
= new Comparator
<Displayable
>() {
75 public int compare(Displayable o1
, Displayable o2
) {
76 if (o1
.getId() < o1
.getId()) return -1;
82 final Connector connector
;
84 final ArrayList
<Displayable
> origins
, targets
;
85 String originids
, targetids
;
86 Row(final Connector c
, final int i
, final ArrayList
<Displayable
> origins
, final ArrayList
<Displayable
> targets
) {
89 this.origins
= origins
;
90 this.targets
= targets
;
91 for (final Iterator
<Displayable
> it
= this.targets
.iterator(); it
.hasNext(); ) {
92 if (it
.next().getClass() == Connector
.class) {
97 final Coordinate
<Node
<Float
>> getCoordinate(int col
) {
101 return connector
.getCoordinateAtOrigin();
103 return connector
.getCoordinate(i
);
105 Utils
.log2("Can't deal with column " + col
);
109 private final long getFirstId(final ArrayList
<Displayable
> c
) {
113 return c
.get(0).getId();
115 final long getColumn(final int col
) {
118 return connector
.getId();
120 return getFirstId(origins
);
122 return getFirstId(targets
);
124 Utils
.log2("Don't know how to deal with column " + col
);
128 private final String
getIds(String ids
, final ArrayList
<Displayable
> ds
) {
135 ids
= ds
.get(0).toString();
138 final StringBuilder sb
= new StringBuilder();
139 for (final Displayable d
: ds
) {
140 sb
.append(d
).append(',').append(' ');
142 sb
.setLength(sb
.length() -2);
149 final String
getTargetIds() {
150 targetids
= getIds(targetids
, targets
);
153 final String
getOriginIds() {
154 originids
= getIds(originids
, origins
);
159 public void update() {
160 // Find all Connector instances intersecting with the nodes of Tree
162 final Collection
<Connector
>[] connectors
= this.tree
.findConnectors();
163 outgoing_model
.setData(connectors
[0]);
164 incoming_model
.setData(connectors
[1]);
165 } catch (Exception e
) {
170 private void addTab(JTabbedPane tabs
, String title
, TargetsTableModel model
) {
171 JTable table
= new Table();
172 table
.setModel(model
);
173 JScrollPane jsp
= new JScrollPane(table
);
174 jsp
.setPreferredSize(new Dimension(500, 500));
175 tabs
.addTab(title
, jsp
);
178 private void createGUI() {
179 this.frame
= new JFrame("Connectors for Tree #" + this.tree
.getId());
180 frame
.addWindowListener(new WindowAdapter() {
181 public void windowClosing(WindowEvent we
) {
185 JTabbedPane tabs
= new JTabbedPane();
186 addTab(tabs
, "Outgoing", outgoing_model
);
187 addTab(tabs
, "Incoming", incoming_model
);
188 frame
.getContentPane().add(tabs
);
190 frame
.setVisible(true);
193 private class Table
extends JTable
{
194 private static final long serialVersionUID
= 1L;
197 getTableHeader().addMouseListener(new MouseAdapter() {
198 public void mouseClicked(MouseEvent me
) {
199 if (2 != me
.getClickCount()) return;
200 int viewColumn
= getColumnModel().getColumnIndexAtX(me
.getX());
201 int column
= convertColumnIndexToModel(viewColumn
);
202 if (-1 == column
) return;
203 ((TargetsTableModel
)getModel()).sortByColumn(column
, me
.isShiftDown());
206 addMouseListener(new MouseAdapter() {
207 public void mousePressed(MouseEvent me
) {
208 final int row
= Table
.this.rowAtPoint(me
.getPoint());
209 final int col
= Table
.this.columnAtPoint(me
.getPoint());
210 if (2 == me
.getClickCount()) {
212 } else if (Utils
.isPopupTrigger(me
)) {
213 JPopupMenu popup
= new JPopupMenu();
214 final JMenuItem go
= new JMenuItem("Go"); popup
.add(go
);
215 final JMenuItem goandsel
= new JMenuItem("Go and select"); popup
.add(go
);
216 final JMenuItem update
= new JMenuItem("Update"); popup
.add(update
);
217 ActionListener listener
= new ActionListener() {
218 public void actionPerformed(ActionEvent ae
) {
219 final Object src
= ae
.getSource();
220 if (src
== go
) go(col
, row
);
221 else if (src
== goandsel
) {
223 if (0 != (ae
.getModifiers() ^ ActionEvent
.SHIFT_MASK
)) Display
.getFront().getSelection().clear();
224 TargetsTableModel ttm
= (TargetsTableModel
)getModel();
225 Display
.getFront().getSelection().add(ttm
.rows
.get(row
).connector
);
226 } else if (src
== update
) {
227 Bureaucrat
.createAndStart(new Worker
.Task("Updating...") {
229 TreeConnectorsView
.this.update();
231 }, TreeConnectorsView
.this.tree
.getProject());
235 go
.addActionListener(listener
);
236 goandsel
.addActionListener(listener
);
237 update
.addActionListener(listener
);
238 popup
.show(Table
.this, me
.getX(), me
.getY());
243 void go(int col
, int row
) {
244 TargetsTableModel ttm
= (TargetsTableModel
)getModel();
245 Display
.centerAt(ttm
.rows
.get(row
).getCoordinate(col
));
249 private class TargetsTableModel
extends AbstractTableModel
{
250 private static final long serialVersionUID
= 1L;
251 List
<Row
> rows
= null;
253 synchronized public void setData(final Collection
<Connector
> connectors
) {
254 this.rows
= new ArrayList
<Row
>(connectors
.size());
255 for (final Connector c
: connectors
) {
257 final ArrayList
<Displayable
> origins
= new ArrayList
<Displayable
>(c
.getOrigins(VectorData
.class, true));
258 Collections
.sort(origins
, IDSorter
);
259 for (final Set
<Displayable
> targets
: c
.getTargets(VectorData
.class, true)) {
260 final ArrayList
<Displayable
> ts
= new ArrayList
<Displayable
>(targets
);
261 Collections
.sort(ts
, IDSorter
);
262 this.rows
.add(new Row(c
, i
++, origins
, ts
));
265 SwingUtilities
.invokeLater(new Runnable() {public void run() {
266 fireTableDataChanged();
267 fireTableStructureChanged();
271 public int getColumnCount() { return 3; }
272 public String
getColumnName(final int col
) {
274 case 0: return "Connector id";
275 case 1: return "Origin id";
276 case 2: return "Target id";
277 default: return null;
280 public int getRowCount() { return rows
.size(); }
281 public Object
getValueAt(final int row
, final int col
) {
283 case 0: return rows
.get(row
).connector
.getId();
284 case 1: return rows
.get(row
).getOriginIds();
285 case 2: return rows
.get(row
).getTargetIds();
286 default: return null;
289 public boolean isCellEditable(int row
, int col
) { return false; }
290 public void setValueAt(Object value
, int row
, int col
) {}
291 final void sortByColumn(final int col
, final boolean descending
) {
292 final ArrayList
<Row
> rows
= new ArrayList
<Row
>(this.rows
);
293 Collections
.sort(rows
, new Comparator
<Row
>() {
294 public int compare(final Row r1
, final Row r2
) {
295 final long op
= r1
.getColumn(col
) - r2
.getColumn(col
);
297 if (op
> 0) return -1;
298 if (op
< 0) return 1;
301 if (op
< 0) return -1;
302 if (op
> 0) return 1;
306 this.rows
= rows
; // swap
307 fireTableDataChanged();
308 fireTableStructureChanged();