1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package org.mlc.swing.layout;
31
32 import java.awt.BorderLayout;
33 import java.awt.Component;
34 import java.awt.Container;
35 import java.awt.Dimension;
36 import java.awt.Frame;
37 import java.awt.event.ActionEvent;
38 import java.awt.event.ActionListener;
39 import java.awt.event.KeyEvent;
40 import java.awt.event.WindowAdapter;
41 import java.awt.event.WindowEvent;
42 import java.io.File;
43 import java.io.FileOutputStream;
44 import java.util.ArrayList;
45 import java.util.HashMap;
46 import java.util.HashSet;
47 import java.util.Iterator;
48 import java.util.List;
49 import java.util.Map;
50
51 import javax.swing.JCheckBoxMenuItem;
52 import javax.swing.JDialog;
53 import javax.swing.JFileChooser;
54 import javax.swing.JFrame;
55 import javax.swing.JMenu;
56 import javax.swing.JMenuBar;
57 import javax.swing.JMenuItem;
58 import javax.swing.JOptionPane;
59 import javax.swing.JPanel;
60 import javax.swing.JScrollPane;
61 import javax.swing.JTabbedPane;
62 import javax.swing.JTextArea;
63 import javax.swing.KeyStroke;
64 import javax.swing.WindowConstants;
65 import javax.swing.filechooser.FileFilter;
66
67 import com.jgoodies.forms.factories.Borders;
68
69 /***
70 * This is the frame that enables you to build a layout. The principle component
71 * is the FormEditor panel.
72 *
73 * @author Michael Connor mlconnor@yahoo.com
74 */
75 @SuppressWarnings("serial")
76 public class LayoutFrame extends JFrame
77 {
78 LayoutConstraintsManager constraintsManager;
79
80 JMenuBar menuBar = new JMenuBar();
81
82 JMenu actionMenu = new JMenu("File");
83 JMenuItem saveXML = new JMenuItem("Save As");
84 JMenuItem viewCode = new JMenuItem("View Code");
85 JMenuItem exit = new JMenuItem("Exit");
86
87 JMenu viewMenu = new JMenu("View");
88 JCheckBoxMenuItem viewDebugMenu = new JCheckBoxMenuItem("Debug Frame");
89
90 final JFileChooser fileChooser = new JFileChooser();
91
92 Map<ContainerLayout, FormEditor> editors = new HashMap<ContainerLayout, FormEditor>();
93
94 JTabbedPane tabs = new JTabbedPane();
95
96 Map<ContainerLayout, Component> layoutToTab = new HashMap<ContainerLayout, Component>();
97
98 List<ContainerLayout> newLayouts = new ArrayList<ContainerLayout>();
99
100
101 public JFrame dframe = null;
102
103 /*** Creates a new instance of Class */
104 public LayoutFrame(LayoutConstraintsManager constraintsManager)
105 {
106 super("FormLayoutMaker - Constraints Editor");
107
108 if (constraintsManager.getLayouts().size() == 0)
109 throw new RuntimeException(
110 "You must register at least one container by calling LayoutConstraintsManager.setLayout(String name, Container container) before instantiating a LayoutFrame");
111
112 setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
113 this.constraintsManager = constraintsManager;
114
115 actionMenu.setMnemonic('F');
116 saveXML.setMnemonic('A');
117 saveXML.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A,
118 KeyEvent.CTRL_MASK));
119 viewCode.setMnemonic('V');
120 viewCode.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
121 KeyEvent.CTRL_MASK));
122 exit.setMnemonic('X');
123 actionMenu.add(saveXML);
124 actionMenu.add(viewCode);
125 actionMenu.add(exit);
126
127 viewDebugMenu.setMnemonic('D');
128 viewDebugMenu.setSelected(UserPrefs.getPrefs().showDebugPanel());
129 viewMenu.add(viewDebugMenu);
130
131
132 viewDebugMenu.setEnabled(false);
133
134 menuBar.add(actionMenu);
135 menuBar.add(viewMenu);
136 this.setJMenuBar(menuBar);
137
138 fileChooser.setFileFilter(new XmlFileFilter());
139
140 this.addWindowListener(new WindowAdapter()
141 {
142 public void windowClosing(WindowEvent e)
143 {
144 exitApplication();
145 }
146 });
147
148 exit.addActionListener(new ActionListener()
149 {
150 public void actionPerformed(ActionEvent e)
151 {
152 exitApplication();
153 }
154 });
155
156 viewDebugMenu.addActionListener(new ActionListener()
157 {
158 public void actionPerformed(ActionEvent e)
159 {
160 LayoutFrame.this.enableDebugPreview(viewDebugMenu.isSelected());
161 }
162 });
163
164 List<ContainerLayout> layouts = constraintsManager.getLayouts();
165
166 for (int index = 0; index < layouts.size(); index++)
167 {
168 ContainerLayout containerLayout = layouts.get(index);
169 Container container = constraintsManager.getContainer(containerLayout);
170 if (container == null)
171 throw new RuntimeException(
172 "A container with name "
173 + containerLayout.getName()
174 + " was found in the contstraints file but was not found in the container");
175 addContainerLayout(containerLayout, container);
176 }
177
178 getContentPane().setLayout(new BorderLayout(3, 3));
179 getContentPane().add(tabs, BorderLayout.CENTER);
180
181
182 viewCode.addActionListener(new ActionListener()
183 {
184 public void actionPerformed(ActionEvent e)
185 {
186 List<ContainerLayout> layouts = LayoutFrame.this.constraintsManager
187 .getLayouts();
188 StringBuffer declarationBuffer = new StringBuffer(
189 "// here are declarations for the controls you created\n");
190 StringBuffer setLayoutBuffer = new StringBuffer(
191 "// here is where we load the layout constraints. "
192 + "change the xml filename!!!\norg.mlc.swing.layout.LayoutConstraintsManager layoutConstraintsManager "
193 + "= \n org.mlc.swing.layout.LayoutConstraintsManager.getLayoutConstraintsManager(\n "
194 + "this.getClass().getResourceAsStream(\"yourConstraintFile.xml\"));\n");
195 /*** @todo KBR generate compilable code */
196
197
198 StringBuffer addBuffer = new StringBuffer(
199 "// here we add the controls to the container. you may\n// "
200 + "need to change the name of panel\n");
201
202 StringBuffer importBuffer = new StringBuffer();
203 importBuffer.append("import org.mlc.swing.layout.*;\n");
204 HashSet<String> importSet = new HashSet<String> ();
205
206 StringBuffer declBuffer = new StringBuffer();
207 declBuffer.append("// here are declarations for the controls you created\n");
208
209 StringBuffer addBuffer2 = new StringBuffer();
210 addBuffer2.append("// here we add the controls to the container.\n");
211
212 StringBuffer confBuffer = new StringBuffer();
213 confBuffer.append("// control configuration\n");
214
215 for (int index = 0; index < layouts.size(); index++)
216 {
217 ContainerLayout containerLayout = layouts.get(index);
218 FormEditor editor = editors.get(containerLayout);
219 Map<Component, String> componentsToNames = containerLayout.getComponentsToNames();
220
221 for (Iterator i = componentsToNames.keySet().iterator(); i.hasNext();)
222 {
223 Component component = (Component) i.next();
224 String componentName = componentsToNames.get(component);
225 if (editor.isNewComponent(component))
226 {
227 String _decl = "";
228 String _import = "";
229 String _add = "";
230 String _config = "";
231
232 ComponentDef cDef = containerLayout.getComponentDef(componentName);
233 if ( cDef == null )
234 {
235
236 String constructorArg = "";
237 if ( LayoutConstraintsManager.isTextComponent(component) )
238 {
239 Map<String,Object> customProperties = containerLayout.getCustomProperties(componentName);
240 Object textValue = customProperties.get("text");
241 if ( textValue != null && textValue instanceof String )
242 constructorArg = "\"" + (String) textValue + "\"";
243 }
244 _decl = component.getClass().getName() + " " +
245 containerLayout.getComponentName(component) +
246 " = new " + component.getClass().getName() +
247 "(" + constructorArg + ");\n";
248 _add = containerLayout.getName() + ".add (" +
249 componentName + ", \"" + componentName + "\");\n";
250 }
251 else
252 {
253
254 _import = cDef.getImports(componentName);
255 _decl = cDef.getDeclarations(componentName);
256 _add = cDef.getAdd(componentName);
257 _add = _add.replaceAll("//$//{container//}", containerLayout.getName());
258 _config = cDef.getConfigure(componentName);
259 }
260
261
262
263
264
265 String [] outstrs = _import.split("\n");
266 for ( int ii = 0; ii < outstrs.length; ii++ )
267 importSet.add(outstrs[ii]);
268
269 declBuffer.append( _decl + "\n");
270 addBuffer2.append( _add + "\n");
271 if ( _config.trim().length() != 0 )
272 confBuffer.append( _config + "\n");
273
274 String constructorArg = "";
275 if (LayoutConstraintsManager.isTextComponent(component))
276 {
277 Map<String, Object> customProperties = containerLayout
278 .getCustomProperties(componentName);
279 Object textValue = customProperties.get("text");
280 if (textValue != null && textValue instanceof String)
281 constructorArg = "\"" + (String) textValue + "\"";
282 }
283
284 String newDeclaration = component.getClass().getName() + " "
285 + containerLayout.getComponentName(component) + " = new "
286 + component.getClass().getName() + "(" + constructorArg
287 + ");\n";
288 declarationBuffer.append(newDeclaration);
289 addBuffer.append(containerLayout.getName() + ".add ("
290 + componentName + ", \"" + componentName + "\");\n");
291 }
292 }
293
294 if (newLayouts.contains(containerLayout))
295 {
296 setLayoutBuffer
297 .append(containerLayout.getName()
298 + ".setBorder(com.jgoodies.forms.factories.Borders.DIALOG_BORDER);\n");
299 setLayoutBuffer.append(containerLayout.getName()
300 + ".setLayout(layoutConstraintsManager.createLayout (\""
301 + containerLayout.getName() + "\", "
302 + containerLayout.getName() + ");\n");
303 }
304 }
305
306
307 Iterator<String> itor = importSet.iterator();
308 while ( itor.hasNext() )
309 importBuffer.append(itor.next() + "\n");
310
311
312
313 String finalText = importBuffer.toString() + "\n" +
314 declBuffer.toString() + "\n" +
315 setLayoutBuffer.toString() + "\n" +
316 addBuffer2.toString() + "\n" +
317 confBuffer.toString() + "\n";
318 CodeDialog codeDialog = new CodeDialog(LayoutFrame.this, finalText);
319 codeDialog.setVisible(true);
320 }
321 });
322
323 saveXML.addActionListener(new ActionListener()
324 {
325 public void actionPerformed(ActionEvent e)
326 {
327 java.util.prefs.Preferences prefs = java.util.prefs.Preferences
328 .userNodeForPackage(getClass());
329 String pathString = prefs.get("lastpath", null);
330 if (pathString != null)
331 {
332 File path = new File(pathString);
333 if (path.exists())
334 {
335 fileChooser.setCurrentDirectory(path);
336 }
337 }
338
339 int returnVal = fileChooser.showSaveDialog(LayoutFrame.this);
340
341 if (returnVal == JFileChooser.APPROVE_OPTION)
342 {
343 File file = fileChooser.getSelectedFile();
344
345
346
347 String filename = file.getAbsolutePath();
348 if ( !filename.endsWith(".xml") &&
349 !filename.endsWith(".XML") &&
350 !filename.endsWith("."))
351 file = new File( file.getAbsolutePath() + ".XML" );
352
353 if (file.exists())
354 {
355 File path = file.getParentFile();
356 if (path != null)
357 {
358 pathString = path.getAbsolutePath();
359 prefs.put("lastpath", pathString);
360 }
361
362 int result = JOptionPane.showConfirmDialog(LayoutFrame.this,
363 "The file you selected exists, ok to overwrite?",
364 "File Exists", JOptionPane.YES_NO_OPTION);
365 if (result != JOptionPane.YES_OPTION)
366 return;
367 }
368
369 FileOutputStream outStream = null;
370 try
371 {
372 outStream = new FileOutputStream(file);
373 String xml = LayoutFrame.this.constraintsManager.getXML();
374 outStream.write(xml.getBytes());
375 }
376 catch (Exception exception)
377 {
378 JOptionPane.showMessageDialog(LayoutFrame.this,
379 "Error writing to file. " + exception.getMessage());
380 exception.printStackTrace();
381 }
382 finally
383 {
384 try
385 {
386 if (outStream != null)
387 outStream.close();
388 }
389 catch (Exception ignore)
390 {
391 }
392 }
393 }
394 }
395 });
396
397 pack();
398 }
399
400 public boolean hasContainer(String name)
401 {
402 return constraintsManager.getContainerLayout(name) != null;
403 }
404
405 private class XmlFileFilter extends FileFilter
406 {
407
408 public boolean accept(File f)
409 {
410 if (f.isDirectory())
411 return true;
412
413 String ext = null;
414 String s = f.getName();
415 int i = s.lastIndexOf('.');
416 boolean isXml = false;
417
418 if (i > 0 && i < s.length() - 1)
419 {
420 ext = s.substring(i + 1).toLowerCase();
421 isXml = ext.equals("xml");
422 }
423
424 return isXml;
425
426 }
427
428 public String getDescription()
429 {
430 return "xml files";
431 }
432
433 }
434
435 public void exitApplication()
436 {
437 int result = JOptionPane.showConfirmDialog(LayoutFrame.this,
438 "Are you sure you want to exit?", "Exit Confirmation",
439 JOptionPane.YES_NO_OPTION);
440 if (result == JOptionPane.YES_OPTION)
441 {
442
443
444
445 UserPrefs.getPrefs().saveWinLoc("main", this);
446 UserPrefs.getPrefs().saveWinLoc("debug", dframe);
447 UserPrefs.getPrefs().saveDebugState(viewDebugMenu.isSelected());
448 setVisible(false);
449 System.exit(0);
450 }
451 }
452
453 public void removeContainer(String name)
454 {
455 ContainerLayout layout = constraintsManager.getContainerLayout(name);
456 if (layout == null)
457 throw new RuntimeException("Container " + name + " does not exist");
458 constraintsManager.removeLayout(layout);
459 FormEditor editor = editors.get(layout);
460 tabs.remove(editor);
461 newLayouts.remove(layout);
462 }
463
464 /***
465 * This is for adding containers on the fly. The idea is that when someone
466 * creates a new panel in one of the existing FormEditors, it can be added
467 * here and then they can lay it out.
468 */
469 public void addContainer(String name, Container container)
470 throws IllegalArgumentException
471 {
472
473 ContainerLayout layout = constraintsManager.getContainerLayout(name);
474 if (layout != null)
475 throw new IllegalArgumentException("A container with name " + name
476 + " already exists");
477
478 layout = new ContainerLayout(name, "pref", "pref");
479 constraintsManager.addLayout(layout);
480 container.setLayout(layout);
481 newLayouts.add(layout);
482
483 addContainerLayout(layout, container);
484 }
485
486 private void addContainerLayout(ContainerLayout containerLayout,
487 Container container)
488 {
489 FormEditor formEditor = new FormEditor(this, containerLayout, container);
490 editors.put(containerLayout, formEditor);
491 tabs.addTab(containerLayout.getName(), formEditor);
492 }
493
494 @SuppressWarnings("serial")
495 private class CodeDialog extends JDialog
496 {
497 public CodeDialog(Frame owner, String text)
498 {
499 super(owner, "FormLayoutMaker - Code View", true);
500
501 UserPrefs.getPrefs().useSavedBounds("codeview",this);
502
503 JPanel content = new JPanel();
504 getContentPane().setLayout(new BorderLayout());
505 getContentPane().add(content, BorderLayout.CENTER);
506
507 JTextArea textArea = new JTextArea();
508 textArea.setEditable(false);
509 textArea.setText(text);
510 textArea.setLineWrap(true);
511 textArea.setWrapStyleWord(true);
512 content.setLayout(new BorderLayout());
513
514 JScrollPane areaScrollPane = new JScrollPane(textArea);
515 areaScrollPane.setPreferredSize(new Dimension(600, 400));
516
517 content.add(areaScrollPane, BorderLayout.CENTER);
518 pack();
519
520 addWindowListener(new WindowAdapter()
521 {
522 public void windowClosing(WindowEvent e)
523 {
524 UserPrefs.getPrefs().saveWinLoc("codeview",CodeDialog.this);
525 }
526 });
527 }
528 }
529
530 /***
531 * Establish the current preview window. Used to switch between the "normal"
532 * and "debug" preview windows.
533 *
534 * KBR 03/26/06 Use this as the mechanism to enable the 'debug preview'
535 * menu, which is disabled by default (to have it disabled when FLM is
536 * invoked via the user's app).
537 *
538 * @param dframe the Jframe for the window.
539 */
540 void setPreviewFrame(LayoutConstraintsManager lcm, JFrame dframe)
541 {
542
543
544 if ( this.dframe != null )
545 this.dframe.setVisible(false);
546 this.dframe = dframe;
547
548
549
550
551
552
553 UserPrefs.getPrefs().useSavedBounds("debug", dframe);
554
555
556
557 dframe.setVisible(true);
558
559 viewDebugMenu.setEnabled(true);
560 }
561
562 /***
563 * Activate "debug" version of preview frame. The title is set accordingly.
564 * @param b true to activate debug version
565 */
566 protected void enableDebugPreview(boolean b)
567 {
568 if ( dframe == null )
569 return;
570 dframe.setTitle("FormLayoutMaker - Preview" + (b ? " (Debug)" : ""));
571 FormDebugPanel fdp = (FormDebugPanel)dframe.getContentPane().getComponent(0);
572 fdp.deactivate( !b );
573 }
574
575 /***
576 * Makes a preview frame using FormDebugPanel. The panel can be switched
577 * between debug and non-debug modes via @see enableDebugPreview.
578 * @param lcm the constraints to be used by the preview panel
579 * @return JFrame the preview window
580 */
581 private static JFrame makeDebugPreview(LayoutConstraintsManager lcm)
582 {
583 FormDebugPanel fdp = new FormDebugPanel(true,false);
584 fdp.setBorder(Borders.DIALOG_BORDER);
585 JFrame debugFrame = new JFrame();
586 lcm.setLayout("panel", fdp);
587 debugFrame.getContentPane().add(fdp, BorderLayout.CENTER);
588 debugFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
589 return debugFrame;
590 }
591
592 public static void main(String[] args)
593 {
594 LayoutConstraintsManager constraintsManager = new LayoutConstraintsManager();
595
596
597
598 JFrame frame = LayoutFrame.makeDebugPreview(constraintsManager);
599
600 LayoutFrame layoutFrame = new LayoutFrame(constraintsManager);
601 LayoutFrame.setDefaultLookAndFeelDecorated(true);
602 UserPrefs.getPrefs().useSavedBounds("main", layoutFrame);
603
604
605
606 layoutFrame.setVisible(true);
607 layoutFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
608 layoutFrame.setPreviewFrame(constraintsManager, frame);
609 layoutFrame.enableDebugPreview(UserPrefs.getPrefs().showDebugPanel());
610 }
611 }