Source code: org/mitre/cvw/DetailList.java
1 /*
2 * Copyright (c) 1996-2000. The MITRE Corporation (http://www.mitre.org/).
3 * All rights reserved.
4 * CVW comes with ABSOLUTELY NO WARRANTY. See license for details.
5 */
6
7 package org.mitre.cvw;
8
9 import javax.swing.*;
10 import javax.swing.event.*;
11 import javax.swing.table.*;
12 import java.awt.*;
13 import java.awt.event.*;
14 import java.util.*;
15
16 import java.awt.dnd.*;
17 import java.awt.datatransfer.*;
18
19 /**
20 * This is the gui widget which displays the contents of the room and all
21 * folders.
22 * @version 1.2
23 * @author Dee Goepel
24 * @author Stephen Jones
25 */
26 public class DetailList extends JPanel implements ObjectValues, Observer, DropTargetListener {
27 // class variable declarations
28 private final int[] initialSize = {80,10,7,9,7,9}; //1/19/98 dage
29 //private final int[] initialSize = {15,10,7,9,7,9}; //1/19/98 dage
30 private final String[] titles = {"Name", "Type", "Created", "Originator", "Modified", "Modified By"};
31
32 public final static int NO_MENU = -1;
33
34 // DetailObject[] contents, new_contents;
35 MultiListData contents;
36 int total, curMenu = NO_MENU, menuHeight = 4, currentSort = 0;
37 MultiList listPanel;
38 int[] types = {USER, DOC, URL, NOTE, PROXY, FOLDER, RECORDER, WHITEBOARD, UNKNOWN};
39 ObjectMenu menu;
40 String dropOrTake = "take"; // can be "drop" or "take"
41 JPanel headingPanel;
42 JLabel headingLabel, sizeLabel;
43 JLabel docServIcon = null;
44 Point menuPt;
45
46 /**
47 * Constructor
48 * @param cvwObj
49 * @param dOT
50 * @param title2
51 */
52 DetailList(CVWObject[] cvwObj, String dOT, String title2) {
53 setLayout(new BorderLayout());
54 setSize(1000, 1000);
55
56 dropOrTake = dOT;
57
58 // make and fill panels for content
59 //System.err.println("heading is "+title2);
60 headingPanel = new JPanel();
61 headingPanel.setLayout(new BorderLayout());
62
63 if (title2.equals("null"))
64 headingLabel = new JLabel(" ");
65 else
66 headingLabel = new JLabel(" "+title2);
67
68 //Font f = getFont();
69 //if (f != null)
70 //headingLabel.setFont(new Font(f.getName(), Font.BOLD, f.getSize()));
71 //else
72 headingLabel.setFont(headingLabel.getFont().deriveFont(Font.BOLD));
73 headingPanel.add("Center",headingLabel);
74
75 Image image = ContentsCoordinator.getDocServIcon();
76 docServIcon = new JLabel(new ImageIcon(image), JLabel.RIGHT);
77 docServIcon.setSize(9,14);
78 JPanel rightPanel = new JPanel(new GridLayout(0, 2, 5, 0));
79 sizeLabel = new JLabel();
80 setSizeLabel(cvwObj.length);
81 rightPanel.add(docServIcon);
82 rightPanel.add(sizeLabel);
83 headingPanel.add("East",rightPanel);
84
85 contents = new MultiListData(cvwObj.length);
86 listPanel = new MultiList(contents, (dropOrTake.equals("drop")));
87 listPanel.setWidths(initialSize);
88 listPanel.setPanelBackground(getBackground());
89 listPanel.getTable().addMouseListener(new MouseAdapter() {
90 public void mousePressed(MouseEvent e) {
91 if (SwingUtilities.isRightMouseButton(e)) {
92 Point pt = e.getPoint();
93 int rowClicked = listPanel.getTable().rowAtPoint(pt);
94 listPanel.select(rowClicked);
95 showMenu(pt.x, pt.y, rowClicked);
96 } else if (SwingUtilities.isLeftMouseButton(e) &&
97 e.getClickCount() == 2) { // double click. Do a Get Info..
98 Point pt = e.getPoint();
99 int row = listPanel.getTable().rowAtPoint(pt);
100 openSelectedObject(row);
101 }
102 }
103 });
104
105 listPanel.getTable().getTableHeader().addMouseListener(new MouseAdapter() {
106 public void mouseClicked(MouseEvent e) {
107 TableColumnModel columnModel = listPanel.getTable().getColumnModel();
108 int viewColumn = columnModel.getColumnIndexAtX(e.getX());
109 int column = listPanel.getTable().convertColumnIndexToModel(viewColumn);
110 if (column != -1) {
111 //System.out.println("Sorting column..." + column);
112 sortContentsBy(column);
113 }
114 }
115 });
116
117 initDetailList(cvwObj);
118
119 // place components
120 add("North", headingPanel);
121 add("Center", listPanel.getScrollTable());
122 doLayout();
123 headingPanel.doLayout();
124 showDocServIcon(false);
125 }
126
127 /**
128 * Scrolls the detail list to the top.
129 */
130 public void goToTop() {
131 if (listPanel != null)
132 listPanel.makeVisible(0);
133 }
134
135 /** Initializes the list with the objects passed into the constructor
136 *
137 * @param cvwObj An array of CVWObjects
138 */
139 protected void initDetailList(CVWObject[] cvwObj) {
140 total = cvwObj.length;
141 listPanel.setSortableTitle(titles);
142
143 setSizeLabel(total);
144 if (total == 0) return;
145
146 for (int i = 0; i < total; i++)
147 contents.addObject(new DetailObject(cvwObj[i], this));
148
149 doSort(contents,currentSort);
150
151 }
152
153 public void setSizeLabel(int size) {
154 if (size == 1)
155 sizeLabel.setText(size + " item ");
156 else
157 sizeLabel.setText(size + " items ");
158 }
159
160 /**
161 * Updates the detail list with a new array of CVWObjects.
162 * Removes any previous contents the array might have.
163 *
164 * @param cvwObj a new array of CVWObjects
165 */
166 public void updateDetailList(CVWObject[] cvwObj) {
167 int temp;
168 //System.err.println("udl:oldTotal " + total + "newTotal " + cvwObj.length);
169 // remove old observers
170 for (int i = 0; i < contents.length(); i++)
171 contents.getObject(i).deleteObserver();
172
173 // class variable assignments
174 int newtotal = cvwObj.length;
175 clearContents();
176
177 setSizeLabel(newtotal);
178
179 if (newtotal == 0) {
180 return;
181 }
182
183 for (int a = 0; a < newtotal; a++) {
184 contents.addObject(new DetailObject(cvwObj[a],this));
185 }
186
187 //System.err.println("done creating");
188 temp = currentSort;
189 currentSort = NO_MENU;
190
191 total = newtotal;
192 try {
193 sortContentsBy(temp);
194 } catch (Exception e) {
195 currentSort = temp;
196 }
197
198 }
199
200 /* 8/26/98 dage - broke this method into much smaller methods
201 sortBy, doSort, updateLists, resetHilights
202 */
203 /**
204 * Sorts the current array of CVWObjects by the specified field, remembering which
205 * object is highlighted before the new sort, so as to high light the same object
206 * after the sort.
207 * @param field the field to sort by
208 */
209 public void sortContentsBy(int field) {
210 int start = listPanel.getVisible();
211 int hilight = listPanel.getSelectedRow();
212 CVWObject select = getSelectedObject();
213
214 if (sortBy(field)) {
215 currentSort = field;
216 resetHilights(hilight, start, select);
217 }
218 //System.err.println("done sorting");
219 }
220
221 /**
222 * Sorts the array of CVWObjects by the field specified, but first sorts alphabetically
223 * by name, so that always by name.
224 * @param field the field to sort by
225 * @return whether the sort actually happened (if user clicked on field already
226 * sorted by, just abort
227 */
228 public boolean sortBy(int field) {
229 boolean sorted = true;
230 CVWObjNum selectobj=null;
231 DetailObject next;
232
233 //contents = new_contents;
234 // at this point the objects on screen are different than those actually
235 // stored, the displayed objects are updated immediately following the sort
236
237 // Do the actual sorting of our contents array
238 // if (currentSort==field) {
239 // sorted = false;
240 // } else {
241
242 // sort alphabetically always
243 // then sort again if name is not our primary sort field
244 /* 5/27/98 dage - name field is 0
245 */
246 //doSort(contents, 0);
247
248 //System.err.println("done 1st sort");
249 /* 5/27/98 dage - replace each repetive field type with a single loop and sent
250 * the field value as a parameter to compareTo function
251 */
252 //if (field != 0)
253 doSort(contents, field);
254
255 //System.err.println("done 2nd sort");
256 return sorted;
257 }
258
259 /**
260 * Performs the sort, given an array of DetailObjects and a field.
261 * @param detailArray the object to be sorted
262 * @param field the field to do the sort on
263 */
264 public void doSort(MultiListData detailArray, int field) {
265 int i, j, h;
266 DetailObject vObj, jhObj;
267 String vString, jhString;
268 boolean stillGreaterThan;
269 int size = detailArray.length();
270
271 int hSize;
272 if (size<10)
273 hSize = size-1;
274 else
275 hSize = (size-1)/9;
276 //System.err.println("hSize" + hSize);
277 for (h=1; h<=hSize; h = (3*h+1));
278 do {
279 h /=3;
280 for(i=h; i<size; i++) {
281 vObj = detailArray.getObject(i);
282 j = i;
283 stillGreaterThan = true;
284 while (j >= h && stillGreaterThan) {
285 jhObj = detailArray.getObject(j-h);
286 if (jhObj.compareTo(vObj, field) > 0) {
287 detailArray.setObjectAt(jhObj, j); //rows.setElementAt(jhObj, j);
288 j -= h;
289 }
290 else
291 stillGreaterThan = false;
292 } //end while
293 detailArray.setObjectAt(vObj, j); // rows.setElementAt(vObj, j);
294 } //end for
295 } while (h > 0);
296 detailArray.dataUpdated();
297 //System.err.println("done sort");
298 }
299
300 /**
301 * Resets the scroll position
302 * if something was selected, reselect it
303 * if it's no longer there don't select anything
304 * if nothing was selected, return us to the same row number
305 * @param hilight
306 * @param start
307 * @param selectobj
308 */
309 public void resetHilights(int hilight, int start, CVWObject selectobj) {
310 if (hilight < 0) {
311 // nothing was highlighted
312 if (start < total)
313 listPanel.makeVisible(start);
314 } else {
315 // try to reselect
316 int a;
317 for (a=0;a<total;a++) {
318 if (selectobj.equals(contents.getObject(a).getCVWObject())) {
319 listPanel.select(a);
320 listPanel.makeVisible(a);
321 break;
322 }
323 }
324 if (a == total) {
325 // the selected object is no longer there
326 listPanel.select(-1); // deselect
327 if (hilight < total) {
328 listPanel.makeVisible(hilight);
329 } else {
330 listPanel.makeVisible(total);
331 }
332 }
333 }
334
335 }
336
337 /**
338 * Refreshes the layouts of the different gui panels.
339 */
340 public void doLayouts() {
341 doLayout();
342 headingPanel.doLayout();
343 }
344
345 /**
346 * Notifies this detail list of when the right mouse selection finished
347 * painting so that the right mouse menu can be shown. No longer used.
348 * @param ob an instance of MultiListWatcher
349 * @param arg "done painting"
350 */
351 public void update(Observable ob, Object arg) {
352 }
353
354 /**
355 * Makes the appropriate right mouse menu visible.
356 * @param x the x coordinate
357 * @param y the y coordinate
358 * @param row the row selected
359 */
360 public void showMenu(int x, int y, int row) {
361 int displayX = x+5, displayY=y-12;
362 int mtype = contents.getObject(row).menuType; // rows start at 1, objects start at 0!
363
364 if ((row >= 0) && (row < total)) {
365 if ((mtype == 89) || (mtype == PROXY)) // 89 is a randomly chosen number to
366 return; // denote lack of menu
367
368 int drop_or_take = (dropOrTake.equals("drop")) ? DROP : TAKE;
369
370 if (menu != null) { // remove previous menu
371 try {
372 //remove(menu);
373 }
374 catch (NullPointerException npe) {
375 System.err.println("menu no longer exists");
376 }
377 }
378
379 CVWObject obj = contents.getObject(row).getCVWObject();
380 if (mtype == GROUP) {
381 menu = ObjectMenuControl.getMenu(mtype, obj, drop_or_take);
382 } else if (mtype == RECORDER) {
383 /* 9/23/98 dage - dot is really whether the recorder is currently on or off
384 */
385 int state = (obj.name.indexOf("OFF")< 0) ? 1 : 0;
386 menu = ObjectMenuControl.getMenu(mtype, obj, state);
387 } else {
388 menu = ObjectMenuControl.getMenu(mtype, obj, drop_or_take);
389 }
390 //add(menu);
391
392 // see what needs to be grayed out, if anything
393 int menu_mask = 0;
394 if (drop_or_take == DROP &&
395 ((menu instanceof DocMenu) || (menu instanceof DocWBMenu)) &&
396 !(menu instanceof DocSCMenu)) {
397 // this is a doc in carrying folder
398 CVWDocument doc = (CVWDocument)obj; // should be a document
399 if (doc.isCheckedOut()) {
400 menu_mask = menu.getGrayoutMask(CHECKEDOUTDOC);
401 } else {
402 menu_mask = menu.getGrayoutMask(NOTCHECKEDOUTDOC);
403 }
404 }
405 if (menu != null)
406 menu.show(listPanel.getTable(), menu_mask, displayX, displayY);
407
408 }
409 }
410
411 /**
412 * Updates the contents of the list.
413 */
414 public void updateContents() {
415 contents.dataUpdated();
416 }
417
418 /**
419 * Clears the contents ofthe room.
420 */
421 public void clearContents() {
422 contents.clear();
423 }
424
425 /**
426 * Updates the label of this detail list, can be a room name or folder name change.
427 * @param roomName the new name
428 */
429 public void updateHeading(String roomName) { //called when a room change occurs
430 headingLabel.setText(roomName);
431 headingPanel.doLayout();
432 doLayout();
433 goToTop(); // scroll to the top on change of room
434 }
435
436 /**
437 * Shows/Hides the doc server communication icon.
438 * @param b whether to show or hide the icon
439 */
440 public void showDocServIcon(boolean b) {
441 if (docServIcon == null)
442 return;
443 docServIcon.setVisible(b);
444 docServIcon.repaint();
445 doLayout();
446 headingPanel.doLayout();
447 }
448
449 public boolean openSelectedObject(int row) {
450 DetailObject dob = contents.getObject(row);
451 if (row >= contents.length()) return false;
452 if (dob.menuType == 89) return false; // 89 == no menu
453
454 if (dob.menuType == 88 || dob.menuType == FORMFOLDER) {
455 CVWCoordinator.getInstance().displayError(CVWCoordinator.findFrame(this),
456 "\"" + dob.getName()
457 + "\", which is of type "
458 + dob.getType()
459 + ", can not be opened in this version of CVW.");
460 return false;
461 }
462 if (dob.menuType == PROXY)
463 return false;
464 dob.getCVWObject().startOpen();
465 return true;
466 }
467
468
469 /**
470 * Returns the CVWObject represented by the selected row.
471 * @return the CVWObject selected
472 */
473 public CVWObject getSelectedObject() {
474 int row = listPanel.getSelectedRow();
475 if (row == -1)
476 return null;
477 if (row >= contents.length())
478 return null;
479 return contents.getObject(row).getCVWObject();
480 }
481
482 /**
483 * Returns the CVWObject represented by the selected row and y coordinate, returns
484 * <code>null</code> if y and selected row DO NOT match.
485 * @param y the y coordinate
486 * @return the CVWObject selected
487 */
488 public CVWObject getSelectedObject(int y) {
489 int row = listPanel.getSelectedRow();
490 int row2 = listPanel.getRowIndex(y);
491 row2--;
492 if (row != row2)
493 return null;
494 if (row == -1)
495 return null;
496 if (row >= contents.length())
497 return null;
498 //System.err.println(contents.length);
499 return contents.getObject(row).getCVWObject();
500 }
501
502 // DropTargetListener methods
503 public void dragEnter(DropTargetDragEvent dtde) {
504 if (dtde.isDataFlavorSupported(DetailObjectTransferable.OBJECT_FLAVOR)) {
505 dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
506 } else
507 dtde.rejectDrag();
508 }
509
510 public void dropActionChanged(DropTargetDragEvent dtde) {}
511 public void dragExit(DropTargetEvent dte) {}
512
513 public void dragOver(DropTargetDragEvent dtde) {
514 if (!(dtde.getDropTargetContext().getComponent() instanceof JTable)) {
515 listPanel.select(-1);
516 return;
517 }
518 int row = listPanel.getRowIndex(dtde.getLocation().y);
519 if (row < 0 || row >= contents.length()) {
520 listPanel.select(-1);
521 return;
522 }
523 CVWObject cvwObj = contents.getObject(row).getCVWObject();
524 if (cvwObj != null && cvwObj instanceof CVWFolder)
525 listPanel.select(row);
526 else
527 listPanel.select(-1);
528 }
529
530 public void drop(DropTargetDropEvent dtde) {
531 try {
532 if (dtde.isLocalTransfer()) {
533 Transferable tr = dtde.getTransferable();
534 DataFlavor objFlavor = DetailObjectTransferable.OBJECT_FLAVOR;
535 if (tr.isDataFlavorSupported(objFlavor)) {
536 dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
537 CVWObject dropObject = (CVWObject)tr.getTransferData(objFlavor);
538
539 //get target object, current selection if folder,
540 //current folder window, current user or current room.
541 CVWObject target = null;
542
543 if (dtde.getDropTargetContext().getComponent() instanceof JTable) {
544 int row = listPanel.getRowIndex(dtde.getLocation().y);
545 if (row > -1) {
546 CVWObject cvwObj = contents.getObject(row).getCVWObject();
547 if (cvwObj != null && cvwObj instanceof CVWFolder)
548 target = cvwObj;
549 }
550 }
551 if (target == null)
552 target = getDropLocation();
553 dropObject.moveObject(target);
554 dtde.getDropTargetContext().dropComplete(true);
555 }
556 }
557
558 else {
559 int action = dtde.getSourceActions();
560 System.err.println("hey, you dropped something! action = " + action);
561 dtde.rejectDrop();
562 }
563 }
564 catch (Exception e) {
565 System.err.println("Error during drop: " + e);
566 dtde.rejectDrop();
567 }
568 }
569
570 /**
571 * Sets the drop target listener for this detail list to itself.
572 */
573 public void setDropTargetListener() {
574 listPanel.setDropTarget((DropTargetListener)this);
575 new DropTarget(headingLabel, this);
576 }
577
578 /**
579 * Returns the container for this detail list. If the frame is CVWCoordinator
580 * then current room is assumed. If frame is a CVWFolderWindow, then the
581 * CVWFolder the window represents, which could be the current user.
582 */
583 public CVWObject getDropLocation() {
584 JFrame frame = CVWCoordinator.findFrame(this);
585 if (frame instanceof CVWCoordinator)
586 return CVWCoordinator.getInstance().getCurrentRoom();
587
588 if (frame instanceof CVWFolderWindow) {
589 return ((CVWFolderWindow)frame).getCVWFolder();
590 }
591
592 return null; //should never get here
593 }
594
595 }
596
597