001: /*
002: * Copyright 2001-2006 C:1 Financial Services GmbH
003: *
004: * This software is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License Version 2.1, as published by the Free Software Foundation.
007: *
008: * This software is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
011: * Lesser General Public License for more details.
012: *
013: * You should have received a copy of the GNU Lesser General Public
014: * License along with this library; if not, write to the Free Software
015: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
016: */
017:
018: package de.finix.contelligent.client.gui.directory;
019:
020: import java.awt.BorderLayout;
021: import java.awt.Component;
022: import java.awt.Dimension;
023: import java.awt.SystemColor;
024: import java.awt.Toolkit;
025: import java.awt.event.ActionEvent;
026: import java.awt.event.ActionListener;
027: import java.util.ArrayList;
028: import java.util.Collection;
029: import java.util.Iterator;
030: import java.util.List;
031: import java.util.StringTokenizer;
032: import java.util.logging.Level;
033: import java.util.logging.Logger;
034:
035: import javax.swing.AbstractAction;
036: import javax.swing.Action;
037: import javax.swing.DefaultComboBoxModel;
038: import javax.swing.JComboBox;
039: import javax.swing.JLabel;
040: import javax.swing.JList;
041: import javax.swing.JPanel;
042: import javax.swing.JScrollPane;
043: import javax.swing.JSplitPane;
044: import javax.swing.JToolBar;
045: import javax.swing.KeyStroke;
046: import javax.swing.ListCellRenderer;
047: import javax.swing.UIManager;
048: import javax.swing.border.TitledBorder;
049: import javax.swing.event.ListSelectionEvent;
050: import javax.swing.event.ListSelectionListener;
051:
052: import org.jvnet.flamingo.bcb.BreadcrumbBar;
053: import org.jvnet.flamingo.bcb.BreadcrumbBarCallBack;
054: import org.jvnet.flamingo.bcb.BreadcrumbBarEvent;
055: import org.jvnet.flamingo.bcb.BreadcrumbBarListener;
056: import org.jvnet.flamingo.bcb.BreadcrumbItem;
057: import org.jvnet.flamingo.bcb.BreadcrumbItemChoices;
058:
059: import de.finix.contelligent.client.base.ComponentFactory;
060: import de.finix.contelligent.client.base.ComponentNotFoundException;
061: import de.finix.contelligent.client.base.ContelligentComponent;
062: import de.finix.contelligent.client.base.Context;
063: import de.finix.contelligent.client.base.Session;
064: import de.finix.contelligent.client.event.ComponentEventListener;
065: import de.finix.contelligent.client.event.ContelligentComponentEvent;
066: import de.finix.contelligent.client.event.ContelligentEvent;
067: import de.finix.contelligent.client.gui.AbstractComponentEditor;
068: import de.finix.contelligent.client.gui.ContelligentAction;
069: import de.finix.contelligent.client.gui.GUIContainer;
070: import de.finix.contelligent.client.gui.PathSelectionListener;
071: import de.finix.contelligent.client.gui.PathSelectionManager;
072: import de.finix.contelligent.client.i18n.Resources;
073: import de.finix.contelligent.client.modules.preferences.PreferencesModule;
074: import de.finix.contelligent.client.util.ActionBundle;
075: import de.finix.contelligent.client.util.ButtonComposer;
076: import de.finix.contelligent.client.util.JTextUtil;
077: import de.finix.contelligent.client.util.OptionalToolBar;
078:
079: public class DirectoryEditor extends AbstractComponentEditor implements
080: GUIContainer, PathSelectionManager, ComponentEventListener,
081: ListSelectionListener, ActionListener {
082:
083: private static Logger logger = Logger
084: .getLogger(DirectoryEditor.class.getName());
085:
086: private final static int MAX_HISTORY_SIZE = 20;
087:
088: private AbstractComponentEditor selectionPanel;
089:
090: private JSplitPane splitPane;
091:
092: private JSplitPane mainSplitPane = new JSplitPane(
093: JSplitPane.VERTICAL_SPLIT);
094:
095: private int defaultDividerSize = mainSplitPane.getDividerSize();
096:
097: private JPanel contentPanel, pathsPanel;
098:
099: private Collection paths;
100:
101: private JComboBox location = null;
102:
103: private int selectedIndex = -1;
104:
105: private List history = new ArrayList();
106:
107: private ContelligentComponent selectedComponent;
108:
109: private SelectionCellRenderer cellRenderer;
110:
111: private JList list;
112:
113: private JScrollPane listScroller;
114:
115: private TitledBorder border = new TitledBorder("");
116:
117: private List pathSelectionListeners = new ArrayList();
118:
119: private boolean pathsVisible = false;
120:
121: private JToolBar toolbar = new JToolBar();
122:
123: private CancelAction cancelAction = new CancelAction();
124:
125: private BackAction backAction = new BackAction();
126:
127: private ForwardAction forwardAction = new ForwardAction();
128:
129: BreadcrumbItem rootItem;
130:
131: BreadcrumbBar bcb = null;
132:
133: public void init() {
134: toolbar.setOpaque(false);
135: // edit toolbar
136: OptionalToolBar editToolBar = new OptionalToolBar();
137: editToolBar.setOpaque(false);
138: editToolBar.setFloatable(false);
139: editToolBar.addActionBundleName(ActionBundle.EDITOR_ACTIONS);
140: editToolBar
141: .addActionBundleName(ActionBundle.TRANSACTION_ACTIONS);
142: getView().getMenuAndToolbarComposer().addOptionalToolBar(
143: editToolBar);
144:
145: // toolbar panel
146: JPanel toolbarPanel = new JPanel(new BorderLayout());
147: toolbarPanel.setOpaque(false);
148: toolbarPanel.add(editToolBar, BorderLayout.CENTER);
149:
150: // locationBar
151: if (location != null) {
152: remove(location);
153: }
154: location = new JComboBox();
155: location.setFont(JTextUtil.getInfoFont());
156: location.setEditable(true);
157: location.getEditor().getEditorComponent().setBackground(
158: SystemColor.text);
159: location.setBackground(SystemColor.text);
160: setLocation(getComponent().getPath() + "/");
161:
162: if (PreferencesModule.getPreferences().getBoolean(
163: PreferencesModule.DISABLE_BREADCRUMB_BAR,
164: PreferencesModule.DEFAULT_DISABLE_BREADCRUMB_BAR)) {
165: add(location, BorderLayout.NORTH);
166: } else {
167: JPanel locationPanel = new JPanel(new BorderLayout());
168: locationPanel.setOpaque(false);
169:
170: String rootName;
171: if (getComponent().getPath().length() == 0) {
172: rootName = "/";
173: } else {
174: rootName = getComponent().getName();
175: }
176: rootItem = new BreadcrumbItem(new String[] { rootName,
177: getComponent().getPath() + "/" });
178: rootItem.setIcon(getComponent().getSmallIcon());
179:
180: ComponentBreadcrumbCallBack callback = new ComponentBreadcrumbCallBack(
181: rootItem);
182:
183: bcb = new BreadcrumbBar(":", callback);
184: bcb.setOpaque(false);
185:
186: bcb.pushChoice(rootItem);
187: bcb.setPath(new BreadcrumbItem[] { rootItem });
188:
189: final ComponentBreadcrumbBarListener cbblistener = new ComponentBreadcrumbBarListener();
190: bcb.addListener(cbblistener);
191:
192: locationPanel.add(location, BorderLayout.NORTH);
193: locationPanel.add(bcb, BorderLayout.CENTER);
194:
195: add(locationPanel, BorderLayout.NORTH);
196: }
197:
198: getView().setActionBundle(DirectoryEditor.class.getName(),
199: new Action[] { backAction, forwardAction });
200: enableActions();
201:
202: // content panel
203: contentPanel = new JPanel(new BorderLayout());
204: contentPanel.setOpaque(false);
205:
206: // optional paths panel
207: pathsPanel = new JPanel(new BorderLayout());
208: pathsPanel.setPreferredSize(new Dimension(0, 150));
209: pathsPanel.setOpaque(false);
210: list = new JList();
211: cellRenderer = new SelectionCellRenderer();
212: list.setCellRenderer(cellRenderer);
213: listScroller = new JScrollPane(list);
214: listScroller.setOpaque(false);
215: listScroller.getViewport().setOpaque(false);
216: border.setTitleFont(JTextUtil.getTitleFont());
217: listScroller.setBorder(border);
218: pathsPanel.add(listScroller, BorderLayout.CENTER);
219: pathsPanel.add(toolbar, BorderLayout.SOUTH);
220:
221: // edit panel
222: JPanel editPanel = new JPanel(new BorderLayout());
223: editPanel.setOpaque(false);
224: editPanel.add(toolbarPanel, BorderLayout.NORTH);
225: editPanel.add(contentPanel, BorderLayout.CENTER);
226:
227: // split pane
228: splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
229: splitPane.setOpaque(false);
230: splitPane.setLeftComponent(selectionPanel);
231: splitPane.setRightComponent(editPanel);
232: mainSplitPane.setTopComponent(splitPane);
233: mainSplitPane.setDividerSize(0);
234: mainSplitPane.setOpaque(false);
235: splitPane.setDividerLocation(235);
236: add(mainSplitPane, BorderLayout.CENTER);
237:
238: setSelectedComponent(getComponent());
239: }
240:
241: private void setLocation(String path) {
242: if (!history.contains(path)) {
243: history.add(path);
244: if (history.size() > MAX_HISTORY_SIZE) {
245: history.remove(0);
246: }
247: } else {
248: history.remove(path);
249: history.add(path);
250: }
251: location.removeActionListener(this );
252: location.setModel(new DefaultComboBoxModel(history.toArray()));
253: location.setSelectedItem(path);
254: location.addActionListener(this );
255: selectedIndex = location.getSelectedIndex();
256: setBreadcrumbPath(path);
257: enableActions();
258: }
259:
260: public void valueChanged(ListSelectionEvent e) {
261: notifyPathListeners(getSelectedPath());
262: }
263:
264: public void actionPerformed(ActionEvent e) {
265: String selectedPath = (String) location.getSelectedItem();
266: if (selectedPath.indexOf('/') != -1) {
267: notifyPathListeners(selectedPath);
268: if (e.getActionCommand().equals("comboBoxEdited")) {
269: // Only if the user edited the combo box and pressed enter, not
270: // if using the back/forward buttons or selecting an existing
271: // entry in the history.
272: setLocation(selectedPath);
273: }
274: } else {
275: Toolkit.getDefaultToolkit().beep();
276: }
277: }
278:
279: public void setBreadcrumbPath(String path) {
280: if (bcb != null) {
281: try {
282: ArrayList<BreadcrumbItem> array = new ArrayList<BreadcrumbItem>();
283: array.add(rootItem);
284: String[] tokens = path.split("/");
285: StringBuffer tempPath = new StringBuffer();
286: tempPath.append("/");
287: for (int i = 0; i < tokens.length; i++) {
288: if (tokens[i].length() > 0) {
289: tempPath.append(tokens[i]);
290: tempPath.append("/");
291: if (tempPath.toString().startsWith(
292: rootItem.getValue()[1])
293: && !(tempPath.toString()
294: .equals(rootItem.getValue()[1]))) {
295: // Only add nodes to the BC bar if they are below our view root path
296: ContelligentComponent comp = ComponentFactory
297: .getInstance().getComponent(
298: tempPath.toString());
299: BreadcrumbItem item = new BreadcrumbItem(
300: new String[] { tokens[i],
301: tempPath.toString() });
302: item.setIcon(comp.getSmallIcon());
303: array.add(item);
304: }
305: }
306: }
307: bcb.setPath(array.toArray(new BreadcrumbItem[] {}));
308: } catch (ComponentNotFoundException cne) {
309: logger.log(Level.INFO, "Unable to locate component.",
310: cne);
311: }
312: }
313: }
314:
315: private void notifyPathListeners(String selectedPath) {
316: Iterator i = pathSelectionListeners.iterator();
317: while (i.hasNext()) {
318: PathSelectionListener listener = (PathSelectionListener) i
319: .next();
320: listener.pathSelected(selectedPath);
321: }
322: }
323:
324: private void notifyPathListenersForClose() {
325: Iterator i = pathSelectionListeners.iterator();
326: while (i.hasNext()) {
327: PathSelectionListener listener = (PathSelectionListener) i
328: .next();
329: listener.selectionManagerClosed();
330: }
331: }
332:
333: public void setEditable(boolean editable) {
334: this .editable = editable;
335: if (selectionPanel != null) {
336: selectionPanel.setEditable(isEditable());
337: }
338: }
339:
340: public void setSelectedComponent(ContelligentComponent component) {
341: this .selectedComponent = component;
342:
343: // XXX this caused locking of wrong component when selecting a new one
344: // while
345: // rendering an old one (bug #220)
346: // getView().setComponent(selectedComponent);
347:
348: list.revalidate();
349: list.repaint();
350: }
351:
352: public void setSelectionPanel(AbstractComponentEditor selectionPanel) {
353: this .selectionPanel = selectionPanel;
354: }
355:
356: public void renderSelectedComponent() {
357: setLocation(getSelectedComponent().getPath() + "/");
358: getView().setGUIPanel(contentPanel);
359: getView().setComponent(selectedComponent);
360: getView().render();
361: }
362:
363: public void editSelectedComponent() {
364: getView().setGUIPanel(contentPanel);
365: getView().setComponent(selectedComponent);
366: getView().edit();
367: }
368:
369: public ContelligentComponent getSelectedComponent() {
370: return selectedComponent;
371: }
372:
373: public void showPaths() {
374: if (!pathsVisible) {
375: pathsVisible = true;
376: mainSplitPane.setDividerSize(defaultDividerSize);
377: mainSplitPane.setBottomComponent(pathsPanel);
378: mainSplitPane
379: .setDividerLocation(splitPane.getHeight() - 150);
380: repaint();
381: }
382: }
383:
384: public void hidePaths() {
385: pathsVisible = false;
386: mainSplitPane.setBottomComponent(null);
387: mainSplitPane.setDividerSize(0);
388: repaint();
389: }
390:
391: public void addPathSelectionListener(PathSelectionListener listener) {
392: pathSelectionListeners.add(listener);
393: }
394:
395: public void removePathSelectionListener(
396: PathSelectionListener listener) {
397: pathSelectionListeners.remove(listener);
398: }
399:
400: public void setPaths(String title, Collection paths,
401: Action[] actions) {
402: this .paths = paths;
403: list.removeListSelectionListener(this );
404: if (paths != null) {
405: list.setListData(paths.toArray());
406: } else {
407: list.setListData(new Object[0]);
408: }
409: list.addListSelectionListener(this );
410: border.setTitle(title);
411: toolbar.removeAll();
412: toolbar.add(ButtonComposer.createButton(cancelAction, true,
413: JTextUtil.getInfoFont(), false, false));
414: if (actions != null && actions.length > 0) {
415: for (int i = 0; i < actions.length; i++) {
416: toolbar.add(ButtonComposer.createButton(actions[i],
417: true, JTextUtil.getInfoFont(), false, false));
418: }
419: }
420: repaint();
421: }
422:
423: public String getSelectedPath() {
424: Object o = list.getSelectedValue();
425: if (o instanceof ComponentFactory.Lock) {
426: return ((ComponentFactory.Lock) o).getPath();
427: } else {
428: return o.toString();
429: }
430: }
431:
432: public void setSelectedPath(String path) {
433: setLocation(path);
434: notifyPathListeners(path);
435: }
436:
437: public void clearPaths() {
438: this .paths = null;
439: }
440:
441: public void update() {
442: }
443:
444: public void rollback() {
445: }
446:
447: public void commit() {
448: notifyListeners();
449: }
450:
451: public Action[] getActions() {
452: return selectionPanel.getActions();
453: }
454:
455: protected void updateComponent() {
456: }
457:
458: protected void componentChanged(ContelligentEvent event) {
459: }
460:
461: protected void childComponentAdded(ContelligentEvent event) {
462: }
463:
464: protected void childComponentRemoved(ContelligentEvent event) {
465: }
466:
467: protected void childComponentChanged(ContelligentEvent event) {
468: }
469:
470: protected void descendentComponentChanged(ContelligentEvent event) {
471: }
472:
473: private void enableActions() {
474: if (selectedIndex <= 0 || history.size() == 0) {
475: backAction.setEnabled(false);
476: } else {
477: backAction.setEnabled(true);
478: }
479: if (selectedIndex < history.size() - 1) {
480: forwardAction.setEnabled(true);
481: } else {
482: forwardAction.setEnabled(false);
483: }
484: }
485:
486: public void onComponentRemoved(ContelligentComponentEvent event) {
487: super .onComponentRemoved(event);
488: if (paths != null && paths.contains(event.getTarget())) {
489: paths.remove(event.getTarget());
490: list.removeListSelectionListener(this );
491: list.setListData(paths.toArray());
492: list.addListSelectionListener(this );
493: }
494: }
495:
496: public class CancelAction extends AbstractAction implements
497: ContelligentAction {
498: public CancelAction() {
499: super ("close", Resources.deleteComponentIcon);
500: putValue(ROLLOVER_ICON,
501: Resources.deleteComponentIconRollOver);
502: putValue(TYPE, PUSH_ACTION);
503: putValue(ACTION_TYPE, EDIT_ACTION);
504: putValue(MENU_TARGET, NO_MENU);
505: putValue(BUTTON_TARGET, NO_BUTTON);
506: putValue(POPUP_TARGET, NO_POPUP);
507: }
508:
509: public void actionPerformed(ActionEvent e) {
510: hidePaths();
511: notifyPathListenersForClose();
512: }
513: }
514:
515: public class BackAction extends AbstractAction implements
516: ContelligentAction {
517: public BackAction() {
518: super ("back_action", Resources.previousIcon);
519: putValue(TYPE, PUSH_ACTION);
520: putValue(ACTION_TYPE, NAVIGATION_ACTION);
521: putValue(ACTION_GROUP, NAVIGATION_HISTORY_GROUP);
522: putValue(ACTION_POS, NAVIGATION_HISTORY_BACK);
523: putValue(MENU_TARGET, MENU);
524: putValue(BUTTON_TARGET, TOOLBAR);
525: putValue(POPUP_TARGET, NO_POPUP);
526: putValue(Action.ACCELERATOR_KEY, KeyStroke
527: .getKeyStroke("alt LEFT"));
528: }
529:
530: public void actionPerformed(ActionEvent e) {
531: if (selectedIndex > 0) {
532: selectedIndex--;
533: location.setSelectedIndex(selectedIndex);
534: enableActions();
535: }
536: }
537: }
538:
539: public class ForwardAction extends AbstractAction implements
540: ContelligentAction {
541: public ForwardAction() {
542: super ("forward_action", Resources.nextIcon);
543: putValue(TYPE, PUSH_ACTION);
544: putValue(ACTION_TYPE, NAVIGATION_ACTION);
545: putValue(ACTION_GROUP, NAVIGATION_HISTORY_GROUP);
546: putValue(ACTION_POS, NAVIGATION_HISTORY_FORWARD);
547: putValue(MENU_TARGET, MENU);
548: putValue(BUTTON_TARGET, TOOLBAR);
549: putValue(POPUP_TARGET, NO_POPUP);
550: putValue(Action.ACCELERATOR_KEY, KeyStroke
551: .getKeyStroke("alt RIGHT"));
552: }
553:
554: public void actionPerformed(ActionEvent e) {
555: selectedIndex++;
556: location.setSelectedIndex(selectedIndex);
557: enableActions();
558: }
559: }
560:
561: private class SelectionCellRenderer extends JLabel implements
562: ListCellRenderer {
563: public SelectionCellRenderer() {
564: setOpaque(true);
565: }
566:
567: public Component getListCellRendererComponent(JList list,
568: Object value, int index, boolean isSelected,
569: boolean cellHasFocus) {
570: setIcon(null);
571: if (value instanceof ComponentFactory.Lock) {
572: ComponentFactory.Lock lock = (ComponentFactory.Lock) value;
573: String contextShortName = lock.getContext();
574: try {
575: contextShortName = Context.get(contextShortName)
576: .getShortName();
577: } catch (Exception e) {
578: ;
579: }
580: setText((lock.isShared() ? Resources
581: .getLocalString("locked_shared") : Resources
582: .getLocalString("locked"))
583: + ": "
584: + lock.getPath()
585: + " - "
586: + contextShortName);
587: if (!lock.isShared()) {
588: if (lock.getPrincipal().equals(
589: Session.getInstance().getUser()
590: .getPrincipal().getDisplayName())
591: && lock.getContext().equals(
592: ComponentFactory.getInstance()
593: .getCurrentContext()
594: .getName())) {
595: setIcon(Resources.lockedByMeSmallIcon);
596: } else {
597: setIcon(Resources.lockedBySomeoneElseSmallIcon);
598: }
599: } else {
600: if (lock.getContext().equals(
601: ComponentFactory.getInstance()
602: .getCurrentContext().getName())) {
603: setIcon(Resources.lockedByWfSmallIcon);
604: } else {
605: setIcon(Resources.lockedBySomeoneElseSmallIcon);
606: }
607: }
608: } else {
609: setText(value.toString());
610: }
611: if (isSelected) {
612: setBackground(list.getSelectionBackground());
613: setForeground(list.getSelectionForeground());
614: } else {
615: setBackground(list.getBackground());
616: setForeground(list.getForeground());
617: }
618: return this ;
619: }
620: }
621:
622: private final class ComponentBreadcrumbCallBack implements
623: BreadcrumbBarCallBack {
624: private final BreadcrumbItem rootItem;
625:
626: private ComponentBreadcrumbCallBack(BreadcrumbItem rootItem) {
627: super ();
628: this .rootItem = rootItem;
629: }
630:
631: public BreadcrumbItemChoices getChoices(String dirName) {
632: ContelligentComponent comp;
633: try {
634: comp = ComponentFactory.getInstance().getComponent(
635: dirName);
636: } catch (ComponentNotFoundException cne) {
637: logger.log(Level.INFO, "Unable to resolve component: "
638: + dirName);
639: return null;
640: }
641: Iterator it = comp.getSubcomponents().iterator();
642: ArrayList<BreadcrumbItem> array = new ArrayList<BreadcrumbItem>();
643: while (it.hasNext()) {
644: String subName = (String) it.next();
645: try {
646: String subPath = comp.getPath() + "/" + subName;
647: ContelligentComponent sub = ComponentFactory
648: .getInstance().getComponent(subPath);
649: BreadcrumbItem item = new BreadcrumbItem(
650: new String[] { sub.getName(), sub.getPath() });
651: item.setIcon(sub.getSmallIcon());
652: array.add(item);
653: } catch (ComponentNotFoundException cne) {
654: logger.log(Level.INFO,
655: "Unable to resolve component: " + dirName);
656: }
657: }
658: return new BreadcrumbItemChoices(array
659: .toArray(new BreadcrumbItem[] {}));
660: }
661:
662: public BreadcrumbItemChoices getChoices(BreadcrumbItem[] path) {
663: if (path == null) {
664: return new BreadcrumbItemChoices(
665: new BreadcrumbItem[] { rootItem });
666: }
667: if (path.length == 0) {
668: return new BreadcrumbItemChoices(
669: new BreadcrumbItem[] { rootItem });
670: }
671: String dirName = path[path.length - 1].getValue()[1];
672: return getChoices(dirName);
673: }
674: }
675:
676: private final class ComponentBreadcrumbBarListener implements
677: BreadcrumbBarListener {
678: private boolean enabled = true;
679:
680: public void breadcrumbBarEvent(BreadcrumbBarEvent event) {
681: if (enabled) {
682: if (event.getType() == BreadcrumbBarEvent.PATH_CHANGED) {
683: BreadcrumbItem[] newPath = (BreadcrumbItem[]) event
684: .getNewValue();
685: String newCompPath = newPath[newPath.length - 1]
686: .getValue()[1];
687: enabled = false;
688: notifyPathListeners(newCompPath);
689: enabled = true;
690: }
691: }
692: }
693: }
694:
695: }
|