001: package net.xoetrope.builder.editor;
002:
003: import java.util.Enumeration;
004: import java.util.Hashtable;
005: import java.util.Vector;
006:
007: import java.awt.BorderLayout;
008: import java.awt.Color;
009: import java.awt.Component;
010: import java.awt.Container;
011: import java.awt.Dimension;
012: import java.awt.Font;
013: import java.awt.Graphics;
014: import java.awt.Point;
015: import java.awt.event.ActionEvent;
016: import java.awt.event.ActionListener;
017: import java.awt.event.MouseEvent;
018: import java.awt.event.MouseListener;
019: import javax.swing.JMenuItem;
020: import javax.swing.JPanel;
021: import javax.swing.JPopupMenu;
022: import javax.swing.JScrollPane;
023: import javax.swing.JToolTip;
024: import javax.swing.JTree;
025: import javax.swing.ToolTipManager;
026: import javax.swing.border.EmptyBorder;
027: import javax.swing.event.TreeSelectionEvent;
028: import javax.swing.event.TreeSelectionListener;
029: import javax.swing.tree.DefaultMutableTreeNode;
030: import javax.swing.tree.TreeNode;
031: import javax.swing.tree.TreePath;
032:
033: import net.xoetrope.builder.editor.components.ComponentHelper;
034: import net.xoetrope.builder.editor.components.PropertyHelper;
035: import net.xoetrope.builder.editor.dialog.XStyleEditorDialog;
036: import net.xoetrope.builder.editor.events.ProjectListener;
037: import net.xoetrope.builder.editor.events.StyleListener;
038: import net.xoetrope.builder.editor.helper.XStyleCellRenderer;
039: import net.xoetrope.xui.XPage;
040: import net.xoetrope.xui.style.XStyle;
041: import net.xoetrope.debug.DebugLogger;
042:
043: /**
044: * An editor component for XUI styles
045: * <p>Copyright: Copyright (c) Xoetrope Ltd., 1998-2003</p>
046: * $Revision: 1.20 $
047: */
048: public class XStyleEditor extends JPanel implements ActionListener,
049: TreeSelectionListener, StyleListener, MouseListener,
050: ProjectListener {
051: private JTree styleTree;
052: private JScrollPane stylePane;
053:
054: private JPanel mainPanel, spacer;
055: private DefaultMutableTreeNode topNode;
056: private Component targetComponent;
057:
058: private XEditorProject currentProject;
059:
060: private StyleListener styleListener;
061: private XEditorStyleManager styleManager;
062:
063: private Vector selectedComponents;
064: private boolean listenerChanging = false;
065:
066: public XStyleEditor(String name, MouseListener listener) {
067: setLayout(new BorderLayout());
068: setVisible(false);
069:
070: styleManager = (XEditorStyleManager) XEditorProjectManager
071: .getStyleManager();
072: setupStylePalette();
073: }
074:
075: public void projectLoaded(XEditorProject project) {
076: currentProject = project;
077: createTree();
078: }
079:
080: /**
081: * The project has been updated
082: */
083: public void projectUpdated() {
084: }
085:
086: public void setSelectedComponents(Vector targets) {
087: selectedComponents = targets;
088: }
089:
090: public void setStyleListener(StyleListener listener) {
091: styleListener = listener;
092: }
093:
094: public Dimension getPreferredSize() {
095: return new Dimension(200, 300);
096: }
097:
098: public void setupStylePalette() {
099: mainPanel = new JPanel(new BorderLayout());
100: mainPanel.setBorder(new EmptyBorder(0, 0, 0, 0));
101: add(mainPanel);
102:
103: spacer = new JPanel();
104: spacer.setPreferredSize(new Dimension(200, 1));
105: spacer.setBorder(new EmptyBorder(0, 200, 0, 0));
106:
107: if (stylePane != null) {
108: stylePane.getParent().remove(stylePane);
109: stylePane = null;
110: }
111:
112: // XStyle style = styleManager.getStyle( "base" );
113: topNode = new DefaultMutableTreeNode("Styles");
114: styleTree = new JStyleTree(topNode);
115: styleTree.setFont(XuiDefaults.defaultFont);
116: styleTree.setCellRenderer(new XStyleCellRenderer());
117: styleTree.setScrollsOnExpand(true);
118: styleTree.addTreeSelectionListener(this );
119: styleTree.addMouseListener(this );
120:
121: stylePane = new JScrollPane(styleTree);
122: stylePane.setBorder(new EmptyBorder(0, 0, 0, 0));
123: styleTree.setBorder(new EmptyBorder(0, 0, 0, 0));
124: mainPanel.add(stylePane, BorderLayout.CENTER);
125: mainPanel.add(spacer, BorderLayout.SOUTH);
126:
127: spacer.doLayout();
128: stylePane.doLayout();
129: mainPanel.doLayout();
130: doLayout();
131: }
132:
133: public void actionPerformed(ActionEvent e) {
134: if (e.getActionCommand().equals("Add...")) {
135: String styleName = getTreePath();
136: XStyle style = styleManager.getStyle(styleName);
137: XStyleEditorDialog sed = new XStyleEditorDialog(true,
138: style, styleName);
139: sed.setLocationRelativeTo(this );
140: sed.show();
141:
142: if (sed.getStatus()) {
143: XStyle updatedStyle = sed.getStyle();
144: String path = getTreePath() + "/";
145: if (path.compareTo("/") == 0)
146: path = "";
147: String updatedStyleName = path + sed.getStyleName();
148: styleManager.addStyle(updatedStyleName, updatedStyle);
149: updateStyle(sed.getStyle(), updatedStyleName, true);
150: createTree();
151: }
152: } else if (e.getActionCommand().equals("Edit...")) {
153: String styleName = getTreePath();
154: XStyle style = styleManager.getStyle(styleName);
155: XStyleEditorDialog sed = new XStyleEditorDialog(false,
156: style, styleName);
157: sed.setLocationRelativeTo(this );
158: sed.show();
159:
160: if (sed.getStatus()) {
161: XStyle updatedStyle = sed.getStyle();
162: String path = getTreePath() + "/";
163: if (path.compareTo("/") == 0)
164: path = "";
165: String updatedStyleName = styleName;
166: updateStyle(style, updatedStyleName, false);
167: createTree();
168: }
169: } else if (e.getActionCommand().equals("Delete")) {
170: styleManager.removeStyle(getTreePath());
171: if (styleListener != null)
172: styleListener.styleChanged(getTreePath(), null);
173: updateComponentStyles(getTreePath(), false);
174:
175: createTree();
176: }
177: }
178:
179: private void applyStyle(XStyle style) {
180: Color fore = style.getStyleAsColor(style.COLOR_FORE);
181: Color back = style.getStyleAsColor(style.COLOR_BACK);
182: String tempfontface = style.getStyleAsString(style.FONT_FACE);
183: if (tempfontface != null) {
184: String fontface = tempfontface.substring(0, 1)
185: .toUpperCase();
186: fontface += tempfontface
187: .substring(1, tempfontface.length());
188: int fontsize = style.getStyleAsInt(style.FONT_SIZE);
189: int fontitalic = style.getStyleAsInt(style.FONT_ITALIC);
190: int fontweight = style.getStyleAsInt(style.FONT_WEIGHT);
191: int fontStyle = 0;
192: if (fontweight == 1)
193: fontStyle = Font.BOLD;
194: if (fontitalic == 1)
195: fontStyle = fontStyle | Font.ITALIC;
196:
197: Font font = new Font(fontface, fontStyle, fontsize);
198: if (targetComponent != null)
199: targetComponent.setFont(font);
200: }
201:
202: if (targetComponent != null) {
203: targetComponent.setForeground(fore);
204: targetComponent.setBackground(back);
205: }
206: }
207:
208: private void updateStyle(XStyle modifiedStyle, String styleName,
209: boolean newStyle) {
210: if (styleListener != null) {
211: if (!newStyle)
212: styleListener
213: .styleChanged(getTreePath(), modifiedStyle);
214: }
215:
216: updateComponentStyles(styleName, newStyle);
217:
218: DefaultMutableTreeNode node = (DefaultMutableTreeNode) styleTree
219: .getLastSelectedPathComponent();
220: if (node == null)
221: return;
222: if (!newStyle)
223: node.setUserObject((getStrippedPath((String) node
224: .getUserObject()))
225: + getStyleAttribs(modifiedStyle));
226: styleTree.repaint();
227: }
228:
229: private void updateComponentStyles(String styleName,
230: boolean newStyle) {
231: if (currentProject != null) {
232: if (!newStyle) {
233: Hashtable pages = currentProject.getPageResources();
234: Enumeration keys = pages.keys();
235: while (keys.hasMoreElements()) {
236: String pageName = (String) keys.nextElement();
237: XPageResource pageResource = (XPageResource) pages
238: .get(pageName);
239: XPage page = pageResource.getPage();
240: if (page != null) {
241: updateComponentStyle(pageResource, page,
242: styleName, newStyle);
243: }
244: }
245: }
246: }
247:
248: }
249:
250: private void updateComponentStyle(XPageResource pageResource,
251: Component comp, String styleName, boolean newStyle) {
252: int resourceIdx = 6; // Aaaghhh.... hard coding
253:
254: PropertyHelper helper = new ComponentHelper()
255: .getPropertyHelper(comp);
256: if (helper == null)
257: return;
258:
259: String oldStyleName = helper.getPropertyValue(pageResource,
260: comp, resourceIdx);
261: if ((oldStyleName != null) && oldStyleName.equals(styleName)) {
262: if (!newStyle)
263: helper.setPropertyValue(pageResource, comp,
264: resourceIdx, "[None]");
265: else
266: helper.setPropertyValue(pageResource, comp,
267: resourceIdx, styleName);
268: }
269:
270: if (comp instanceof Container) {
271: Container cont = (Container) comp;
272:
273: int numChildren = cont.getComponentCount();
274: for (int i = 0; i < numChildren; i++)
275: updateComponentStyle(pageResource,
276: cont.getComponent(i), styleName, newStyle);
277: }
278: }
279:
280: private DefaultMutableTreeNode createTree() {
281: styleManager = (XEditorStyleManager) XEditorProjectManager
282: .getStyleManager();
283: String[] values = styleManager.getStylesArray();
284: topNode.removeAllChildren();
285: DefaultMutableTreeNode root = null;
286: DefaultMutableTreeNode subroot = null;
287:
288: for (int i = 0; i < values.length; i++) {
289: if (values[i].indexOf("/") > -1) {
290: subroot = createTreeSubNodes(values[i], root);
291: String next = "";
292: if ((i + 1) < values.length)
293: next = values[i + 1];
294: if ((next.length() >= values[i].length())
295: && (next.startsWith(values[i]))) {
296: String temp = next.substring(values[i].length(),
297: next.length());
298: if (temp.startsWith("/"))
299: root = subroot;
300: }
301: } else {
302: XStyle style = styleManager.getStyle(values[i]);
303: root = new DefaultMutableTreeNode(values[i]
304: + getStyleAttribs(style));
305: topNode.add(root);
306: }
307: }
308: TreePath path = new TreePath(topNode);
309: styleTree.expandPath(path);
310: styleTree.repaint();
311: styleTree.updateUI();
312: return topNode;
313: }
314:
315: private DefaultMutableTreeNode createTreeSubNodes(String path,
316: DefaultMutableTreeNode root) {
317: DefaultMutableTreeNode newroot = null;
318: String temp = path.substring(path.lastIndexOf("/") + 1, path
319: .length());
320: if (temp.indexOf("/") > -1) {
321: XStyle style = styleManager.getStyle(path);
322: newroot = new DefaultMutableTreeNode(path.substring(0, path
323: .indexOf("/"))
324: + getStyleAttribs(style));
325: root.add(newroot);
326: createTreeSubNodes(temp, newroot);
327: return root;
328: } else {
329: XStyle style = styleManager.getStyle(path);
330: newroot = new DefaultMutableTreeNode(temp
331: + getStyleAttribs(style));
332: // if ( root == null )
333: // root = new DefaultMutableTreeNode( "base" );
334: root.add(newroot);
335: }
336: return newroot;
337: }
338:
339: /**
340: * Responds to tree selection changes
341: * @param evt
342: */
343: public void valueChanged(TreeSelectionEvent evt) {
344: Object o = evt.getSource();
345: String styleName = getTreePath();
346:
347: XStyle style = styleManager.getStyle(styleName);
348: applyStyle(style);
349: if (styleName != null) {
350: int idx = styleName.indexOf('|');
351: if (idx > 0)
352: styleName = styleName.substring(0, idx);
353: }
354: }
355:
356: /**
357: * Update the selected component if double clicked
358: * @param me
359: */
360: public void mouseClicked(MouseEvent me) {
361: if (me.getClickCount() > 1) {
362: if (listenerChanging)
363: DebugLogger
364: .logWarning("cannot assign style because listenerChanging is true");
365:
366: if ((styleListener != null) && !listenerChanging) {
367: String styleName = getTreePath();
368: // if ( ( styleName == null ) || ( styleName.length() == 0 ) )
369: // styleName = "/base";
370: XStyle style = styleManager.getStyle(styleName);
371:
372: listenerChanging = true;
373: styleListener.styleChanged(styleName, style);
374: listenerChanging = false;
375: }
376: }
377: }
378:
379: public void mousePressed(MouseEvent me) {
380: }
381:
382: public void mouseReleased(MouseEvent me) {
383: if (me.isPopupTrigger()) {
384: JPopupMenu popupMenu = new JPopupMenu("Styles");
385: if (styleTree.getSelectionPath() != null) {
386: if (styleTree.getSelectionPath().getPathCount() == 1) {
387: JMenuItem mi = new JMenuItem("Add...");
388: mi.addActionListener(this );
389: popupMenu.add(mi);
390: } else {
391: JMenuItem mi = new JMenuItem("Edit...");
392: mi.addActionListener(this );
393: popupMenu.add(mi);
394:
395: mi = new JMenuItem("Add...");
396: mi.addActionListener(this );
397: popupMenu.add(mi);
398:
399: popupMenu.addSeparator();
400:
401: mi = new JMenuItem("Delete");
402: mi.addActionListener(this );
403: popupMenu.add(mi);
404:
405: }
406: Point pt = me.getPoint();
407: Point vp = styleTree.getLocation();
408: popupMenu.show(this , pt.x + vp.x, pt.y + vp.y);
409: }
410: }
411: }
412:
413: public void mouseEntered(MouseEvent me) {
414: }
415:
416: public void mouseExited(MouseEvent me) {
417: }
418:
419: /**
420: * Called when a style is changed. This allows the editor to reset the
421: * components visually.
422: * @param styleName the name of the style which has been changed
423: * @param newstyle The new XStyle
424: */
425: public void styleChanged(String styleName, XStyle style) {
426: if (!listenerChanging) {
427: listenerChanging = true;
428: applyStyle(style);
429: if (styleName != null) {
430: int idx = styleName.indexOf('|');
431: if (idx > 0)
432: styleName = styleName.substring(0, idx);
433:
434: Vector nodes = new Vector();
435: nodes.add(topNode);
436: addNodes(nodes, topNode, styleName);
437: if (nodes.size() > 0) {
438: Object nodeArray[] = nodes.toArray();
439: TreePath path = new TreePath(nodeArray);
440: styleTree.setSelectionPath(path);
441: styleTree.scrollPathToVisible(path);
442: }
443: }
444: listenerChanging = false;
445: }
446: }
447:
448: private void addNodes(Vector nodes, TreeNode node, String styleName) {
449: int pos = styleName.indexOf('/');
450: String subStyle = pos > 0 ? styleName.substring(0, pos)
451: : styleName;
452: int numChildren = node.getChildCount();
453: for (int i = 0; i < numChildren; i++) {
454: TreeNode childNode = node.getChildAt(i);
455: if (childNode.toString().indexOf(subStyle) >= 0) {
456: nodes.add(childNode);
457: if ((pos > 0) && (pos < styleName.length()))
458: addNodes(nodes, childNode, styleName
459: .substring(pos + 1));
460: break;
461: }
462: }
463: }
464:
465: private String getTreePath() {
466: String styleName = null;
467: if (styleTree.getSelectionPath() != null) {
468: Object path[] = styleTree.getSelectionPath().getPath();
469:
470: styleName = "";
471: for (int i = 1; i < path.length; i++) {
472: styleName += getStrippedPath(path[i].toString()) + "/";
473: }
474: if (styleName.length() > 0)
475: styleName = styleName.substring(0,
476: styleName.length() - 1);
477: }
478:
479: if (styleName == null)
480: return "";
481: else if (styleName.trim().compareTo("") != 0)
482: return styleName;
483: else
484: return "";
485: }
486:
487: private String getTreePath(MouseEvent me) {
488: String styleName = null;
489: TreePath path = styleTree.getClosestPathForLocation(me
490: .getPoint().x, me.getPoint().y);
491: if (path != null) {
492: Object paths[] = path.getPath();
493:
494: styleName = "";
495: for (int i = 1; i < paths.length; i++) {
496: styleName += getStrippedPath(paths[i].toString()) + "/";
497: }
498: if (styleName.length() > 0)
499: styleName = styleName.substring(0,
500: styleName.length() - 1);
501: }
502:
503: return styleName;
504: }
505:
506: private String getStrippedPath(String path) {
507: int delim = path.indexOf("|");
508: if (delim < 0)
509: return path;
510: else
511: return path.substring(0, delim);
512: }
513:
514: private String getStyleAttribs(XStyle style) {
515: String attribStr = "|";
516: Color bgColor = style.getStyleAsColor(XStyle.COLOR_BACK);
517: Color fgColor = style.getStyleAsColor(XStyle.COLOR_FORE);
518: int fontSize = style.getStyleAsInt(XStyle.FONT_SIZE);
519:
520: if (bgColor == null)
521: bgColor = Color.white;
522: if (fgColor == null)
523: fgColor = Color.black;
524: if (fontSize == 0)
525: fontSize = 10;
526:
527: return "|" + bgColor.getRGB() + "|" + fgColor.getRGB() + "|"
528: + fontSize;
529: }
530:
531: /**
532: * Subclass the tree so as to add tooltip support
533: */
534: class JStyleTree extends JTree {
535: Font toolTipFont;
536: XStyle toolTipStyle;
537:
538: public JStyleTree(DefaultMutableTreeNode model) {
539: super (model);
540: ToolTipManager.sharedInstance().registerComponent(this );
541: }
542:
543: public JToolTip createToolTip() {
544: StyleToolTip tt = new StyleToolTip();
545: tt.setComponent(this );
546:
547: if (toolTipFont != null)
548: tt.setFont(toolTipFont);
549:
550: if (toolTipStyle != null) {
551: tt.setBackground(toolTipStyle
552: .getStyleAsColor(XStyle.COLOR_BACK));
553: tt.setForeground(toolTipStyle
554: .getStyleAsColor(XStyle.COLOR_FORE));
555: }
556: return tt;
557: }
558:
559: public String getToolTipText(MouseEvent me) {
560: String styleName = getTreePath(me);
561: if (styleName.length() > 0) {
562: toolTipStyle = styleManager.getStyle(styleName);
563: String fontDescription = styleName
564: + " ["
565: + toolTipStyle
566: .getStyleAsString(XStyle.FONT_FACE);
567: int fontSize = toolTipStyle
568: .getStyleAsInt(XStyle.FONT_SIZE);
569: fontDescription += ": " + fontSize + "pt";
570: fontSize = Math.max(fontSize, 10);
571: int fontStyle = 0;
572: if (toolTipStyle.getStyleAsInt(XStyle.FONT_ITALIC) == 1) {
573: fontDescription += ", italic";
574: fontStyle |= Font.ITALIC;
575: }
576: if (toolTipStyle.getStyleAsInt(XStyle.FONT_WEIGHT) == 1) {
577: fontDescription += ", bold";
578: fontStyle |= Font.BOLD;
579: }
580: fontDescription += "]";
581:
582: toolTipFont = new Font(toolTipStyle
583: .getStyleAsString(XStyle.FONT_FACE), fontStyle,
584: fontSize);
585: return fontDescription;
586: } else
587: return "";
588: }
589: }
590:
591: /**
592: * Subclass the tooltip to allow the colours to be changed
593: */
594: class StyleToolTip extends JToolTip {
595: public StyleToolTip() {
596: }
597:
598: public void paintComponent(Graphics g) {
599: g.setColor(getForeground());
600: super.paintComponent(g);
601: }
602: }
603: }
|