KickJava   Java API By Example, From Geeks To Geeks.

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


1 package jimm.datavision.gui;
2 import jimm.datavision.*;
3 import jimm.datavision.field.Field;
4 import jimm.datavision.source.DataSource;
5 import jimm.datavision.layout.swing.SwingLE;
6 import jimm.datavision.gui.sql.*;
7 import jimm.datavision.gui.cmd.*;
8 import jimm.util.I18N;
9 import java.awt.*;
10 import java.awt.event.*;
11 import java.io.File JavaDoc;
12 import java.util.*;
13 import javax.swing.*;
14
15 /**
16  * The abstract superclass of {@link Report} designer windows and applets.
17  *
18  * @author Jim Menard, <a HREF="mailto:jimm@io.com">jimm@io.com</a>
19  */

20 public abstract class Designer implements ActionListener, Observer {
21
22 public static final int GRID_SIZE = 8;
23
24 public static final int ALIGN_TOP = 0;
25 public static final int ALIGN_MIDDLE = 1;
26 public static final int ALIGN_BOTTOM = 2;
27 public static final int ALIGN_LEFT = 3;
28 public static final int ALIGN_CENTER = 4;
29 public static final int ALIGN_RIGHT = 5;
30 public static final int ALIGN_SNAP_TO_GRID = 6;
31
32 public static final int SIZE_SAME_WIDTH = 0;
33 public static final int SIZE_SAME_HEIGHT = 1;
34 public static final int SIZE_SAME_SIZE = 2;
35
36 protected static ArrayList designWindows = new ArrayList();
37 protected static boolean exitWhenLastWindowClosed = true;
38 protected static JFileChooser chooser;
39
40 protected Report report;
41 /** The frame may be null; it will be the parent of dialog boxes. */
42 protected JFrame frame;
43 /** The container of the root pane---the highest level widget. */
44 protected RootPaneContainer rootPaneContainer; // Set by subclasses
45
protected CommandHistory commandHistory;
46 protected ArrayList sectionWidgets;
47 protected String JavaDoc reportFilePath;
48 protected JLayeredPane sectionContainer;
49 protected ArrayList selectedFields;
50 protected JScrollPane scroller;
51 protected JMenuItem undoItem, redoItem, cutItem, copyItem, pasteItem,
52     delSelectionItem, delGroupItem, delSectionItem, aggrItem, groupItem,
53     sectItem, formatItem, borderItem, boundsItem, defaultFormatItem,
54     tableJoinItem, sqlQueryTextItem, connectionItem, selectRecordsItem,
55     sortByItem, groupByItem, runItem, exportItem, subreportItem;
56 protected JMenu alignSubmenu, sizeSubmenu, paperSizeSubmenu;
57 protected boolean placingNewTextField;
58 protected boolean ignoreKeys;
59
60 /**
61  * Adds a window to the list of open design windows. Also notifies the
62  * error handler class that we it should use the GUI to display error
63  * messages.
64  *
65  * @param win a design window
66  */

67 public static void addWindow(Designer win) {
68     designWindows.add(win);
69 }
70
71 /**
72  * Returns the design window associated with the specified report, or
73  * <code>null</code> if one is not found.
74  *
75  * @param r a report
76  * @return a design window or <code>null</code> if one is not found
77  */

78 public static Designer findWindowFor(Report r) {
79     for (Iterator iter = designWindows.iterator(); iter.hasNext(); ) {
80     Designer win = (Designer)iter.next();
81     if (win.report == r)
82         return win;
83     }
84     return null;
85 }
86
87 /**
88  * Sets value of flag that determines if the application should exit
89  * when the last design window is closed. The default value is
90  * <code>true</code>.
91  */

92 public static void setExitWhenLastWinClosed(boolean exit) {
93     exitWhenLastWindowClosed = exit;
94 }
95
96 /**
97  * Deletes a window from the list of windows. If there are no more design
98  * windows left and <var>exitWhenLastWindowClosed</var> is
99  * <code>true</code> (which it is by default), exits the application.
100  *
101  * @param win a design window
102  */

103 protected static void deleteWindow(Designer win) {
104     designWindows.remove(win);
105     if (designWindows.isEmpty() && exitWhenLastWindowClosed)
106     System.exit(0);
107 }
108
109 /**
110  * Closes each open design window (unless user cancels). If all are closed,
111  * quits the application.
112  */

113 protected static void maybeQuit() {
114     // Can't use iterator over original list 'cause we're deleting items
115
// from the list.
116
ArrayList copy = (ArrayList)designWindows.clone();
117     for (Iterator iter = copy.iterator(); iter.hasNext(); )
118     ((Designer)iter.next()).maybeClose();
119 }
120
121 public static JFileChooser getChooser() {
122     if (chooser == null)
123     chooser = new JFileChooser();
124     return chooser;
125 }
126
127 /**
128  * Constructor. Reads the named report file or, if it's <code>null</code>,
129  * creates a new, empty report.
130  *
131  * @param f an XML report file; may be <code>null</code>
132  * @param databasePassword string to give to report; OK if it's
133  * <code>null</code>
134  * @param rpc the root pane container (the <code>JFrame</code> or
135  * <code>JApplet</code>)
136  * @param jframe the design window; may be <code>null</code> (for example,
137  * when the designer is an applet)
138  */

139 public Designer(File JavaDoc f, String JavaDoc databasePassword,
140         RootPaneContainer rpc, JFrame jframe)
141 {
142     // In subclasses, calling super(fileName, password, rpc, frame)
143
// is a pain when frame == rpc because it is difficult to create
144
// the frame, assign it to a temp, and pass the temp into both frame
145
// and rpc. Therefore, when you pass in a frame but no rpc we assume
146
// frame == rpc (because a JFrame is a RootPaneContainer).
147
frame = jframe;
148     rootPaneContainer = rpc;
149     if (frame != null && rootPaneContainer == null)
150     rootPaneContainer = frame;
151
152     ErrorHandler.useGUI(true); // Must set before opening report
153
selectedFields = new ArrayList();
154
155     // Must create command history before asking for database information
156
// because that can cause a command to be created.
157
commandHistory = new CommandHistory();
158
159     StatusDialog statusDialog =
160     new StatusDialog(frame, I18N.get("DesignWin.status_title"), false,
161              f == null
162              ? I18N.get("DesignWin.creating_empty")
163              : I18N.get("DesignWin.reading_xml"));
164
165     // readReport() sets our report ivar as a side-effect.
166
boolean askForDbConnInfo = readReport(f, databasePassword);
167
168     if (report == null ||
169     (report.getDataSource() == null && !askForDbConnInfo))
170     {
171     // User cancelled when asked for password. Close this window and
172
// quit if this is the only report open.
173
statusDialog.dispose();
174     closeMe();
175     Designer.deleteWindow(this); // Will quit if no other windows
176
return;
177     }
178
179     if (askForDbConnInfo) {
180     openDbConnWin(true); // Modally ask for database connection info
181
if (report.getDataSource() == null) {
182         // User cancelled. Close this window and quit if this is the
183
// only report open.
184
statusDialog.dispose();
185         closeMe();
186         Designer.deleteWindow(this); // Will quit if no other windows
187
return;
188     }
189     }
190
191     statusDialog.update(I18N.get("DesignWin.building_win"));
192
193     buildWindow();
194     commandHistory.setMenuItems(undoItem, redoItem);
195     enableMenuItems();
196
197     // Might be using this code for dragging to select multiple fields.
198
// SelectionHandler h = new SelectionHandler();
199
// frame.addMouseListener(h);
200
// frame.addMouseMotionListener(h);
201

202     Designer.addWindow(this);
203
204     // Let the format window start a thread to load font names. It will
205
// only load them the first time this is called, but that's not our
206
// problem, now is it?
207
FormatWin.loadFontChoices();
208
209     statusDialog.dispose();
210 }
211
212 protected void closeMe() {
213     if (frame != null)
214     frame.dispose();
215 }
216
217 public void update(Observable o, Object JavaDoc arg) {
218     enableMenuItems();
219 }
220
221 /**
222  * Performs a command.
223  *
224  * @param cmd a command
225  */

226 public void performCommand(Command cmd) {
227     commandHistory.perform(cmd);
228 }
229
230 /**
231  * Adds to the command history a command that has already been performed.
232  *
233  * @param cmd a command
234  */

235 public void addCommand(Command cmd) {
236     commandHistory.add(cmd);
237 }
238
239 /**
240  * Reads the named report file or, if it's <code>null</code>, creates
241  * a new, empty report. Returns <code>true</code> if we need to ask
242  * the user for connection info because this is a new report.
243  *
244  * @param f report XML file
245  * @param databasePassword string to give to report; OK if it's
246  * <code>null</code>
247  * @return <code>true</code> if we need to ask the user for connection info
248  */

249 protected boolean readReport(File JavaDoc f, String JavaDoc databasePassword) {
250     if (f != null) {
251     reportFilePath = f.getPath();
252     report = new Report();
253     report.setDatabasePassword(databasePassword);
254     try {
255         report.read(f);
256         return false;
257     }
258     catch (UserCancellationException uce) {
259         report = null; // Signal report open cancelled
260
return true; // Doesn't matter what we return
261
}
262     catch (Exception JavaDoc e) {
263         ErrorHandler.error(e);
264         report = new Report();
265         return true;
266     }
267     }
268     else {
269     report = new Report();
270     reportFilePath = null;
271     return true;
272     }
273 }
274
275 public void setIgnoreKeys(boolean ignore) { ignoreKeys = ignore; }
276
277 /**
278  * Builds the window components.
279  */

280 protected void buildWindow() {
281     rootPaneContainer.getRootPane().setJMenuBar(buildMenuBar());
282     buildSections();
283 }
284
285 /**
286  * Builds the window menu bar.
287  */

288 protected JMenuBar buildMenuBar() {
289     JMenuBar bar = new JMenuBar();
290     bar.add(buildFileMenu());
291     bar.add(buildEditMenu());
292     bar.add(buildInsertMenu());
293     bar.add(buildFormatMenu());
294     bar.add(buildDatabaseMenu());
295     bar.add(buildReportMenu());
296     bar.add(Box.createHorizontalGlue());
297     bar.add(buildHelpMenu());
298
299     return bar;
300 }
301
302 /**
303  * Builds and returns the "File" menu.
304  *
305  * @return a menu
306  */

307 protected JMenu buildFileMenu() {
308     JMenu menu = MenuUtils.readMenu("DesignWin.menu_file");
309
310     MenuUtils.addToMenu(this, menu, "DesignWin.menu_file_new");
311     MenuUtils.addToMenu(this, menu, "DesignWin.menu_file_open");
312     menu.addSeparator();
313     MenuUtils.addToMenu(this, menu, "DesignWin.menu_file_save");
314     MenuUtils.addToMenu(this, menu, "DesignWin.menu_file_save_as");
315
316     menu.addSeparator();
317
318     ButtonGroup orientationGroup = new ButtonGroup();
319     ButtonGroup nameGroup = new ButtonGroup();
320     menu.add(paperSizeSubmenu =
321          MenuUtils.buildPaperSizeMenu(this,
322                       report.getPaperFormat(),
323                       orientationGroup, nameGroup));
324     menu.addSeparator();
325     MenuUtils.addToMenu(this, menu, "DesignWin.menu_file_close");
326     MenuUtils.addToMenu(this, menu, "DesignWin.menu_file_quit");
327
328     return menu;
329 }
330
331 /**
332  * Builds and returns the "Edit" menu.
333  *
334  * @return a menu
335  */

336 protected JMenu buildEditMenu() {
337     JMenu menu = MenuUtils.readMenu("DesignWin.menu_edit");
338
339     undoItem = MenuUtils.addToMenu(this, menu, "DesignWin.menu_edit_undo");
340     redoItem = MenuUtils.addToMenu(this, menu, "DesignWin.menu_edit_redo");
341     menu.addSeparator();
342     cutItem = MenuUtils.addToMenu(this, menu, "DesignWin.menu_edit_cut");
343     copyItem = MenuUtils.addToMenu(this, menu, "DesignWin.menu_edit_copy");
344     pasteItem = MenuUtils.addToMenu(this, menu, "DesignWin.menu_edit_paste");
345     menu.addSeparator();
346     delSelectionItem =
347     MenuUtils.addToMenu(this, menu, "DesignWin.menu_edit_del_fields");
348     menu.addSeparator();
349     delGroupItem =
350     MenuUtils.addToMenu(this, menu, "DesignWin.menu_edit_del_group");
351     delSectionItem =
352     MenuUtils.addToMenu(this, menu, "DesignWin.menu_edit_del_section");
353
354     return menu;
355 }
356
357 /**
358  * Builds and returns the "Insert" menu.
359  *
360  * @return a menu
361  */

362 protected JMenu buildInsertMenu() {
363     JMenu menu = MenuUtils.readMenu("DesignWin.menu_insert");
364
365     MenuUtils.addToMenu(this, menu, "DesignWin.menu_insert_column");
366     MenuUtils.addToMenu(this, menu, "DesignWin.menu_insert_text");
367     MenuUtils.addToMenu(this, menu, "DesignWin.menu_insert_formula");
368     MenuUtils.addToMenu(this, menu, "DesignWin.menu_insert_param");
369     MenuUtils.addToMenu(this, menu, "DesignWin.menu_insert_usercol");
370     MenuUtils.addToMenu(this, menu, "DesignWin.menu_insert_special");
371     aggrItem =
372     MenuUtils.addToMenu(this, menu, "DesignWin.menu_insert_aggr");
373     menu.addSeparator();
374     MenuUtils.addToMenu(this, menu, "DesignWin.menu_insert_image");
375     MenuUtils.addToMenu(this, menu, "DesignWin.menu_insert_line");
376     menu.addSeparator();
377     groupItem = MenuUtils.addToMenu(this, menu, "DesignWin.menu_insert_group");
378     sectItem =
379     MenuUtils.addToMenu(this, menu, "DesignWin.menu_insert_section");
380     subreportItem =
381     MenuUtils.addToMenu(this, menu, "DesignWin.menu_insert_subreport");
382
383     return menu;
384 }
385
386 /**
387  * Builds and returns the "Format" menu.
388  *
389  * @return a menu
390  */

391 protected JMenu buildFormatMenu() {
392     JMenu menu = MenuUtils.readMenu("DesignWin.menu_format");
393
394     formatItem =
395     MenuUtils.addToMenu(this, menu, "DesignWin.menu_format_format");
396     borderItem =
397     MenuUtils.addToMenu(this, menu, "DesignWin.menu_format_border");
398     menu.addSeparator();
399     boundsItem =
400     MenuUtils.addToMenu(this, menu, "DesignWin.menu_format_bounds");
401     menu.add(alignSubmenu = MenuUtils.buildAlignMenu(this, null));
402     menu.add(sizeSubmenu = MenuUtils.buildSizeMenu(this, null));
403     menu.addSeparator();
404     defaultFormatItem =
405     MenuUtils.addToMenu(this, menu, "DesignWin.menu_format_default");
406
407     return menu;
408 }
409
410 /**
411  * Builds and returns the "Database" menu.
412  *
413  * @return a menu
414  */

415 protected JMenu buildDatabaseMenu() {
416     JMenu menu = MenuUtils.readMenu("DesignWin.menu_database");
417
418     tableJoinItem =
419     MenuUtils.addToMenu(this, menu, "DesignWin.menu_database_linker");
420     menu.addSeparator();
421 // MenuUtils.addToMenu(this, menu, "DesignWin.menu_database_join");
422
// menu.addSeparator();
423
sqlQueryTextItem =
424     MenuUtils.addToMenu(this, menu, "DesignWin.menu_database_sql");
425     menu.addSeparator();
426     connectionItem =
427     MenuUtils.addToMenu(this, menu, "DesignWin.menu_connection");
428
429     return menu;
430 }
431
432 /**
433  * Builds and returns the "Report" menu.
434  *
435  * @return a menu
436  */

437 protected JMenu buildReportMenu() {
438     JMenu menu = MenuUtils.readMenu("DesignWin.menu_report");
439
440     runItem = MenuUtils.addToMenu(this, menu, "DesignWin.menu_report_run");
441     exportItem =
442     MenuUtils.addToMenu(this, menu, "DesignWin.menu_report_export");
443     menu.addSeparator();
444     selectRecordsItem =
445     MenuUtils.addToMenu(this, menu, "DesignWin.menu_report_select");
446     sortByItem =
447     MenuUtils.addToMenu(this, menu, "DesignWin.menu_report_sort");
448     groupByItem =
449     MenuUtils.addToMenu(this, menu, "DesignWin.menu_report_group");
450     MenuUtils.addToMenu(this, menu, "DesignWin.menu_report_start_formula");
451     menu.addSeparator();
452     MenuUtils.addToMenu(this, menu, "DesignWin.menu_report_scripting_langs");
453     MenuUtils.addToMenu(this, menu, "DesignWin.menu_report_summary");
454
455     return menu;
456 }
457
458 /**
459  * Builds and returns the "Help" menu.
460  *
461  * @return a menu
462  */

463 protected JMenu buildHelpMenu() {
464     JMenu menu = MenuUtils.readMenu("DesignWin.menu_help");
465
466     MenuUtils.addToMenu(this, menu, "DesignWin.menu_help_help");
467     menu.addSeparator();
468     MenuUtils.addToMenu(this, menu, "DesignWin.menu_help_about");
469
470     return menu;
471 }
472
473 /**
474  * Builds the sections and adds them to the section container.
475  */

476 protected void buildSections() {
477     rootPaneContainer.getContentPane().setLayout(new BorderLayout());
478
479     sectionWidgets = new ArrayList();
480     sectionContainer = new JLayeredPane();
481     sectionContainer.setLayout(new DesignWinLayout());
482
483     // Can't just call report.each_section because we want to append
484
// '(a)', '(b)', etc. if there is more than one section in the group.
485
buildSectionsInArea(report.headers());
486     buildSectionsInArea(report.pageHeaders());
487
488     // Add headers for each group.
489
for (Iterator iter = report.groups(); iter.hasNext(); ) {
490     Group g = (Group)iter.next();
491     buildSectionsInArea(g.headers());
492     }
493
494     buildSectionsInArea(report.details());
495
496     // Add footers for each group, where the groups are in reverse order.
497
for (Iterator iter = report.groupsReversed(); iter.hasNext(); ) {
498     Group g = (Group)iter.next();
499     buildSectionsInArea(g.footers());
500     }
501
502     buildSectionsInArea(report.footers());
503     buildSectionsInArea(report.pageFooters());
504
505     renameSectionWidgets(); // Muck with section names (e.g., add " (a)")
506

507     // Put sectionContainer within scroller and add scroller to content
508
// pane.
509
int width = SectionWidget.LHS_WIDTH
510     + (int)report.getPaperFormat().getWidth();
511     scroller = new JScrollPane(sectionContainer);
512     scroller.setPreferredSize(new Dimension(width + 4, 400));
513     rootPaneContainer.getContentPane().add(scroller, BorderLayout.CENTER);
514 }
515
516 /**
517  * Builds the section widgets for the sections in an area and adds them to the
518  * section container. We name the widgets with a separate call to {@link
519  * #renameSectionWidgets}.
520  * <p>
521  * We also start observing each section. Though our caller is called more than
522  * once, it is OK to call addObserver() on an Observable multiple times.
523  *
524  * @param area contains sections
525  */

526 protected void buildSectionsInArea(SectionArea area) {
527     for (Iterator iter = area.iterator(); iter.hasNext(); ) {
528     Section sect = (Section)iter.next();
529     sect.addObserver(this); // Start observing changes
530

531     SectionWidget sw = new SectionWidget(this, sect, "");
532     sectionWidgets.add(sw);
533
534     // Add to palette layer (one above default layer) because we want
535
// to move field widgets below section widgets temporarily at the
536
// end of a drag (see putDown()).
537
sectionContainer.add(sw, JLayeredPane.PALETTE_LAYER);
538     }
539 }
540
541 /**
542  * Recalculates section names for all sections in the report. Calls {@link
543  * #renameSectionWidgetsIn} for each group of sections.
544  */

545 protected void renameSectionWidgets() {
546     renameSectionWidgetsIn(report.headers(), I18N.get("Report.report_header"),
547                null);
548     renameSectionWidgetsIn(report.pageHeaders(),
549                I18N.get("Report.page_header"), null);
550     int i = 1;
551     for (Iterator iter = report.groups(); iter.hasNext(); ++i) {
552     Group g = (Group)iter.next();
553     renameSectionWidgetsIn(g.headers(), I18N.get("DesignWin.group") + " #"
554                    + i + ' ' + I18N.get("DesignWin.header"), g);
555     }
556     renameSectionWidgetsIn(report.details(), I18N.get("Report.detail"), null);
557     i = 1;
558     for (Iterator iter = report.groups(); iter.hasNext(); ++i) {
559     Group g = (Group)iter.next();
560     renameSectionWidgetsIn(g.footers(), I18N.get("DesignWin.group") + " #"
561                    + i + ' ' + I18N.get("DesignWin.footer"), g);
562     }
563     renameSectionWidgetsIn(report.footers(), I18N.get("Report.report_footer"),
564                null);
565     renameSectionWidgetsIn(report.pageFooters(),
566                I18N.get("Report.page_footer"), null);
567 }
568
569 /**
570  * Recalculates section names for a collection of sections. Called from {@link
571  * #renameSectionWidgets}. Also sets the section's popup menu's first item
572  * text.
573  *
574  * @param area a section area
575  * @param prefix prepended to all section names in the collection
576  * @param group the group containing this section list; may be
577  * <code>null</code>
578  */

579 protected void renameSectionWidgetsIn(SectionArea area, String JavaDoc prefix,
580                       Group group)
581 {
582     SectionWidget firstSectionWidget = null;
583     boolean firstSectionFixed = false;
584     int i = 0;
585     for (Iterator iter = area.iterator(); iter.hasNext(); ++i) {
586     Section s = (Section)iter.next();
587     SectionWidget sw = findSectionWidgetFor(s);
588     if (firstSectionWidget == null) {
589         sw.setDisplayName(prefix);
590         firstSectionWidget = sw;
591     }
592     else {
593         if (!firstSectionFixed) {
594         firstSectionWidget.setDisplayName(prefix + " (a)");
595         firstSectionFixed = true;
596         }
597         sw.setDisplayName(prefix + " (" + (char)('a' + i) + ")");
598     }
599     sw.setPopupName(group == null ? prefix : group.getSelectableName());
600     }
601 }
602
603 /**
604  * Enables or disables menu items based on field and window state.
605  */

606 public void enableMenuItems() {
607     int numSelected = countSelectedFields();
608     boolean someFieldSelected = numSelected > 0;
609     boolean multipleFieldsSelected = numSelected > 1;
610     FieldWidget first = someFieldSelected ? (FieldWidget)selectedFields.get(0)
611     : null;
612
613     DataSource ds = report.getDataSource();
614
615     // Edit menu
616
Section s = (first == null) ? null : first.getSectionWidget().getSection();
617
618     cutItem.setEnabled(someFieldSelected);
619     copyItem.setEnabled(someFieldSelected);
620     pasteItem.setEnabled(!Clipboard.instance().isEmpty());
621     delSelectionItem.setEnabled(someFieldSelected);
622     delGroupItem.setEnabled(someFieldSelected && report.isInsideGroup(s));
623     delSectionItem.setEnabled(someFieldSelected && !report.isOneOfAKind(s));
624
625     // Insert menu
626
if (numSelected == 1) { // One field is selected
627
// Only enable aggregates if the selected field is a field
628
// for which aggregates make sense.
629
aggrItem.setEnabled(first.getField().canBeAggregated());
630     }
631     else
632     aggrItem.setEnabled(false);
633     sectItem.setEnabled(someFieldSelected);
634     subreportItem.setEnabled(ds.canJoinTables());
635
636     // Format menu
637
if (someFieldSelected) {
638     // Only enable if some field is formattable
639
boolean enable = someSelectedFieldUsesFormat();
640     formatItem.setEnabled(enable);
641     }
642     else
643     formatItem.setEnabled(false);
644     borderItem.setEnabled(someFieldSelected);
645     boundsItem.setEnabled(someFieldSelected);
646     alignSubmenu.setEnabled(multipleFieldsSelected);
647     sizeSubmenu.setEnabled(multipleFieldsSelected);
648
649     // Database menu
650
tableJoinItem.setEnabled(ds.canJoinTables());
651     sqlQueryTextItem.setEnabled(ds.isSQLGenerated());
652     connectionItem.setEnabled(ds.isConnectionEditable());
653
654     // Report menu
655
runItem.setEnabled(ds.canRunReports());
656     exportItem.setEnabled(ds.canRunReports());
657     selectRecordsItem.setEnabled(ds.areRecordsSelectable());
658     sortByItem.setEnabled(ds.areRecordsSortable());
659     groupByItem.setEnabled(ds.canGroupRecords());
660 }
661
662 /**
663  * Returns <code>true</code> if there is some selected field that can
664  * be formatted.
665  *
666  * @return <code>true</code> if there is some selected field that can
667  * be formatted
668  */

669 public boolean someSelectedFieldUsesFormat() {
670     for (Iterator iter = selectedFields.iterator(); iter.hasNext(); )
671     if (((FieldWidget)iter.next()).usesFormat())
672         return true;
673     return false;
674 }
675
676
677 String JavaDoc action(String JavaDoc name) {
678     return I18N.get(I18N.MENU_FILE_PREFIX, "DesignWin.menu_" + name
679             + ".action");
680 }
681
682 String JavaDoc action(String JavaDoc menu, String JavaDoc name) {
683     return I18N.get(I18N.MENU_FILE_PREFIX, menu + ".menu_" + name + ".action");
684 }
685
686 /**
687  * Handles user actions.
688  */

689 public void actionPerformed(ActionEvent e) {
690     String JavaDoc cmd = e.getActionCommand();
691     if (cmd == null || cmd.length() == 0)
692     return;
693
694     // File menu
695
if (cmd.equals(action("file_new"))) newReport();
696     else if (cmd.equals(action("file_open"))) openReport();
697     else if (cmd.equals(action("file_save"))) saveReport();
698     else if (cmd.equals(action("file_save_as"))) saveReportAs();
699     else if (cmd.equals(action("file_close"))) maybeClose();
700     else if (cmd.equals(action("file_quit"))) maybeQuit();
701
702     // Edit menu
703
else if (cmd.equals(action("edit_undo"))) commandHistory.undo();
704     else if (cmd.equals(action("edit_redo"))) commandHistory.redo();
705     else if (cmd.equals(action("edit_cut")))
706     commandHistory.perform(new CutCommand(this, selectedFields));
707     else if (cmd.equals(action("edit_copy"))) copySelectedFields();
708     else if (cmd.equals(action("edit_paste"))) paste();
709     else if (cmd.equals(action("edit_del_fields"))) deleteSelectedFields();
710     else if (cmd.equals(action("edit_del_group"))) {
711     FieldWidget fw = (FieldWidget)selectedFields.get(0);
712     deleteGroupContaining(fw.getSectionWidget().getSection());
713     }
714     else if (cmd.equals(action("edit_del_section"))) {
715     FieldWidget fw = (FieldWidget)selectedFields.get(0);
716     deleteSection(fw.getSectionWidget().getSection());
717     }
718
719     // Insert menu
720
else if (cmd.equals(action("insert_column")))
721     openFieldPickerWin(FieldPickerWin.REPORT_DATABASE_FIELDS);
722     else if (cmd.equals(action("insert_text"))) placeNewTextField();
723     else if (cmd.equals(action("insert_formula")))
724     openFieldPickerWin(FieldPickerWin.FORMULAS);
725     else if (cmd.equals(action("insert_usercol")))
726     openFieldPickerWin(FieldPickerWin.USERCOLS);
727     else if (cmd.equals(action("insert_param")))
728     openFieldPickerWin(FieldPickerWin.PARAMETERS);
729     else if (cmd.equals(action("insert_aggr"))) openAggregateWin();
730     else if (cmd.equals(action("insert_special")))
731     openFieldPickerWin(FieldPickerWin.SPECIAL_FIELDS);
732     else if (cmd.equals(action("insert_image"))) createImageField();
733 // else if (cmd.equals(action("insert_line"))) placeNewLine();
734
else if (cmd.equals(action("insert_group"))) openNewGroupWin();
735     else if (cmd.equals(action("insert_section"))) insertSection();
736     else if (cmd.equals(action("insert_subreport"))) insertSubreport();
737
738     // Format menu
739
else if (cmd.equals(action("format_format"))) openFormatWin(0);
740     else if (cmd.equals(action("format_border"))) openFormatWin(1);
741     else if (cmd.equals(action("format_bounds"))) openBoundsWin();
742     else if (cmd.equals(action("format_default"))) openDefaultFormatWin();
743
744     // Format/Align submenu
745
else if (cmd.equals(action("Align", "tops"))) align(ALIGN_TOP);
746     else if (cmd.equals(action("Align", "middles"))) align(ALIGN_MIDDLE);
747     else if (cmd.equals(action("Align", "bottoms"))) align(ALIGN_BOTTOM);
748     else if (cmd.equals(action("Align", "lefts"))) align(ALIGN_LEFT);
749     else if (cmd.equals(action("Align", "centers"))) align(ALIGN_CENTER);
750     else if (cmd.equals(action("Align", "rights"))) align(ALIGN_RIGHT);
751     else if (cmd.equals(action("Align", "snap"))) align(ALIGN_SNAP_TO_GRID);
752
753     // Format/Size submenu
754
else if (cmd.equals(action("Size", "same_width"))) size(SIZE_SAME_WIDTH);
755     else if (cmd.equals(action("Size", "same_height"))) size(SIZE_SAME_HEIGHT);
756     else if (cmd.equals(action("Size", "same_size"))) size(SIZE_SAME_SIZE);
757
758     // Database menu
759
else if (cmd.equals(action("database_linker"))) openVisTableWin();
760     else if (cmd.equals(action("database_sql"))) showSQL();
761     else if (cmd.equals(action("connection"))) openDbConnWin(false);
762
763     // Report menu
764
else if (cmd.equals(action("report_run"))) runReport();
765     else if (cmd.equals(action("report_export"))) exportReport();
766     else if (cmd.equals(action("report_select"))) openWhereClauseEditor();
767     else if (cmd.equals(action("report_sort"))) openSortWin();
768     else if (cmd.equals(action("report_group"))) openGroupWin();
769     else if (cmd.equals(action("report_start_formula"))) openStartupScriptEditor();
770     else if (cmd.equals(action("report_scripting_langs"))) openScriptingWin();
771     else if (cmd.equals(action("report_summary"))) openDescripWin();
772
773     // Help menu
774
else if (cmd.equals(action("help_help"))) help();
775     else if (cmd.equals(action("help_about"))) about();
776
777     // Paper size menu
778
else if (cmd.equals(action("MenuUtils", "paper_size_portrait")))
779     changePaperOrientation(PaperFormat.PORTRAIT);
780     else if (cmd.equals(action("MenuUtils", "paper_size_landscape")))
781     changePaperOrientation(PaperFormat.LANDSCAPE);
782     else {
783     PaperFormat p =
784         PaperFormat.get(report.getPaperFormat().getOrientation(), cmd);
785     changePaperSize(p);
786     }
787 }
788
789 protected void changePaperOrientation(int orientation) {
790     changePaperSize(PaperFormat.get(orientation,
791                     report.getPaperFormat().getName()));
792 }
793
794 protected void changePaperSize(PaperFormat p) {
795     if (p != null) {
796     performCommand(new PaperSizeCommand(report, this, p));
797     // The paper size menu gets updated as a side effect of the
798
// command's call to paperSizeChanged().
799
}
800 }
801
802 /**
803  * Update paper orientation and size menus.
804  */

805 public void updatePaperSizeMenu(PaperFormat p) {
806     paperSizeSubmenu.getItem(p.getOrientation() == PaperFormat.PORTRAIT
807                  ? 0 : 1)
808     .setSelected(true);
809     int i = 3;
810     for (Iterator iter = PaperFormat.names(); iter.hasNext(); ++i) {
811     String JavaDoc name = (String JavaDoc)iter.next();
812     if (name.equals(p.getName()))
813         paperSizeSubmenu.getItem(i).setSelected(true);
814     }
815 }
816
817 public void paperSizeChanged(PaperFormat p) {
818     for (Iterator iter = sectionWidgets.iterator(); iter.hasNext(); )
819     ((SectionWidget)iter.next()).paperSizeChanged();
820
821     Dimension d = new Dimension(SectionWidget.LHS_WIDTH
822                 + (int)report.getPaperFormat().getWidth(),
823                 sectionContainer.getHeight());
824     sectionContainer.setPreferredSize(d);
825     sectionContainer.invalidate();
826     rootPaneContainer.getRootPane().validate();
827
828     updatePaperSizeMenu(p);
829 }
830
831 public Frame getFrame() { return frame; }
832
833 public void invalidate() { rootPaneContainer.getRootPane().invalidate(); }
834
835 public Report getReport() { return report; }
836
837 /**
838  * Creates a new report in a new design window.
839  */

840 protected void newReport() {
841     new DesignWin(null); // Open a new window
842
}
843
844 /**
845  * Opens an existing report in a new design window.
846  */

847 protected void openReport() {
848     int returnVal = getChooser().showOpenDialog(frame);
849     if (returnVal == JFileChooser.APPROVE_OPTION)
850     new DesignWin(getChooser().getSelectedFile());
851 }
852
853 /**
854  * Saves the current report.
855  */

856 protected void saveReport() {
857     if (reportFilePath == null)
858     saveReportAs();
859     else
860     writeReportFile(reportFilePath);
861 }
862
863 /**
864  * Saves the current report in a different file.
865  */

866 protected void saveReportAs() {
867     int returnVal = getChooser().showSaveDialog(frame);
868     if (returnVal == JFileChooser.APPROVE_OPTION) {
869     reportFilePath = getChooser().getSelectedFile().getPath();
870     writeReportFile(reportFilePath);
871     }
872 }
873
874 /**
875  * Writes the current report to the specified file. Also tells the
876  * command history the report has been saved so it knows how to report
877  * if any changes have been made from this point on.
878  *
879  * @param fileName a file name
880  */

881 protected void writeReportFile(String JavaDoc fileName) {
882     report.writeFile(fileName);
883     commandHistory.setBaseline();
884 }
885
886 /**
887  * Exports the report output using one of the layout engines.
888  */

889 protected void exportReport() {
890     new ExportWin(getFrame(), report);
891 }
892
893 /**
894  * Saves the report if it is changed (some command has been performed) and
895  * closes the current design window. If there are no more open design
896  * windows, exist the application.
897  */

898 protected void maybeClose() {
899     if (commandHistory.isChanged()) {
900     String JavaDoc str = I18N.get("DesignWin.save_question");
901     switch (JOptionPane.showConfirmDialog(frame, str)) {
902     case JOptionPane.YES_OPTION:
903         saveReport();
904     case JOptionPane.NO_OPTION:
905         break;
906     case JOptionPane.CANCEL_OPTION:
907         return; // Don't close window
908
}
909     }
910     closeMe();
911     Designer.deleteWindow(this);
912 }
913
914 /**
915  * Runs and displays the report.
916  */

917 protected void runReport() {
918     report.setLayoutEngine(new SwingLE());
919     report.run();
920 }
921
922 /**
923  * Returns the number of selected fields.
924  *
925  * @return the number of selected fields
926  */

927 int countSelectedFields() {
928     return selectedFields.size();
929 }
930
931 /**
932  * Hands each field widget to the specified {@link FieldWidgetWalker}.
933  *
934  * @param perambulator a field widget walker
935  */

936 void withWidgetsDo(FieldWidgetWalker perambulator) {
937     for (Iterator iter = sectionWidgets.iterator(); iter.hasNext(); ) {
938     SectionWidget sw = (SectionWidget)iter.next();
939     Object JavaDoc[] kids = sw.fieldPanel.getComponents();
940     for (int i = 0; i < kids.length; ++i) {
941         FieldWidget fw = FieldWidget.findFieldWidgetOwning(kids[i]);
942         if (fw != null)
943         perambulator.step(fw);
944     }
945     }
946 }
947
948 /**
949  * Hands each selected field widget's field to the specified {@link
950  * FieldWalker}.
951  *
952  * @param perambulator a field walker
953  */

954 void withSelectedFieldsDo(FieldWalker perambulator) {
955     for (Iterator iter = selectedFields.iterator(); iter.hasNext(); )
956     perambulator.step(((FieldWidget)iter.next()).getField());
957 }
958
959 /**
960  * Deletes the group that contains the specified section.
961  *
962  * @param section a report section
963  */

964 void deleteGroupContaining(Section section) {
965     Group group = report.findGroup(section);
966     if (group != null)
967     commandHistory.perform(new DeleteGroupCommand(this, report, group));
968 }
969
970 /**
971  * Inserts a new section below the section containing the first selected
972  * field widget. Only called when at least one widget is selected.
973  */

974 void insertSection() {
975     Field f = firstSelectedFieldWidget().getField();
976     if (f != null)
977     insertSectionBelow(f.getSection());
978 }
979
980 /**
981  * Inserts a new section below the specified section.
982  *
983  * @param s a report section
984  */

985 void insertSectionBelow(Section s) {
986     commandHistory.perform(new NewSectionCommand(this, report, s));
987 }
988
989 /**
990  * Inserts a section widget at the specified position in the list. Also starts
991  * observing the section and renames all section widgets (adding "(a)", for
992  * example. Called from {@link NewSectionCommand#perform}.
993  *
994  * @param sw the section widget to insert
995  * @param putAfter <var>sw</var> goes after this widget; may be
996  * <code>null</code>
997  */

998 public void insertSectionWidgetAfter(SectionWidget sw, SectionWidget putAfter)
999 {
1000    int insertIndex = sectionWidgets.indexOf(putAfter);
1001    sectionWidgets.add(insertIndex + 1, sw);
1002
1003    // Add to palette layer (one above default layer) because
1004
// we want to move field widgets below section widgets
1005
// temporarily at the end of a drag (see putDown()).
1006
sectionContainer.add(sw, JLayeredPane.PALETTE_LAYER, insertIndex + 1);
1007
1008    sw.getSection().addObserver(this);
1009    renameSectionWidgets(); // Muck with names (e.g., add " (a)")
1010
}
1011
1012/**
1013 * Deletes the specified section. Does nothing if this section is the only
1014 * one of its kind. (This method should only be called if the section is
1015 * not one-of-a-kind. No harm done if you do, though.)
1016 *
1017 * @param s a report section
1018 */

1019public void deleteSection(Section s) {
1020    if (s != null && !report.isOneOfAKind(s))
1021    commandHistory.perform(new DeleteSectionCommand(this, report, s));
1022}
1023
1024/**
1025 * Deletes a section from the report and the design window and returns the
1026 * section widget <em>above</em> the section's. If <var>s</var> is the first
1027 * section in the report, returns <code>null</code>. Called from commands;
1028 * don't call this yourself. Insetad call {@link #deleteSection}.
1029 *
1030 * @param s the section to delete
1031 * @return the section widget above the section's, or <code>null</code>
1032 * if there is none
1033 */

1034public SectionWidget doDeleteSection(Section s) {
1035    SectionWidget sw = findSectionWidgetFor(s);
1036    int index = sectionWidgets.indexOf(sw);
1037    SectionWidget widgetBefore = (index == 0) ? null
1038    : (SectionWidget)sectionWidgets.get(index - 1);
1039
1040    s.deleteObserver(this);
1041    report.removeSection(s);
1042    sectionContainer.remove(sw);
1043    sectionWidgets.remove(sw);
1044    renameSectionWidgets();
1045
1046    return widgetBefore;
1047}
1048
1049/**
1050 * Opens the dialog that starts the process of inserting a sub-report.
1051 */

1052protected void insertSubreport() {
1053    new SubreportWin(this, report);
1054}
1055
1056/**
1057 * Rebuilds the group sections and redisplays the report.
1058 */

1059public void rebuildGroups() {
1060    deselectAll();
1061    rootPaneContainer.getContentPane().remove(scroller);
1062    buildSections();
1063    if (frame != null)
1064    frame.pack();
1065}
1066
1067/**
1068 * Creates and adds a new text field to the first section of the page header.
1069 *
1070 * @param x where to place the title
1071 * @param width how wide it should be
1072 * @param title the string to display
1073 * @return the newly-created widget
1074 */

1075public FieldWidget addTitleField(int x, int width, String JavaDoc title) {
1076    Section s = report.getFirstSectionByArea(SectionArea.PAGE_HEADER);
1077
1078    // Create the field.
1079
Field f = Field.create(null, report, s, "text", title, true);
1080    jimm.datavision.field.Rectangle b = f.getBounds();
1081    b.setBounds(x, 0, width, Field.DEFAULT_HEIGHT);
1082
1083    // Make the field underlined and bold.
1084
f.getFormat().setBold(true);
1085    f.getFormat().setUnderline(true);
1086
1087    // Add the field to the report section.
1088
s.addField(f);
1089
1090    // Create widget and add to section widget.
1091
TextFieldWidget tfw = new TextFieldWidget(null, f);
1092    tfw.moveToSection(findSectionWidgetFor(s));
1093    return tfw;
1094}
1095
1096/**
1097 * Aligns the selected fields to the first selected field (chronologically
1098 * speaking).
1099 *
1100 * @param which alignment constant.
1101 */

1102protected void align(int which) {
1103    if (selectedFields.isEmpty())
1104    return;
1105
1106    // Align the widgets based on the position of the first selected field.
1107
CompoundCommand cmd =
1108    new CompoundCommand(I18N.get("FieldAlignCommand.name"));
1109    Field first = firstSelectedFieldWidget().getField();
1110    for (Iterator iter = selectedFields.iterator(); iter.hasNext(); )
1111    cmd.add(new FieldAlignCommand((FieldWidget)iter.next(), which, first));
1112
1113    commandHistory.perform(cmd);
1114}
1115
1116/**
1117 * Resize the selected fields based on the first selected field
1118 * (chronologically speaking) and the specified resize (width, height, both).
1119 *
1120 * @param which size constant
1121 */

1122protected void size(int which) {
1123    if (selectedFields.isEmpty())
1124    return;
1125
1126    // Resize the widgets based on the position of the first selected field.
1127
CompoundCommand cmd =
1128    new CompoundCommand(I18N.get("FieldResizeCommand.name"));
1129    Field first = firstSelectedFieldWidget().getField();
1130    for (Iterator iter = selectedFields.iterator(); iter.hasNext(); )
1131    cmd.add(new FieldResizeCommand((FieldWidget)iter.next(), which,
1132                       first));
1133
1134    commandHistory.perform(cmd);
1135}
1136
1137/**
1138 * Returns first selected field widget (chronologically speaking). May
1139 * return <code>null</code> if no fields are selected
1140 *
1141 * @return field widget selected the earliest, or <code>null</code> if
1142 * no fields are selected
1143 */

1144FieldWidget firstSelectedFieldWidget() {
1145    return selectedFields.isEmpty()
1146    ? null : (FieldWidget)selectedFields.get(0);
1147}
1148
1149/**
1150 * Selects a field widget, possibly deselecting all others everywhere.
1151 * Called from section widget.
1152 *
1153 * @param fieldWidget a field widget
1154 * @param makeSelected new selection state
1155 * @param deselectOthers if <code>true</code>, all other fields in all
1156 * sections are deselected first
1157 */

1158public void select(FieldWidget fieldWidget, boolean makeSelected,
1159        boolean deselectOthers)
1160{
1161    if (deselectOthers)
1162    deselectAll();
1163
1164    fieldWidget.doSelect(makeSelected);
1165    if (makeSelected) {
1166    if (!selectedFields.contains(fieldWidget)) // Don't add it twice
1167
selectedFields.add(fieldWidget);
1168    }
1169    else {
1170    selectedFields.remove(fieldWidget);
1171    }
1172
1173    enableMenuItems();
1174}
1175
1176/**
1177 * Deselect all fields. Called from {@link SectionWidget#deselectAll}.
1178 */

1179public void deselectAll() {
1180    for (Iterator iter = selectedFields.iterator(); iter.hasNext(); )
1181    ((FieldWidget)iter.next()).doSelect(false);
1182    selectedFields.clear();
1183
1184    enableMenuItems();
1185}
1186
1187/**
1188 * Copies the selected fields to the clipboard. We need to create {@link
1189 * jimm.datavision.gui.cmd.Pasteable} objects.
1190 */

1191protected void copySelectedFields() {
1192    ArrayList pasteables = new ArrayList();
1193    for (Iterator iter = selectedFields.iterator(); iter.hasNext(); )
1194    pasteables.add(new FieldClipping((FieldWidget)iter.next()));
1195    Clipboard.instance().setContents(pasteables);
1196
1197    pasteItem.setEnabled(true);
1198}
1199
1200protected void paste() {
1201    CompoundCommand cmd = new CompoundCommand(I18N.get("PasteCommand.name"));
1202    if (selectedFields.size() > 0)
1203    cmd.add(new DeleteCommand(this, selectedFields));
1204    cmd.add(new PasteCommand(this));
1205    commandHistory.perform(cmd);
1206}
1207
1208/**
1209 * Delete selected fields.
1210 */

1211protected void deleteSelectedFields() {
1212    deleteSelectedFieldsAnd(null);
1213}
1214
1215/**
1216 * Delete specified field and all selected fields.
1217 *
1218 * @param oneMore an additional field to delete; may be <code>null</code>
1219 */

1220protected void deleteSelectedFieldsAnd(FieldWidget oneMore) {
1221    ArrayList fields = new ArrayList(selectedFields);
1222    if (oneMore != null && !fields.contains(oneMore))
1223    fields.add(oneMore);
1224    commandHistory.perform(new DeleteCommand(this, fields));
1225}
1226
1227/**
1228 * Toggles the visibility of all selected fields plus the one passed in.
1229 * Called by a section widget.
1230 *
1231 * @see FieldWidget#doSetVisibility
1232 */

1233void setFieldVisibility(boolean newVisiblity, FieldWidget fw) {
1234    if (selectedFields.isEmpty() && fw == null)
1235    return;
1236
1237    String JavaDoc nameKey = newVisiblity ? "FieldShowCommand.name"
1238    : "FieldHideCommand.name";
1239
1240    CompoundCommand cmd = new CompoundCommand(I18N.get(nameKey));
1241    for (Iterator iter = selectedFields.iterator(); iter.hasNext(); )
1242    cmd.add(new FieldShowHideCommand((FieldWidget)iter.next(), nameKey,
1243                     newVisiblity));
1244    if (fw != null && !selectedFields.contains(fw))
1245    cmd.add(new FieldShowHideCommand(fw, nameKey, newVisiblity));
1246
1247    commandHistory.perform(cmd);
1248}
1249
1250/**
1251 * Asks design window to create and accepts a new text field. Called from
1252 * {@link SectionWidget#createNewTextField}.
1253 *
1254 * @see Designer#createNewTextField
1255 */

1256void createNewTextField(SectionWidget sw, MouseEvent e) {
1257    commandHistory.perform(new NewTextFieldCommand(sw, e));
1258
1259    // Accept the drop
1260
acceptNewTextField();
1261}
1262
1263/**
1264 * Picks up the field widget because field dragging is starting.
1265 * Called from SectionWidget#pickUp.
1266 *
1267 * @param mouseScreenPos the location of the mouse in screen coordinates
1268 */

1269void pickUp(java.awt.Point JavaDoc mouseScreenPos) {
1270    Dimension size = sectionContainer.getBounds().getSize();
1271    sectionContainer.setPreferredSize(size);
1272    sectionContainer.setMinimumSize(size);
1273
1274    for (Iterator iter = selectedFields.iterator(); iter.hasNext(); ) {
1275    FieldWidget fw = (FieldWidget)iter.next();
1276    fw.pickUp(mouseScreenPos);
1277
1278    // Add to the drag layer of our section container.
1279
sectionContainer.add(fw.getComponent(), JLayeredPane.DRAG_LAYER);
1280
1281    // Recalculate bounds relative to the section container.
1282
jimm.datavision.field.Rectangle b = fw.getField().getBounds();
1283    b.setBounds(b.x + SectionWidget.LHS_WIDTH,
1284            b.y + fw.getSectionWidget().getBounds().y,
1285            b.width, b.height);
1286    }
1287}
1288
1289/**
1290 * Puts the dragged field widgets down inside the sections they are floating
1291 * above. Called from {@link SectionWidget#putDown}.
1292 *
1293 * @param f the field widget being dragged; all other selected fields
1294 * have been dragged along with it
1295 * @param origScreenPos the original location of the field in screen
1296 * coordinates
1297 * @param mouseScreenPos the current mouse position in screen coordinates;
1298 * note
1299 */

1300void putDown(FieldWidget f, java.awt.Point JavaDoc origScreenPos,
1301         java.awt.Point JavaDoc mouseScreenPos)
1302{
1303    // Move all dragged fields under everything else so getComponentAt()
1304
// will not return this field.
1305
for (Iterator iter = selectedFields.iterator(); iter.hasNext(); )
1306    sectionContainer.setLayer(((FieldWidget)iter.next()).getComponent(),
1307                  JLayeredPane.DEFAULT_LAYER.intValue());
1308
1309    CompoundCommand cmd =
1310    new CompoundCommand(I18N.get("FieldMoveCommand.name"));
1311
1312    // Move to new section. Each field may be dropped into a different
1313
// section.
1314
for (Iterator iter = selectedFields.iterator(); iter.hasNext(); ) {
1315    FieldWidget fw = (FieldWidget)iter.next();
1316    SectionWidget sw =
1317        getSectionWidgetUnder(fw.getComponent().getLocationOnScreen());
1318    if (sw == null) // Field snaps back to orig pos if sw is null
1319
fw.snapBack();
1320    else
1321        cmd.add(new FieldMoveCommand(fw, sw));
1322    }
1323
1324    if (cmd.numCommands() > 0)
1325    commandHistory.perform(cmd);
1326}
1327
1328/**
1329 * Starts stretching all selected fields. Called from {@link
1330 * SectionWidget#startStretching}.
1331 *
1332 * @param mouseScreenPos the location of the mouse in screen coordinates
1333 */

1334void startStretching(java.awt.Point JavaDoc mouseScreenPos) {
1335    for (Iterator iter = selectedFields.iterator(); iter.hasNext(); ) {
1336    FieldWidget fw = (FieldWidget)iter.next();
1337    fw.startStretching(mouseScreenPos);
1338    }
1339}
1340
1341/**
1342 * Tells each field to stop stretching and creates a command that will undo
1343 * all that stretching. Called from {@link SectionWidget#stopStretching}.
1344 *
1345 * @param f the field widget being dragged; all other selected fields
1346 * have been dragged along with it
1347 * @param origBounds the field's original bounds
1348 */

1349void stopStretching(FieldWidget f, jimm.datavision.field.Rectangle origBounds)
1350{
1351    CompoundCommand cmd =
1352    new CompoundCommand(I18N.get("FieldStretchCommand.name"));
1353
1354    for (Iterator iter = selectedFields.iterator(); iter.hasNext(); ) {
1355    FieldWidget fw = (FieldWidget)iter.next();
1356    cmd.add(new FieldStretchCommand(fw, origBounds));
1357    fw.stopStretching();
1358    }
1359
1360    if (cmd.numCommands() > 0)
1361    commandHistory.perform(cmd);
1362}
1363
1364/**
1365 * Returns the section widget under the mouse. Returns <code>null</code>
1366 * unless the mouse is over a section field panel (the white area on
1367 * which fields belong).
1368 *
1369 * @param screenPos a position in screen coordinates
1370 * @return the SectionWidget under the mouse
1371 */

1372protected SectionWidget getSectionWidgetUnder(java.awt.Point JavaDoc screenPos) {
1373    // Translate screenPos to sectionContainer coords
1374
java.awt.Point JavaDoc scScreenPos = sectionContainer.getLocationOnScreen();
1375    java.awt.Point JavaDoc scPos = new java.awt.Point JavaDoc(screenPos.x - scScreenPos.x,
1376                          screenPos.y - scScreenPos.y);
1377
1378    if (scPos.x < SectionWidget.LHS_WIDTH) // Reject if in LHS name
1379
return null;
1380
1381    // We've landed on a section field panel, a field in the section, or a
1382
// section name label. Crawl up the parent hierarchy until we find
1383
// first the section field panel (insuring we are in the right place)
1384
// and then the section.
1385
Component c = sectionContainer.getComponentAt(scPos);
1386    while (c != null && !(c instanceof SectionWidget))
1387    c = c.getParent();
1388    return (SectionWidget)c;
1389}
1390
1391/**
1392 * Drags the selected field widgets a few pixels. Called from section that
1393 * contains field being dragged.
1394 *
1395 * @param action a {@link FieldWidget}<code>.ACTION_*</code> constant
1396 * @param mouseScreenPos mouse screen position
1397*/

1398protected void dragSelectedWidgets(int action, java.awt.Point JavaDoc mouseScreenPos) {
1399    for (Iterator iter = selectedFields.iterator(); iter.hasNext(); )
1400    ((FieldWidget)iter.next()).doDrag(action, mouseScreenPos);
1401}
1402
1403/**
1404 * Opens a new or existing field picker window.
1405 *
1406 * @param startingType the index of the starting type to display
1407 */

1408protected void openFieldPickerWin(int startingType) {
1409    new FieldPickerWin(this, report, startingType);
1410}
1411
1412/**
1413 * Opens a new or existing field aggregate window. We should
1414 * only get here if there is exactly one selected field.
1415 */

1416protected void openAggregateWin() {
1417    new AggregatesWin(this, (FieldWidget)selectedFields.get(0));
1418}
1419
1420/**
1421 * Opens a dialog that asks the user to select an image file. Creates an
1422 * image in the report header.
1423 */

1424protected void createImageField() {
1425    String JavaDoc url =
1426    new AskStringDialog(frame, I18N.get("DesignWin.image_url_title"),
1427                I18N.get("DesignWin.image_url_label")).getString();
1428    if (url != null) {
1429    Section s = report.getFirstSectionByArea(SectionArea.REPORT_HEADER);
1430    NewImageFieldCommand cmd =
1431        new NewImageFieldCommand(findSectionWidgetFor(s), url);
1432    commandHistory.perform(cmd);
1433    }
1434}
1435
1436/**
1437 * Opens a new or existing new group window.
1438 */

1439protected void openNewGroupWin() {
1440    new NewGroupWin(this, report);
1441}
1442
1443/**
1444 * Sets the flag that tells everyone else that the user wants to place
1445 * a new text field.
1446 */

1447protected void placeNewTextField() {
1448    placingNewTextField = true;
1449    rootPaneContainer.getRootPane().setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
1450}
1451
1452/**
1453 * Returns <code>true</code> if the user is trying to place a new text field.
1454 *
1455 * @return <code>true</code> if the user is trying to place a new text field
1456 */

1457boolean isPlacingNewTextField() {
1458    return placingNewTextField;
1459}
1460
1461/**
1462 * The caller has accepted the new text field.
1463 */

1464void acceptNewTextField() {
1465    placingNewTextField = false;
1466    rootPaneContainer.getRootPane().setCursor(null);
1467}
1468
1469/**
1470 * The caller has rejected the new text field.
1471 */

1472void rejectNewTextField() {
1473    acceptNewTextField();
1474}
1475
1476/**
1477 * Opens a new or existing field format window.
1478 *
1479 * @param whichTab the index of the tab to display when opened
1480 */

1481protected void openFormatWin(int whichTab) {
1482    FieldWidget fw = firstSelectedFieldWidget();
1483    if (fw != null)
1484    new FormatWin(this, fw.getField(), whichTab);
1485}
1486
1487/**
1488 * Opens a new or existing field format window that lets the user edit the
1489 * report's default format and border.
1490 */

1491protected void openDefaultFormatWin() {
1492    new FormatWin(this, report.getDefaultField(), 0);
1493}
1494
1495/**
1496 * Opens a new or existing bounds editor window.
1497 */

1498protected void openBoundsWin() {
1499    FieldWidget fw = firstSelectedFieldWidget();
1500    if (fw != null)
1501    new BoundsWin(this, fw.getField());
1502}
1503
1504/**
1505 * Opens a new or existing visible table joiner window.
1506 */

1507protected void openVisTableWin() {
1508    new VisTableWin(this, report);
1509}
1510
1511/**
1512 * Opens a new or existing where clause editor.
1513 */

1514protected void openWhereClauseEditor() {
1515    new WhereClauseWin(this, report);
1516}
1517
1518/**
1519 * Opens a new or existing sort order window.
1520 */

1521protected void openSortWin() {
1522    new SortWin(this, report);
1523}
1524
1525/**
1526 * Opens a new or existing group order window.
1527 */

1528protected void openGroupWin() {
1529    new GroupWin(this, report);
1530}
1531
1532/**
1533 * Opens a starutp script editor.
1534 */

1535protected void openStartupScriptEditor() {
1536    new StartupScriptEditor(this, report);
1537}
1538
1539/**
1540 * Opens a new or existing report formula language window.
1541 */

1542protected void openScriptingWin() {
1543    new ScriptingWin(this, report.getScripting());
1544}
1545
1546/**
1547 * Opens a new or existing report description (name, title, etc.) window.
1548 */

1549protected void openDescripWin() {
1550    new DescripWin(this, report);
1551}
1552
1553/**
1554 * Opens the help window.
1555 */

1556protected void help() {
1557    HelpWin helpWin = HelpWin.instance();
1558    helpWin.setState(Frame.NORMAL); // De-iconify. Why is this necessary?
1559
helpWin.setVisible(true);
1560    helpWin.toFront();
1561}
1562
1563/**
1564 * Opens the about box.
1565 */

1566protected void about() {
1567    String JavaDoc msg = I18N.get("DesignWin.about_1") + info.Version + "\n"
1568    + I18N.get("DesignWin.about_2") + "\n"
1569    + info.URL + "\n\n"
1570    + info.Copyright + ".\n\n"
1571    + I18N.get("DesignWin.about_3");
1572    JOptionPane.showMessageDialog(null, msg, I18N.get("DesignWin.about_title"),
1573                  JOptionPane.PLAIN_MESSAGE);
1574}
1575
1576/**
1577 * Opens a new or existing database connection info window.
1578 *
1579 * @param modal passed on to dialog constructor
1580 */

1581protected void openDbConnWin(boolean modal) {
1582    new DbConnWin(this, report, modal);
1583}
1584
1585/**
1586 * Opens a new window containing the SQL query text.
1587 */

1588protected void showSQL() {
1589    new SQLQueryWin(frame, report.getDataSource().getQuery().toString());
1590}
1591
1592/**
1593 * Returns the section widget containing the specified section.
1594 *
1595 * @param s section
1596 * @return the section widget containing the section
1597 */

1598public SectionWidget findSectionWidgetFor(Section s) {
1599    for (Iterator iter = sectionWidgets.iterator(); iter.hasNext(); ) {
1600    SectionWidget sw = (SectionWidget)iter.next();
1601    if (sw.section == s)
1602        return sw;
1603    }
1604    return null;
1605}
1606
1607
1608/**
1609 * Snaps the rectangle to the grid.
1610 *
1611 * @param r a rectangle
1612 */

1613public void snapToGrid(jimm.datavision.field.Rectangle r) {
1614    int coord = (int)r.x;
1615    int mod = coord % GRID_SIZE;
1616    if (mod != 0) {
1617    if (mod <= GRID_SIZE / 2)
1618        r.setX(coord - mod);
1619    else
1620        r.setX(coord + GRID_SIZE - mod);
1621    }
1622
1623    coord = (int)r.y;
1624    mod = coord % GRID_SIZE;
1625    if (mod != 0) {
1626    if (mod < GRID_SIZE / 2)
1627        r.setY(coord - mod);
1628    else
1629        r.setY(coord + GRID_SIZE - mod);
1630    }
1631}
1632
1633// Might be using this code for dragging to select multiple fields. It
1634
// should eventually live in a separate file.
1635

1636// class SelectionHandler extends MouseInputAdapter {
1637

1638// protected java.awt.Rectangle rect;
1639
// protected HashSet fields;
1640
// protected JPanel selectionOutline;
1641

1642// public void mousePressed(MouseEvent e) {
1643
// int x = e.getX() - SectionWidget.LHS_WIDTH;
1644
// if (x < 0)
1645
// return;
1646

1647// deselectAll();
1648

1649// int y = e.getY();
1650
// rect = new java.awt.Rectangle(x, y, 0, 0);
1651
// selectionOutline = new JPanel();
1652
// selectionOutline.setBounds(rect);
1653
// rootPaneContainer.getContentPane().add(selectionOutline, 0); // Add to top of visual stack
1654
// }
1655

1656// public void mouseDragged(MouseEvent e) {
1657
// updateSize(e);
1658
// }
1659

1660// public void mouseReleased(MouseEvent e) {
1661
// updateSize(e);
1662
// remove(selectionOutline);
1663
// }
1664

1665// /*
1666
// * Updates the size of the current rectangle, changes selection list, and
1667
// * calls {@link #repaint}. Because rect always has the same origin,
1668
// * translate it if the width or height is negative.
1669
// *
1670
// * For efficiency, specify the painting region using arguments to the
1671
// * {@link #repaint} call.
1672
// */
1673
// void updateSize(MouseEvent e) {
1674
// if (selectionOutline == null)
1675
// return;
1676

1677// int x = e.getX();
1678
// int y = e.getY();
1679
// rect.setSize(x - rect.x, y - rect.y);
1680
// selectionOutline.setSize(x - rect.x, y - rect.y);
1681

1682// // selectFieldsWithin(rect);
1683

1684// // java.awt.Rectangle totalRepaint = rectToDraw.union(previousRectDrawn);
1685
// // repaint(totalRepaint.x, totalRepaint.y,
1686
// // totalRepaint.width, totalRepaint.height);
1687
// }
1688

1689// }
1690

1691}
1692
Popular Tags