KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jimm > datavision > gui > FieldWidget


1 package jimm.datavision.gui;
2 import jimm.datavision.*;
3 import jimm.datavision.field.Field;
4 import jimm.datavision.layout.swing.AbstractSwingField;
5 import jimm.datavision.layout.swing.SwingTextField;
6 import jimm.util.I18N;
7 import java.awt.*;
8 import java.awt.event.*;
9 import java.awt.dnd.*;
10 import java.util.Observable JavaDoc;
11 import java.util.Observer JavaDoc;
12 import java.util.HashMap JavaDoc;
13 import javax.swing.*;
14 import javax.swing.event.MouseInputListener JavaDoc;
15
16 /**
17  * A field widget is the visual representation of a text-based report field.
18  *
19  * @author Jim Menard, <a HREF="mailto:jimm@io.com">jimm@io.com</a>
20  */

21 public class FieldWidget
22     implements MouseInputListener JavaDoc, DropTargetListener, ActionListener,
23            KeyListener, Observer JavaDoc
24 {
25
26 protected static final int GRAB_EDGE_WIDTH = 4;
27
28 protected static final int ACTION_INACTION = 0;
29 protected static final int ACTION_MOVE = 1;
30 protected static final int ACTION_STRETCH_LEFT = 2;
31 protected static final int ACTION_STRETCH_RIGHT = 3;
32 protected static final int ACTION_STRETCH_TOP = 4;
33 protected static final int ACTION_STRETCH_BOTTOM = 5;
34 protected static final int ACTION_POPPING_UP_MENU = 6;
35
36 /** Minimum field with and height. */
37 protected static final int MIN_SIZE = 2;
38
39 protected static final Font POPUP_FONT = new Font("Serif", Font.PLAIN, 10);
40
41 protected static HashMap JavaDoc componentMap = new HashMap JavaDoc();
42
43 protected AbstractSwingField swingField;
44 protected SectionWidget sectionWidget;
45 protected int action;
46 protected boolean actionStartedYet;
47 protected boolean selected;
48 protected boolean mouseChangedSelectedState;
49 protected PreMoveInfo preMoveInfo;
50 protected PreStretchInfo preStretchInfo;
51 protected JPopupMenu popup;
52 protected JMenu alignSubmenu;
53 protected JMenu sizeSubmenu;
54 protected JMenuItem nameItem;
55 protected JMenuItem showOrHide;
56 protected JMenuItem formatMenuItem;
57 protected JMenuItem aggregatesMenuItem;
58
59 /**
60  * Returns the field widget that owns a particular visual component.
61  *
62  * @return a field widget or <code>null</code>
63  */

64 static FieldWidget findFieldWidgetOwning(Object JavaDoc c) {
65     return (FieldWidget)componentMap.get(c);
66 }
67
68 /**
69  * Constructor.
70  *
71  * @param sw section widget in which the field's new widget will reside
72  * @param field a report field
73  */

74 public FieldWidget(SectionWidget sw, Field field) {
75     this(sw, new SwingTextField(field, field.designLabel()));
76 }
77
78 /**
79  * Constructor.
80  *
81  * @param sw section widget in which the field's new widget will reside
82  * @param asf an abstract swing field
83  */

84 protected FieldWidget(SectionWidget sw, AbstractSwingField asf) {
85     sectionWidget = sw;
86     swingField = asf;
87     action = ACTION_INACTION;
88
89     jimm.datavision.field.Rectangle b = getField().getBounds();
90     getComponent().setBounds((int)b.x, (int)b.y, (int)b.width, (int)b.height);
91
92     getComponent().setBorder(new FWBorder(this));
93     getComponent().addMouseListener(this);
94     getComponent().addMouseMotionListener(this);
95     getComponent().addKeyListener(this); // Frank W. Zammetti
96
buildPopupMenu();
97
98     // Allow drops. All we do is pass them on to our parent.
99
new DropTarget(this.getComponent(),
100            DnDConstants.ACTION_COPY_OR_MOVE, // actions
101
this); // DropTargetListener
102

103     // Set color, etc. based on field's visiblity
104
setVisibilityLook();
105
106     // Start observing field changes
107
getField().addObserver(this);
108
109     // Add to the class's map so we can find this widget later, given
110
// a GUI component.
111
componentMap.put(getComponent(), this);
112 }
113
114 /**
115  * Builds the popup menu.
116  */

117 protected void buildPopupMenu() {
118     popup = new JPopupMenu();
119     popup.setFont(POPUP_FONT);
120
121     nameItem = MenuUtils.addToMenu(this, popup,
122                    "FieldWidget.popup_dummy_title",
123                    POPUP_FONT);
124     nameItem.setText(getPopupNameText()); // Overwrite dummy title
125
nameItem.setEnabled(false);
126     popup.addSeparator();
127
128     addCustomPopupItems();
129
130     showOrHide =
131     MenuUtils.addToMenu(this, popup, "FieldWidget.popup_hide", POPUP_FONT);
132     MenuUtils.addToMenu(this, popup, "FieldWidget.popup_delete", POPUP_FONT);
133     popup.addSeparator();
134     formatMenuItem =
135     MenuUtils.addToMenu(this, popup, "FieldWidget.popup_format",
136                 POPUP_FONT);
137     MenuUtils.addToMenu(this, popup, "FieldWidget.popup_border", POPUP_FONT);
138     MenuUtils.addToMenu(this, popup, "FieldWidget.popup_bounds", POPUP_FONT);
139     popup.addSeparator();
140     aggregatesMenuItem =
141     MenuUtils.addToMenu(this, popup, "FieldWidget.popup_aggr",
142                 POPUP_FONT);
143     popup.addSeparator();
144
145     alignSubmenu = MenuUtils.buildAlignMenu(this, POPUP_FONT);
146     alignSubmenu.setFont(POPUP_FONT);
147     popup.add(alignSubmenu); // Add Align submenu to popup menu
148

149     sizeSubmenu = MenuUtils.buildSizeMenu(this, POPUP_FONT);
150     sizeSubmenu.setFont(POPUP_FONT);
151     popup.add(sizeSubmenu); // Add Size submenu to popup menu
152
}
153
154 /**
155  * This hook lets subclasses customize the popup menu. By default,
156  * nothing happens.
157  */

158 protected void addCustomPopupItems() {}
159
160 protected void finalize() throws Throwable JavaDoc {
161     getField().deleteObserver(this);
162 }
163
164 public void update(Observable JavaDoc obj, Object JavaDoc arg) {
165     swingField.format(); // Redo font, style, etc.
166
jimm.datavision.field.Rectangle b = getField().getBounds();
167     JTextPane textPane = (JTextPane)getComponent();
168
169     double width = b.width;
170     if (width < MIN_SIZE) width = MIN_SIZE;
171     double height = b.height;
172     if (height < MIN_SIZE) height = MIN_SIZE;
173
174     textPane.setBounds((int)b.x, (int)b.y, (int)width, (int)height);
175     textPane.setText(getField().designLabel());
176 }
177
178 /**
179  * Returns <code>true</code> if this field can be formatted.
180  *
181  * @return <code>true</code> if this field can be formatted
182  */

183 public boolean usesFormat() {
184     return true;
185 }
186
187 /**
188  * Returns string to use for popup menu's first item, the (disabled)
189  * name of this field.
190  */

191 protected String JavaDoc getPopupNameText() {
192     return getField().designLabel();
193 }
194
195 /**
196  * Returns the section widget containing this field widget.
197  *
198  * @return the section widget containing this field widget
199  */

200 public SectionWidget getSectionWidget() { return sectionWidget; }
201
202 /**
203  * Returns <code>true</code> if the field is selected.
204  *
205  * @return <code>true</code> if the field is selected
206  */

207 boolean isSelected() { return selected; }
208
209 /**
210  * Align this field in relation to <i>prototype</i>.
211  *
212  * @param which one of the <code>Designer.ALIGN_*</code> constants
213  * @param prototype the field to which this one should be aligned
214  */

215 public void align(int which, Field prototype) {
216     jimm.datavision.field.Rectangle b = getField().getBounds();
217     jimm.datavision.field.Rectangle pb = prototype.getBounds();
218     switch (which) {
219     case Designer.ALIGN_TOP:
220     b.setY(pb.y);
221     break;
222     case Designer.ALIGN_MIDDLE:
223     double middle = pb.y + pb.height / 2;
224     b.setY(middle - b.height / 2);
225     break;
226     case Designer.ALIGN_BOTTOM:
227     b.setY(pb.y + pb.height - b.height);
228     break;
229     case Designer.ALIGN_LEFT:
230     b.setX(pb.x);
231     break;
232     case Designer.ALIGN_CENTER:
233     double center = pb.x + pb.width / 2;
234     b.setX(center - b.width / 2);
235     break;
236     case Designer.ALIGN_RIGHT:
237     b.setX(pb.x + pb.width - b.width);
238     break;
239     case Designer.ALIGN_SNAP_TO_GRID:
240     sectionWidget.snapToGrid(b);
241     break;
242     }
243 }
244
245 /**
246  * Resize this field in relation to <var>prototype</var>.
247  *
248  * @param which one of the <code>Designer.SIZE_SAME_*</code> constants
249  * @param prototype the field from which this one should take sizes
250  */

251 public void size(int which, Field prototype) {
252     jimm.datavision.field.Rectangle b = getField().getBounds();
253     jimm.datavision.field.Rectangle pb = prototype.getBounds();
254     switch (which) {
255     case Designer.SIZE_SAME_WIDTH:
256     b.setWidth(pb.width);
257     break;
258     case Designer.SIZE_SAME_HEIGHT:
259     b.setHeight(pb.height);
260     break;
261     case Designer.SIZE_SAME_SIZE:
262     b.setWidth(pb.width);
263     b.setHeight(pb.height);
264     break;
265     }
266 }
267
268 /**
269  * Selects this field. If the shift key is down (we don't want to deselect
270  * other fields), toggles the selection state instead. If
271  * <i>deselectOthers</i> is <code>true</code>, do so. Eventually
272  * {@link #doSelect} will be called.
273  *
274  * @param deselectOthers if <code>true</code>, do so
275  */

276 void select(boolean deselectOthers) {
277     sectionWidget.select(this, !selected, deselectOthers);
278 }
279
280 /**
281  * Performs whatever is necessary to select or deselct self. Called by
282  * {@link Designer#select}.
283  *
284  * @param makeSelected new selection state
285  */

286 void doSelect(boolean makeSelected) {
287     // For some reason, characters between the original selection click and
288
// a deselection click get selected. Un-select all characters.
289
JTextPane textPane = (JTextPane)getComponent();
290     textPane.setCaretPosition(0);
291     textPane.moveCaretPosition(0);
292
293     if (selected != makeSelected) {
294     selected = makeSelected;
295     textPane.repaint(); // Reflect border changes
296
}
297 }
298
299 /**
300  * If the user is placing a new text field, pass it on to the section
301  * widget; else do nothing.
302  *
303  * @param e mousevent
304  */

305 public void mouseClicked(MouseEvent e) {
306     if (sectionWidget.designer.isPlacingNewTextField())
307     sectionWidget.createNewTextField(e);
308     else {
309     if (!mouseChangedSelectedState) {
310         select(!e.isShiftDown());
311     }
312     }
313 }
314
315 /**
316  * Asks section to drag (move, resize) all selected widgets together. (The
317  * section, in turn, asks the window to do the same.)
318  *
319  * @param e mouse event
320  */

321 public void mouseDragged(MouseEvent e) {
322     if (action == ACTION_INACTION || action == ACTION_POPPING_UP_MENU)
323     return;
324
325     if (!selected) {
326     select(!e.isShiftDown());
327     mouseChangedSelectedState = true;
328     }
329
330     // Set ePos to screen position of click
331
java.awt.Point JavaDoc screenMousePos = e.getPoint();
332     java.awt.Point JavaDoc screenPos = getComponent().getLocationOnScreen();
333     screenMousePos.translate(screenPos.x, screenPos.y);
334
335     if (!actionStartedYet) {
336     actionStartedYet = true;
337     switch (action) {
338     case ACTION_MOVE:
339         // will eventually call our pickUp()
340
sectionWidget.pickUp(screenMousePos);
341         break;
342     case ACTION_STRETCH_LEFT:
343     case ACTION_STRETCH_RIGHT:
344     case ACTION_STRETCH_TOP:
345     case ACTION_STRETCH_BOTTOM:
346         // will eventually call our startStretching()
347
sectionWidget.startStretching(screenMousePos);
348         break;
349     }
350     }
351
352     sectionWidget.dragSelectedWidgets(action, screenMousePos);
353 }
354
355 /**
356  * Changes cursor if this widget is selected.
357  *
358  * @param e mouse event
359  */

360 public void mouseEntered(MouseEvent e) {
361     if (selected && !sectionWidget.designer.isPlacingNewTextField())
362     cursorForPosition(e);
363 }
364
365 /**
366  * Changes cursor if this widget is selected.
367  *
368  * @param e mouse event
369  */

370 public void mouseExited(MouseEvent e) {
371     if (selected && !sectionWidget.designer.isPlacingNewTextField())
372     resetCursor();
373 }
374
375 /**
376  * Changes cursor if this widget is selected.
377  *
378  * @param e mouse event
379  */

380 public void mouseMoved(MouseEvent e) {
381     if (selected && !sectionWidget.designer.isPlacingNewTextField())
382     cursorForPosition(e);
383 }
384
385 /**
386  * When the mouse is pressed, do the Right Thing(tm). Handles popup menu,
387  * selecting, shift-selecting, and prepping for movement.
388  *
389  * @param e mouse event
390  */

391 public void mousePressed(MouseEvent e) {
392     mouseChangedSelectedState = false;
393
394     if (mousePressReleaseCommon(e))
395     return;
396
397     cursorForPosition(e);
398     action = actionFromPosition(e);
399
400     actionStartedYet = false; // Used to detect start of moves and stretches
401
}
402
403 /**
404  * When the mouse is released and we have been dragging this field,
405  * drop this one and all others that are being dragged.
406  *
407  * @param e mouse event
408  */

409 public void mouseReleased(MouseEvent e) {
410     if (mousePressReleaseCommon(e))
411     return;
412
413     switch (action) {
414     case ACTION_MOVE:
415     if (actionStartedYet) {
416         // Put down this and all selected fields.
417
// Set mousePos to screen position of mouse.
418
java.awt.Point JavaDoc screenMousePos = e.getPoint();
419         java.awt.Point JavaDoc screenPos = getComponent().getLocationOnScreen();
420         screenMousePos.translate(screenPos.x, screenPos.y);
421
422         // Put all selected widgets down. Might not be put down in same
423
// section.
424
sectionWidget.putDown(this, preMoveInfo.screenPos, screenMousePos);
425     }
426     break;
427     case ACTION_STRETCH_LEFT:
428     case ACTION_STRETCH_RIGHT:
429     case ACTION_STRETCH_TOP:
430     case ACTION_STRETCH_BOTTOM:
431     if (actionStartedYet) {
432         // Stop stretching all selected widgets down.
433
sectionWidget.stopStretching(this, preStretchInfo.origBounds);
434     }
435     break;
436     }
437
438     action = ACTION_INACTION;
439 }
440
441 /**
442  * Performs checks and behaviors common to both mouse presses and mouse
443  * release events. Returns <code>true</code> if the event was handled by
444  * this method and should be ignored by the caller.
445  *
446  * @param e the mouse event
447  * @return <code>true</code> if the event was handled by this method and
448  * should be ignored by the caller
449  */

450 protected boolean mousePressReleaseCommon(MouseEvent e) {
451     if (sectionWidget.designer.isPlacingNewTextField()) {
452     sectionWidget.createNewTextField(e);
453     return true;
454     }
455
456     if (e.isPopupTrigger()) {
457     showPopupMenu(e);
458     return true;
459     }
460
461     return false;
462 }
463
464 /**
465  * Returns the information we saved before starting to move this widget.
466  *
467  * @return an object containing the information we saved before starting
468  * to move this widget
469  */

470 public PreMoveInfo getPreMoveInfo() { return preMoveInfo; }
471
472 /**
473  * Prepares for movement by remembering where we are now and removing
474  * ourself from the section view widget (but not the section model).
475  */

476 public void pickUp(java.awt.Point JavaDoc mouseScreenPos) {
477     preMoveInfo = new PreMoveInfo(this, mouseScreenPos);
478
479     // Remove from section view widget, but not section model in report.
480
sectionWidget.removeField(this);
481 }
482
483 /**
484  * Place this field into a section widget. Our bounds rectangle is in
485  * window coordinates; translate to section coordinates.
486  */

487 public void putDown(SectionWidget sw) {
488     // Recalculate bounds
489
jimm.datavision.field.Rectangle b = getField().getBounds();
490     b.setBounds(b.x - SectionWidget.LHS_WIDTH, b.y - sw.getBounds().y,
491         b.width, b.height);
492
493     // Move model and view to new section
494
moveToSection(sw);
495
496     preMoveInfo = null;
497 }
498
499 /**
500  * Move back to original location in original section widget.
501  */

502 void snapBack() {
503     getField().getBounds().setBounds(preMoveInfo.origBounds);
504     moveToSection(preMoveInfo.sectionWidget);
505 }
506
507 /**
508  * Prepares for stretching by creating a <code>PreStretchInfo</code>.
509  *
510  * @param mouseScreenPos the location of the mouse in screen coordinates
511  */

512 public void startStretching(java.awt.Point JavaDoc mouseScreenPos) {
513     preStretchInfo = new PreStretchInfo(this, mouseScreenPos);
514 }
515
516 /**
517  * Stop stretching.
518  */

519 public void stopStretching() {
520     preStretchInfo = null;
521 }
522
523 /**
524  * Displays popup menu, after enabling/disabling the appropriate items.
525  */

526 protected void showPopupMenu(MouseEvent e) {
527     showOrHide.setText(getField().isVisible()
528                ? I18N.get(I18N.MENU_FILE_PREFIX,
529                   "FieldWidget.popup_hide")
530                : I18N.get(I18N.MENU_FILE_PREFIX,
531                   "FieldWidget.popup_show"));
532
533     enableMenuItems();
534
535     action = ACTION_POPPING_UP_MENU;
536     popup.show(e.getComponent(), e.getX(), e.getY());
537 }
538
539 /**
540  * Enables or disables popup menu items based on field and window state.
541  */

542 protected void enableMenuItems() {
543     boolean canFormat = usesFormat()
544     || sectionWidget.designer.someSelectedFieldUsesFormat();
545     formatMenuItem.setEnabled(canFormat);
546
547     int numSelectedFields = sectionWidget.designer.countSelectedFields();
548     if (numSelectedFields >= 2) {
549     // More than two fields selected.
550
for (int i = 0; i < alignSubmenu.getItemCount(); ++i)
551         alignSubmenu.getItem(i).setEnabled(true);
552     sizeSubmenu.setEnabled(true);
553     aggregatesMenuItem.setEnabled(false);
554     }
555     else {
556     // Only one item selected or this item is not selected.
557
for (int i = 0; i < alignSubmenu.getItemCount() - 1; ++i)
558         alignSubmenu.getItem(i).setEnabled(false);
559     sizeSubmenu.setEnabled(false);
560
561     // Ask the AggregateField class if we can aggregate this field.
562
aggregatesMenuItem.setEnabled(getField().canBeAggregated());
563     }
564 }
565
566 /**
567  * Given a mouse event, returns the <code>ACTION_*</code> constant
568  * associated with the mouse position within the field.
569  */

570 protected int actionFromPosition(MouseEvent e) {
571     int ex = e.getX();
572     int ey = e.getY();
573     if (ex <= GRAB_EDGE_WIDTH)
574     return ACTION_STRETCH_LEFT;
575     else if (ex >= getField().getBounds().width - GRAB_EDGE_WIDTH)
576     return ACTION_STRETCH_RIGHT;
577     else if (ey <= GRAB_EDGE_WIDTH)
578     return ACTION_STRETCH_TOP;
579     else if (ey >= getField().getBounds().height - GRAB_EDGE_WIDTH)
580     return ACTION_STRETCH_BOTTOM;
581     else
582     return ACTION_MOVE;
583 }
584
585 /**
586  * If this field is selected, sets the cursor based on the current mouse
587  * position in the widget. If the field is unselected, resets the cursor.
588  *
589  * @param e a mouse event
590  */

591 protected void cursorForPosition(MouseEvent e) {
592     if (!selected) {
593     resetCursor();
594     return;
595     }
596
597     switch (action == ACTION_INACTION ? actionFromPosition(e) : action) {
598     case ACTION_MOVE:
599     getComponent().setCursor(Cursor
600                  .getPredefinedCursor(Cursor.MOVE_CURSOR));
601     break;
602     case ACTION_STRETCH_LEFT:
603     getComponent().setCursor(Cursor
604                  .getPredefinedCursor(Cursor.W_RESIZE_CURSOR));
605     break;
606     case ACTION_STRETCH_RIGHT:
607     getComponent().setCursor(Cursor
608                  .getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
609     break;
610     case ACTION_STRETCH_TOP:
611     getComponent().setCursor(Cursor
612                  .getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
613     break;
614     case ACTION_STRETCH_BOTTOM:
615     getComponent().setCursor(Cursor
616                  .getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
617     break;
618     }
619 }
620
621 /**
622  * Resets the cursor to its default.
623  */

624 protected void resetCursor() {
625     getComponent().setCursor(null);
626 }
627
628 /**
629  * Performs a drag or a stretch. Called from {@link
630  * Designer#dragSelectedWidgets}.
631  *
632  * @param action a <code>ACTION_*</code> constant
633  * @param mouseScreenPos the location of the mouse in screen coordinates
634  * @see Designer#dragSelectedWidgets
635  */

636 void doDrag(int action, java.awt.Point JavaDoc mouseScreenPos) {
637     jimm.datavision.field.Rectangle b = getField().getBounds();
638
639     if (action == ACTION_MOVE) {
640     int dx = mouseScreenPos.x - preMoveInfo.startMouseScreenPos.x;
641     int dy = mouseScreenPos.y - preMoveInfo.startMouseScreenPos.y;
642     // Must take into account the fact that we are floating on the
643
// section container. See Designer.pickUp.
644
b.setBounds(preMoveInfo.origBounds.x + dx + SectionWidget.LHS_WIDTH,
645             preMoveInfo.origBounds.y + dy
646             + sectionWidget.getBounds().y,
647             preMoveInfo.origBounds.width,
648             preMoveInfo.origBounds.height);
649     return;
650     }
651
652     int dx = mouseScreenPos.x - preStretchInfo.startMouseScreenPos.x;
653     int dy = mouseScreenPos.y - preStretchInfo.startMouseScreenPos.y;
654     java.awt.Rectangle JavaDoc newBounds;
655
656     switch (action) {
657     case ACTION_STRETCH_LEFT:
658     newBounds =
659         new java.awt.Rectangle JavaDoc((int)preStretchInfo.origBounds.x + dx,
660                    (int)preStretchInfo.origBounds.y,
661                    (int)preStretchInfo.origBounds.width - dx,
662                    (int)preStretchInfo.origBounds.height);
663     break;
664     case ACTION_STRETCH_RIGHT:
665     newBounds =
666         new java.awt.Rectangle JavaDoc((int)preStretchInfo.origBounds.x,
667                    (int)preStretchInfo.origBounds.y,
668                    (int)preStretchInfo.origBounds.width + dx,
669                    (int)preStretchInfo.origBounds.height);
670     break;
671     case ACTION_STRETCH_TOP:
672     newBounds =
673         new java.awt.Rectangle JavaDoc((int)preStretchInfo.origBounds.x,
674                    (int)preStretchInfo.origBounds.y + dy,
675                    (int)preStretchInfo.origBounds.width,
676                    (int)preStretchInfo.origBounds.height - dy);
677     break;
678     case ACTION_STRETCH_BOTTOM:
679     newBounds =
680         new java.awt.Rectangle JavaDoc((int)preStretchInfo.origBounds.x,
681                    (int)preStretchInfo.origBounds.y,
682                    (int)preStretchInfo.origBounds.width,
683                    (int)preStretchInfo.origBounds.height + dy);
684     break;
685     default:
686     return;
687     }
688
689     // Make sure new bounds fit within the section
690
newBounds = newBounds.intersection(preStretchInfo.sectionBounds);
691
692     // Make sure new bounds are not too small.
693
switch (action) {
694     case ACTION_STRETCH_LEFT:
695     if (newBounds.width < MIN_SIZE) {
696         dx = MIN_SIZE - newBounds.width;
697         newBounds.x -= dx;
698         newBounds.width = MIN_SIZE;
699     }
700     break;
701     case ACTION_STRETCH_RIGHT:
702     if (newBounds.width < MIN_SIZE)
703     newBounds.width = MIN_SIZE;
704     break;
705     case ACTION_STRETCH_TOP:
706     if (newBounds.height < MIN_SIZE) {
707         dy = MIN_SIZE - newBounds.height;
708         newBounds.y -= dy;
709         newBounds.height = MIN_SIZE;
710     }
711     break;
712     case ACTION_STRETCH_BOTTOM:
713     if (newBounds.height < MIN_SIZE)
714         newBounds.height = MIN_SIZE;
715     break;
716     default:
717     return;
718     }
719
720     b.setBounds(newBounds);
721 }
722
723 /**
724  * Asks the window delete this field and all selected fields.
725  */

726 protected void delete() {
727     sectionWidget.designer.deleteSelectedFieldsAnd(this);
728 }
729
730 /**
731  * Deletes this field from its section. Deletes the report field from the
732  * report section (the model) and the field widget from the parent widget
733  * (the view/controller).
734  */

735 public void doDelete() {
736     getField().getSection().removeField(getField());
737     getComponent().getParent().remove(getComponent());
738 }
739
740 /**
741  * Moves both field view and model to a new section. Technically, moves
742  * model to a new section and adds view to section widget.
743  *
744  * @param sw a section widget
745  */

746 public void moveToSection(SectionWidget sw) {
747     // Bounds are already relative to new section widget
748

749     Section currSection = getField().getSection();
750     Section newSection = sw.section;
751     if (newSection != currSection) {
752     if (currSection != null)
753         currSection.removeField(getField());
754     newSection.addField(getField());
755     }
756
757     // Always move to new section widget, because the act of dragging
758
// lifted this widget from that section widget. (That's why we don't
759
// need to remove it from the current section widget).
760
sw.addField(this);
761
762     // Not sure why this is necessary, but sometimes it is.
763
getComponent().repaint();
764 }
765
766 /**
767  * Handles drop of a dragged field. Passes request on to parent view.
768  *
769  * @param e drop event
770  * @see SectionFieldPanel#drop
771  */

772 public void drop(DropTargetDropEvent e) {
773     ((DropTargetListener)getComponent().getParent()).drop(e);
774 }
775
776 public void dragEnter(DropTargetDragEvent e) { }
777 public void dragExit(DropTargetEvent e) { }
778 public void dragOver(DropTargetDragEvent e) { }
779 public void dropActionChanged(DropTargetDragEvent e) { }
780
781 /**
782  * Performs some action based on the action command string (the menu
783  * item text).
784  */

785 public void actionPerformed(ActionEvent e) {
786     String JavaDoc command = e.getActionCommand();
787     if (command == null) return;
788
789     Designer designer = sectionWidget.designer;
790
791     if ("hide".equals(command) || "show".equals(command))
792     toggleVisibility();
793     else if ("delete".equals(command))
794     delete();
795
796     else if ("align_top".equals(command))
797     designer.align(Designer.ALIGN_TOP);
798     else if ("align_middle".equals(command))
799     designer.align(Designer.ALIGN_MIDDLE);
800     else if ("align_bottom".equals(command))
801     designer.align(Designer.ALIGN_BOTTOM);
802     else if ("align_left".equals(command))
803     designer.align(Designer.ALIGN_LEFT);
804     else if ("align_center".equals(command))
805     designer.align(Designer.ALIGN_CENTER);
806     else if ("align_right".equals(command))
807     designer.align(Designer.ALIGN_RIGHT);
808     else if ("snap_to_grid".equals(command)) {
809     if (designer.countSelectedFields() > 0)
810         designer.align(Designer.ALIGN_SNAP_TO_GRID);
811     else
812         align(Designer.ALIGN_SNAP_TO_GRID, getField());
813     }
814
815     else if ("size_width".equals(command))
816     designer.size(Designer.SIZE_SAME_WIDTH);
817     else if ("size_height".equals(command))
818     designer.size(Designer.SIZE_SAME_HEIGHT);
819     else if ("size_size".equals(command))
820     designer.size(Designer.SIZE_SAME_SIZE);
821
822     else if ("format".equals(command))
823     new FormatWin(designer, this.getField(), 0);
824     else if ("border".equals(command))
825     new FormatWin(designer, this.getField(), 1);
826     else if ("bounds".equals(command))
827     new BoundsWin(designer, this.getField());
828     else if ("aggregates".equals(command))
829     new AggregatesWin(designer, this);
830 }
831
832 public String JavaDoc toString() {
833     return getField().designLabel();
834 }
835
836 /**
837  * Toggles the visiblity of this field and all selected fields.
838  */

839 void toggleVisibility() {
840     boolean newVisibility = !getField().isVisible();
841     sectionWidget.setFieldVisibility(newVisibility, this);
842 }
843
844 /**
845  * Sets the visiblity of this field. Called directly and/or indirectly
846  * from <code>toggleVisibility</code>.
847  */

848 public void doSetVisibility(boolean newVisibility) {
849     getField().setVisible(newVisibility);
850     setVisibilityLook();
851 }
852
853 /**
854  * Sets the look of the field based on the current visiblity flag value. The
855  * {@link jimm.datavision.layout.swing.AbstractSwingField} does all the work.
856  * We just ask our <var>swingField</var> to re-format itself.
857  */

858 protected void setVisibilityLook() {
859     swingField.format();
860 }
861
862 Color getColor() { return swingField.getColor(); }
863
864 public Field getField() { return swingField.getField(); }
865
866 public JComponent getComponent() { return swingField.getComponent(); }
867
868 /* This code fixes the delete key not working. Basically, I discovered, for
869  * reasons I frankly don't get at the moment, attaching the KeyListener to the
870  * frame in DesignWin wasn't working (I'm beting it's some sort of event
871  * bubbling issue with which I am unfamiliar). So, it had to be attached at
872  * the widget level. So, putting here in FieldWidget applies it to all other
873  * widgets. The keyPressed and keyTyped events we want to basically ignore, as
874  * they only apply to TextFieldWidgets, and in that case, that class will
875  * override keyTyped, which is what it's interested in. So, we implement the
876  * delete code that was previously an anonymous inner class in DesignWin, and
877  * we're good!
878  * <p>
879  * Frank W. Zammetti
880  */

881
882 public void keyPressed(KeyEvent ke) { return; }
883 public void keyTyped(KeyEvent ke) { return; }
884 public void keyReleased(KeyEvent ke) {
885     if (!sectionWidget.designer.ignoreKeys) {
886     int code = ke.getKeyCode();
887     if (code == KeyEvent.VK_BACK_SPACE || code == KeyEvent.VK_DELETE)
888         sectionWidget.designer.deleteSelectedFields();
889     }
890 }
891
892 }
893
Popular Tags