Source code: nectar/reda/recordeditor/client/CMButtonPanel.java
1 /*
2 * CMButtonPanel.java
3 *
4 * Created on April 29, 2003, 3:21 PM
5 */
6
7 package nectar.reda.recordeditor.client;
8
9 import nectar.reda.client.base.ClientJFrame;
10 import java.awt.Color;
11 import javax.swing.JPanel;
12
13 /** A wrapper JPanel for RecordView panels (CMDocCompactPanel, CMNewsEditPanel, etc) that handles the edit toggle button,
14 * the delete button, and drag and drop operations.
15 *
16 * @author Kai Schutte skander@skander.com
17 */
18 public class CMButtonPanel extends JPanel {
19
20 private static final java.awt.Color highlightColor = new java.awt.Color(0,0,0);
21 private static final java.awt.Color normalColor = new java.awt.Color(204,204,204);
22 private boolean northLit = false;
23 private boolean southLit = false;
24 private ContentManagerPanel main;
25 private CMPanel panel;
26 private CMListPanel parent;
27 private java.util.ArrayList childList = new java.util.ArrayList();
28 /** edit mode toggle */
29 private boolean editMode = false;
30 private boolean expanded = false;
31
32
33 /** drag support variables */
34 private java.awt.dnd.DragSource dragSource;
35 private java.awt.dnd.DragGestureListener dgListener;
36 private java.awt.dnd.DragSourceListener dsListener;
37 private int dragAction;
38
39 /** drop support vars */
40 private java.awt.dnd.DropTarget dropTarget;
41 private java.awt.dnd.DropTargetListener dtListener;
42 private int acceptableDropActions = java.awt.dnd.DnDConstants.ACTION_MOVE | java.awt.dnd.DnDConstants.ACTION_LINK;
43
44
45 /** Creates new form CMButtonPanel
46 * @param main A link the the main ContentManagerPanel instance
47 * @param parent the CMListPanel instance that this panel is currently being displayed in
48 * @param panel the CMPanel instance that this wrapper contains.
49 */
50 public CMButtonPanel(ContentManagerPanel main, CMListPanel listParent, nectar.view.RecordView view) {
51 this.main = main;
52 this.parent = listParent;
53
54 if (view instanceof nectar.view.NewsView) {
55 this.panel = new CMNewsCompactPanel((nectar.view.NewsView)view);
56 } else if (view instanceof nectar.view.FAQView) {
57 this.panel = new CMFAQCompactPanel((nectar.view.FAQView)view);
58 } else if (view instanceof nectar.view.ForumView) {
59 this.panel = new CMForumCompactPanel((nectar.view.ForumView)view);
60 } else if (view instanceof nectar.view.CategoryView) {
61 this.panel = new CMCategoryCompactPanel((nectar.view.CategoryView)view);
62 } else if (view instanceof nectar.view.DocumentationView) {
63 this.panel = new CMDocsCompactPanel((nectar.view.DocumentationView)view);
64 }
65
66 this.panel.setCMButtonPanel(this);
67
68 initComponents();
69 this.expandButton.setBorder(new javax.swing.border.CompoundBorder(new javax.swing.border.BevelBorder(javax.swing.border.BevelBorder.RAISED), new javax.swing.border.EmptyBorder(new java.awt.Insets(1, 3, 1, 3))));
70 this.internalList.add(panel.getJPanel());
71 initDragSupport();
72 initDropSupport();
73 }
74
75 public void addChild(CMButtonPanel panel) {
76 if (!this.expandButton.isEnabled())
77 this.expandButton.setEnabled(true);
78 this.childList.add(panel);
79 if (this.expanded) {
80 internalList.add(panel);
81 internalList.validate();
82 }
83 }
84
85 public void removeChild(CMButtonPanel panel) {
86 this.childList.remove(panel);
87 if (this.expanded) {
88 internalList.remove(panel);
89 internalList.validate();
90 }
91 }
92
93 public java.util.List getChildren() {
94 return this.childList;
95 }
96
97 public nectar.view.RecordView getView() {
98 return panel.getView();
99 }
100
101
102 private void initDragSupport() {
103 this.dragAction = java.awt.dnd.DnDConstants.ACTION_MOVE;
104 this.dragSource = java.awt.dnd.DragSource.getDefaultDragSource();
105 this.dgListener = new nectar.reda.recordeditor.client.CMButtonPanel.DGListener();
106 this.dsListener = new nectar.reda.recordeditor.client.CMButtonPanel.DSListener();
107 this.dragSource.createDefaultDragGestureRecognizer(this, dragAction, dgListener);
108 }
109
110 private void initDropSupport() {
111 this.dtListener = new DTListener();
112 this.dropTarget = new java.awt.dnd.DropTarget(this, acceptableDropActions, dtListener, true);
113 }
114
115 /** This method is called from within the constructor to
116 * initialize the form.
117 * WARNING: Do NOT modify this code. The content of this method is
118 * always regenerated by the Form Editor.
119 */
120 private void initComponents() {//GEN-BEGIN:initComponents
121 treeStructPanel = new javax.swing.JPanel();
122 bodyPanel = new javax.swing.JPanel();
123 buttonPanel = new javax.swing.JPanel();
124 editButton = new javax.swing.JButton();
125 deleteButton = new javax.swing.JButton();
126 expandButton = new javax.swing.JButton();
127 internalList = new javax.swing.JPanel();
128 northSeparator = new javax.swing.JSeparator();
129 southSeparator = new javax.swing.JSeparator();
130
131 setLayout(new java.awt.BorderLayout());
132
133 treeStructPanel.setLayout(new javax.swing.BoxLayout(treeStructPanel, javax.swing.BoxLayout.Y_AXIS));
134
135 treeStructPanel.setBorder(new javax.swing.border.EmptyBorder(new java.awt.Insets(1, 1, 1, 1)));
136 add(treeStructPanel, java.awt.BorderLayout.WEST);
137
138 bodyPanel.setLayout(new java.awt.BorderLayout());
139
140 buttonPanel.setLayout(new javax.swing.BoxLayout(buttonPanel, javax.swing.BoxLayout.Y_AXIS));
141
142 buttonPanel.setBorder(new javax.swing.border.EmptyBorder(new java.awt.Insets(1, 1, 1, 1)));
143 editButton.setFont(new java.awt.Font("Dialog", 0, 10));
144 editButton.setText("edit");
145 editButton.setBorder(new javax.swing.border.CompoundBorder(new javax.swing.border.BevelBorder(javax.swing.border.BevelBorder.RAISED), new javax.swing.border.EmptyBorder(new java.awt.Insets(1, 3, 1, 3))));
146 editButton.addActionListener(new java.awt.event.ActionListener() {
147 public void actionPerformed(java.awt.event.ActionEvent evt) {
148 editButtonActionPerformed(evt);
149 }
150 });
151
152 buttonPanel.add(editButton);
153
154 deleteButton.setFont(new java.awt.Font("Dialog", 0, 10));
155 deleteButton.setText("delete");
156 deleteButton.setBorder(new javax.swing.border.CompoundBorder(new javax.swing.border.EtchedBorder(), new javax.swing.border.EmptyBorder(new java.awt.Insets(1, 3, 1, 3))));
157 deleteButton.addActionListener(new java.awt.event.ActionListener() {
158 public void actionPerformed(java.awt.event.ActionEvent evt) {
159 deleteButtonActionPerformed(evt);
160 }
161 });
162
163 buttonPanel.add(deleteButton);
164
165 expandButton.setFont(new java.awt.Font("Dialog", 0, 10));
166 expandButton.setText("expand");
167 expandButton.setBorder(new javax.swing.border.CompoundBorder(new javax.swing.border.EtchedBorder(), new javax.swing.border.EmptyBorder(new java.awt.Insets(1, 3, 1, 3))));
168 expandButton.setEnabled(false);
169 expandButton.addActionListener(new java.awt.event.ActionListener() {
170 public void actionPerformed(java.awt.event.ActionEvent evt) {
171 expandButtonActionPerformed(evt);
172 }
173 });
174
175 buttonPanel.add(expandButton);
176
177 bodyPanel.add(buttonPanel, java.awt.BorderLayout.WEST);
178
179 internalList.setLayout(new javax.swing.BoxLayout(internalList, javax.swing.BoxLayout.Y_AXIS));
180
181 bodyPanel.add(internalList, java.awt.BorderLayout.CENTER);
182
183 add(bodyPanel, java.awt.BorderLayout.CENTER);
184
185 northSeparator.setBackground(new java.awt.Color(204, 204, 204));
186 northSeparator.setForeground(new java.awt.Color(204, 204, 204));
187 northSeparator.setMinimumSize(new java.awt.Dimension(0, 2));
188 add(northSeparator, java.awt.BorderLayout.NORTH);
189
190 southSeparator.setBackground(new java.awt.Color(204, 204, 204));
191 southSeparator.setForeground(new java.awt.Color(204, 204, 204));
192 southSeparator.setMinimumSize(new java.awt.Dimension(0, 2));
193 add(southSeparator, java.awt.BorderLayout.SOUTH);
194
195 }//GEN-END:initComponents
196
197 private void expandButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_expandButtonActionPerformed
198 expandButtonToggle();
199 }//GEN-LAST:event_expandButtonActionPerformed
200
201 private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed
202 CMDeleteConfirmJDialog dialog = new CMDeleteConfirmJDialog((java.awt.Frame)this.getTopLevelAncestor(), true);
203 dialog.show();
204 if (dialog.hasBeenCancelled()) {
205 return;
206 }
207 nectar.record.Record rec = panel.getView().getRecord();
208 main.deleteRecord(rec);
209 parent.remove(this);
210 }//GEN-LAST:event_deleteButtonActionPerformed
211
212 private void editButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editButtonActionPerformed
213 editButtonToggle(false);
214 }//GEN-LAST:event_editButtonActionPerformed
215
216 private void highlightSouthBorder() {
217 if (!southLit) {
218 southSeparator.setBackground(highlightColor);
219 southSeparator.setForeground(highlightColor);
220 southLit = true;
221 }
222 if (northLit) {
223 northSeparator.setBackground(normalColor);
224 northSeparator.setForeground(normalColor);
225 northLit = false;
226 }
227 }
228
229 private void highlightNorthBorder() {
230 if (!northLit) {
231 northSeparator.setBackground(highlightColor);
232 northSeparator.setForeground(highlightColor);
233 northLit = true;
234 }
235 if (southLit) {
236 southSeparator.setBackground(normalColor);
237 southSeparator.setForeground(normalColor);
238 southLit = false;
239 }
240 }
241
242 private void highlightNorthAndSouthBorder() {
243 if (!southLit) {
244 southSeparator.setBackground(highlightColor);
245 southSeparator.setForeground(highlightColor);
246 southLit = true;
247 }
248 if (!northLit) {
249 northSeparator.setBackground(highlightColor);
250 northSeparator.setForeground(highlightColor);
251 northLit = true;
252 }
253 }
254
255 private void resetHighlights() {
256 if (southLit) {
257 southSeparator.setBackground(normalColor);
258 southSeparator.setForeground(normalColor);
259 southLit = false;
260 }
261 if (northLit) {
262 northSeparator.setBackground(normalColor);
263 northSeparator.setForeground(normalColor);
264 northLit = false;
265 }
266 }
267
268 // Variables declaration - do not modify//GEN-BEGIN:variables
269 private javax.swing.JPanel treeStructPanel;
270 private javax.swing.JButton editButton;
271 private javax.swing.JButton deleteButton;
272 private javax.swing.JSeparator northSeparator;
273 private javax.swing.JButton expandButton;
274 private javax.swing.JPanel bodyPanel;
275 private javax.swing.JPanel internalList;
276 private javax.swing.JPanel buttonPanel;
277 private javax.swing.JSeparator southSeparator;
278 // End of variables declaration//GEN-END:variables
279
280 public void expandButtonToggle() {
281 if (expanded) {
282 internalList.removeAll();
283 internalList.add(panel.getJPanel());
284 this.expandButton.setBorder(new javax.swing.border.CompoundBorder(new javax.swing.border.BevelBorder(javax.swing.border.BevelBorder.RAISED), new javax.swing.border.EmptyBorder(new java.awt.Insets(1, 3, 1, 3))));
285 } else {
286 for (int t=0; t<childList.size(); t++) {
287 internalList.add((java.awt.Component)childList.get(t));
288 }
289 this.expandButton.setBorder(new javax.swing.border.CompoundBorder(new javax.swing.border.BevelBorder(javax.swing.border.BevelBorder.LOWERED), new javax.swing.border.EmptyBorder(new java.awt.Insets(1, 3, 1, 3))));
290 }
291 parent.validate();
292 expanded = !expanded;
293 }
294
295 public void editButtonToggle(boolean save) {
296 if (!this.editMode) { // in compact mode.
297 this.internalList.remove((JPanel)this.panel);
298 this.panel = ((CMCompactPanel)this.panel).getEditPanel();
299 this.internalList.add((JPanel)this.panel, 0);
300 this.editButton.setBorder(new javax.swing.border.CompoundBorder(new javax.swing.border.BevelBorder(javax.swing.border.BevelBorder.LOWERED), new javax.swing.border.EmptyBorder(new java.awt.Insets(1, 3, 1, 3))));
301 editMode = true;
302 } else {
303 this.internalList.remove((JPanel)this.panel);
304 this.panel = ((CMEditPanel)this.panel).getCompactPanel();
305 this.internalList.add((JPanel)this.panel, 0);
306 this.editButton.setBorder(new javax.swing.border.CompoundBorder(new javax.swing.border.BevelBorder(javax.swing.border.BevelBorder.RAISED), new javax.swing.border.EmptyBorder(new java.awt.Insets(1, 3, 1, 3))));
307
308 if (save) {
309 // save record to server
310 main.saveRecord(this.panel.getView().getRecord());
311 }
312 editMode = false;
313 }
314 this.parent.validate();
315 }
316
317
318 /**
319 * DGListener
320 * a listener that will start the drag.
321 * has access to top level's dsListener and dragSource
322 * @see java.awt.dnd.DragGestureListener
323 * @see java.awt.dnd.DragSource
324 * @see java.awt.datatransfer.StringSelection
325 */
326 private class DGListener implements java.awt.dnd.DragGestureListener {
327 /**
328 * Start the drag if the operation is ok.
329 * uses java.awt.datatransfer.StringSelection to transfer
330 * the label's data
331 * @param e the event object
332 */
333 public void dragGestureRecognized(java.awt.dnd.DragGestureEvent e) {
334 if((e.getDragAction() & CMButtonPanel.this.dragAction) == 0)
335 return;
336
337 java.awt.datatransfer.Transferable transferable = new RecordTransferable(CMButtonPanel.this.panel.getView().getRecord());
338 try {
339 e.startDrag(java.awt.dnd.DragSource.DefaultMoveNoDrop, transferable, CMButtonPanel.this.dsListener);
340 } catch ( java.awt.dnd.InvalidDnDOperationException idoe ) {
341 idoe.printStackTrace();
342 }
343 }
344
345 }
346
347 /**
348 * DSListener
349 * a listener that will track the state of the DnD operation
350 *
351 * @see java.awt.dnd.DragSourceListener
352 * @see java.awt.dnd.DragSource
353 * @see java.awt.datatransfer.StringSelection
354 */
355 private class DSListener implements java.awt.dnd.DragSourceListener {
356
357 /**
358 * @param e the event
359 */
360 public void dragDropEnd(java.awt.dnd.DragSourceDropEvent e) {
361 if( e.getDropSuccess() == false ) {
362 return;
363 }
364 if ( (e.getDropAction() & (java.awt.dnd.DnDConstants.ACTION_MOVE | java.awt.dnd.DnDConstants.ACTION_LINK)) != 0) {
365 CMButtonPanel.this.parent.remove(CMButtonPanel.this);
366 }
367 }
368
369 private void refreshCursor(java.awt.dnd.DragSourceDragEvent e) {
370 java.awt.dnd.DragSourceContext context = e.getDragSourceContext();
371 //intersection of the users selected action, and the source and target actions
372 int myaction = e.getDropAction();
373 if( (myaction & CMButtonPanel.this.dragAction) != 0) {
374 context.setCursor(java.awt.dnd.DragSource.DefaultMoveDrop);
375 } else if ((myaction & java.awt.dnd.DnDConstants.ACTION_LINK) != 0) {
376 context.setCursor(java.awt.dnd.DragSource.DefaultLinkDrop);
377 } else {
378 context.setCursor(java.awt.dnd.DragSource.DefaultMoveNoDrop);
379 }
380 }
381
382 /**
383 * @param e the event
384 */
385 public void dragEnter(java.awt.dnd.DragSourceDragEvent e) {
386 refreshCursor(e);
387 }
388 /**
389 * @param e the event
390 */
391 public void dragOver(java.awt.dnd.DragSourceDragEvent e) {
392 }
393 /**
394 * @param e the event
395 */
396 public void dragExit(java.awt.dnd.DragSourceEvent e) {
397 }
398
399 /**
400 * for example, press shift during drag to change to
401 * a link action
402 * @param e the event
403 */
404 public void dropActionChanged(java.awt.dnd.DragSourceDragEvent e) {
405 refreshCursor(e);
406 }
407 }
408
409
410 /**
411 * DTListener
412 * a listener that tracks the state of the operation
413 * @see java.awt.dnd.DropTargetListener
414 * @see java.awt.dnd.DropTarget
415 */
416 private class DTListener implements java.awt.dnd.DropTargetListener {
417 private java.awt.Rectangle rect = new java.awt.Rectangle();
418 /**
419 * Called by isDragOk
420 * Checks to see if the flavor drag flavor is acceptable
421 * @param e the DropTargetDragEvent object
422 * @return whether the flavor is acceptable
423 */
424 private boolean isDragFlavorSupported(java.awt.dnd.DropTargetDragEvent e) {
425 boolean ok=false;
426 if (e.isDataFlavorSupported(RecordTransferable.getJavaJVMLocalObjectDataFlavor())) {
427 ok=true;
428 }
429 return ok;
430 }
431 /**
432 * Called by drop
433 * Checks the flavors and operations
434 * @param e the DropTargetDropEvent object
435 * @return the chosen DataFlavor or null if none match
436 */
437 private java.awt.datatransfer.DataFlavor chooseDropFlavor(java.awt.dnd.DropTargetDropEvent e) {
438 if (e.isLocalTransfer() == true && e.isDataFlavorSupported(RecordTransferable.getJavaJVMLocalObjectDataFlavor())) {
439 return RecordTransferable.getJavaJVMLocalObjectDataFlavor();
440 }
441 return null;
442 }
443
444 private void highlightBorders(java.awt.Point point) {
445 rect = getBounds(rect);
446 if (point.getY() >= (rect.getCenterY() - rect.getY()))
447 highlightSouthBorder();
448 else
449 highlightNorthBorder();
450 }
451
452 /**
453 * Called by dragEnter and dragOver
454 * Checks the flavors and operations
455 * @param e the event object
456 * @return whether the flavor and operation is ok
457 */
458 private boolean isDragOk(java.awt.dnd.DropTargetDragEvent e) {
459 boolean ok = true;
460 if(isDragFlavorSupported(e) == false) {
461 ok = false;
462 }
463 int da = e.getDropAction();
464 if (ok) {
465 if ((da & CMButtonPanel.this.acceptableDropActions) == 0)
466 ok = false;
467 }
468
469 if (!ok) {
470 resetHighlights();
471 } else if ( (da & java.awt.dnd.DnDConstants.ACTION_MOVE) == 0) {
472 highlightNorthAndSouthBorder();
473 } else if ( (da & java.awt.dnd.DnDConstants.ACTION_COPY) == 0) {
474 highlightBorders(e.getLocation());
475 }
476 return ok;
477 }
478
479 /**
480 * start "drag under" feedback on component
481 * invoke acceptDrag or rejectDrag based on isDragOk
482 */
483 public void dragEnter(java.awt.dnd.DropTargetDragEvent e) {
484 if(isDragOk(e) == false) {
485 e.rejectDrag();
486 return;
487 }
488 e.acceptDrag(e.getDropAction());
489 }
490
491 /**
492 * continue "drag under" feedback on component
493 * invoke acceptDrag or rejectDrag based on isDragOk
494 */
495 public void dragOver(java.awt.dnd.DropTargetDragEvent e) {
496 if(isDragOk(e) == false) {
497 e.rejectDrag();
498 return;
499 }
500 e.acceptDrag(e.getDropAction());
501 }
502
503 public void dropActionChanged(java.awt.dnd.DropTargetDragEvent e) {
504 if(isDragOk(e) == false) {
505 e.rejectDrag();
506 return;
507 }
508 e.acceptDrag(e.getDropAction());
509 }
510
511 public void dragExit(java.awt.dnd.DropTargetEvent e) {
512 resetHighlights();
513 }
514
515 /**
516 * perform action from getSourceActions on
517 * the transferrable
518 * invoke acceptDrop or rejectDrop
519 * invoke dropComplete
520 * if its a local (same JVM) transfer, use StringTransferable.localStringFlavor
521 * find a match for the flavor
522 * check the operation
523 * get the transferable according to the chosen flavor
524 * do the transfer
525 */
526 public void drop(java.awt.dnd.DropTargetDropEvent e) {
527 resetHighlights();
528 java.awt.datatransfer.DataFlavor chosen = chooseDropFlavor(e);
529 if (chosen == null) {
530 e.rejectDrop();
531 return;
532 }
533 // the actual operation
534 int da = e.getDropAction();
535 // the actions that the source has specified with DragGestureRecognizer
536 int sa = e.getSourceActions();
537
538 if ( ( sa & CMButtonPanel.this.acceptableDropActions ) == 0 ) {
539 // incompatible source for possible actions.
540 e.rejectDrop();
541 return;
542 }
543
544 Object data=null;
545 try {
546 e.acceptDrop(da);
547 data = e.getTransferable().getTransferData(chosen);
548 if (data == null)
549 throw new NullPointerException();
550 } catch ( Throwable t ) {
551 t.printStackTrace();
552 e.dropComplete(false);
553 return;
554 }
555
556
557 boolean rejected = true;
558
559 if (data instanceof nectar.record.Record ) {
560 nectar.record.Record record = (nectar.record.Record) data;
561
562 if ( (da & java.awt.dnd.DnDConstants.ACTION_LINK) != 0) {
563 System.err.println("Drop is a LINK");
564 rejected = !main.linkDragObjectToCurrentPane(record, CMButtonPanel.this);
565 } else {
566 System.err.println("Drop is a MOVE");
567 rect = getBounds(rect);
568 if (e.getLocation().getY() >= (rect.getCenterY() - rect.getY())) // insert below
569 rejected = !main.moveDragObjectToCurrentPane(record, CMButtonPanel.this, false);
570 else // insert above
571 rejected = !main.moveDragObjectToCurrentPane(record, CMButtonPanel.this, true);
572 }
573 }
574
575 if (rejected) {
576 e.dropComplete(false);
577 return;
578 }
579 e.dropComplete(true);
580 }
581
582 }
583 }