001: /*
002: * Copyright 2006-2007 Pentaho Corporation. All rights reserved.
003: * This software was developed by Pentaho Corporation and is provided under the terms
004: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
005: * this file except in compliance with the license. If you need a copy of the license,
006: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt.
007: *
008: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
009: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
010: * the license for the specific language governing your rights and limitations.
011: *
012: * Additional Contributor(s): Martin Schmid gridvision engineering GmbH
013: */
014: package org.pentaho.reportdesigner.lib.client.components.favoritespanel;
015:
016: import org.jetbrains.annotations.NotNull;
017: import org.pentaho.reportdesigner.lib.client.components.Category;
018:
019: import javax.swing.*;
020: import java.awt.*;
021: import java.awt.event.ActionEvent;
022: import java.awt.event.ActionListener;
023: import java.beans.PropertyChangeEvent;
024: import java.beans.PropertyChangeListener;
025: import java.beans.PropertyChangeSupport;
026: import java.util.ArrayList;
027: import java.util.Collection;
028: import java.util.Collections;
029: import java.util.Comparator;
030: import java.util.LinkedHashMap;
031:
032: /**
033: * User: Martin
034: * Date: 11.03.2005
035: * Time: 10:09:48
036: */
037: public class FavoritesPanel extends JPanel {
038:
039: @NotNull
040: private Category<?> maximizedCategory;//the one currently maximized
041: @NotNull
042: private ArrayList<Category<?>> minimizedCategoryList;//all minimized (visible on the buttons, without the maximized)
043: @NotNull
044: private LinkedHashMap<Object, Category<?>> categoryMap;//all (including maximized and visible)
045:
046: @NotNull
047: private AbstractHeaderComponent headerComponent;
048:
049: @NotNull
050: private ArrayList<JButton> activateButtons;
051: @NotNull
052: private JPanel activateButtonsPanel;
053:
054: @NotNull
055: private JPanel toolbarButtonPanel;
056:
057: @NotNull
058: private JPanel southPanel;
059:
060: @NotNull
061: private JButton showListButton;
062: @NotNull
063: private JPopupMenu popupMenu;
064:
065: private int visibleCategoryCount;
066:
067: private boolean toolbarVisible;
068:
069: @NotNull
070: private JMenuItem moreElementsMenuItem;
071: @NotNull
072: private JMenuItem lessElementsMenuItem;
073:
074: @NotNull
075: private PropertyChangeSupport propertyChangeSupport;
076:
077: public FavoritesPanel() {
078: categoryMap = new LinkedHashMap<Object, Category<?>>();
079: minimizedCategoryList = new ArrayList<Category<?>>();
080:
081: setLayout(new BorderLayout());
082:
083: headerComponent = new DefaultHeaderComponent();
084: add(headerComponent, BorderLayout.NORTH);
085:
086: visibleCategoryCount = 0;
087:
088: toolbarVisible = false;
089:
090: activateButtons = new ArrayList<JButton>();
091: activateButtonsPanel = new JPanel(new GridLayout(0, 1));
092:
093: southPanel = new JPanel(new BorderLayout());
094: southPanel.add(activateButtonsPanel, BorderLayout.CENTER);
095:
096: JPanel moreLessGroupPanel = new JPanel(new BorderLayout());
097:
098: toolbarButtonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
099:
100: showListButton = new JButton("...");
101: showListButton.setDefaultCapable(false);
102:
103: popupMenu = new JPopupMenu();
104: popupMenu.setInvoker(showListButton);
105:
106: showListButton.addActionListener(new ActionListener() {
107: public void actionPerformed(@NotNull
108: ActionEvent e) {
109: Point p = showListButton.getLocationOnScreen();
110: int h = popupMenu.getPreferredSize().height;
111: p.y -= h;
112: p.y += showListButton.getHeight();
113: p.x += showListButton.getWidth();
114: popupMenu.setLocation(p);
115: popupMenu.setVisible(true);
116: }
117: });
118:
119: JPanel helperPanel = new JPanel(new BorderLayout());
120: helperPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5,
121: 5));
122: helperPanel.add(showListButton, BorderLayout.SOUTH);
123: moreLessGroupPanel.add(helperPanel, BorderLayout.EAST);
124:
125: moreLessGroupPanel.add(toolbarButtonPanel, BorderLayout.CENTER);
126:
127: southPanel.add(moreLessGroupPanel, BorderLayout.SOUTH);
128:
129: add(southPanel, BorderLayout.SOUTH);
130:
131: moreElementsMenuItem = new JMenuItem("Mehr Elemente");//NON-NLS
132: moreElementsMenuItem.addActionListener(new ActionListener() {
133: public void actionPerformed(@NotNull
134: ActionEvent e) {
135: if (getVisibleCategoryCount() == categoryMap.size()) {
136: setEnabled(false);
137: }
138:
139: setVisibleCategoryCount(getVisibleCategoryCount() + 1);
140: }
141: });
142:
143: lessElementsMenuItem = new JMenuItem("Weniger Elemente");//NON-NLS
144: lessElementsMenuItem.addActionListener(new ActionListener() {
145: public void actionPerformed(@NotNull
146: ActionEvent e) {
147: if (getVisibleCategoryCount() == 1) {
148: lessElementsMenuItem.setEnabled(false);
149: }
150:
151: setVisibleCategoryCount(getVisibleCategoryCount() - 1);
152: }
153: });
154:
155: propertyChangeSupport = new PropertyChangeSupport(this );
156: }
157:
158: @NotNull
159: public AbstractHeaderComponent getHeaderComponent() {
160: return headerComponent;
161: }
162:
163: public void setHeaderComponent(@NotNull
164: AbstractHeaderComponent headerComponent) {
165: remove(this .headerComponent);
166: this .headerComponent = headerComponent;
167: add(headerComponent, BorderLayout.NORTH);
168: }
169:
170: @NotNull
171: public JButton getShowListButton() {
172: return showListButton;
173: }
174:
175: @NotNull
176: public JMenuItem getMoreElementsMenuItem() {
177: return moreElementsMenuItem;
178: }
179:
180: @NotNull
181: public JMenuItem getLessElementsMenuItem() {
182: return lessElementsMenuItem;
183: }
184:
185: public void setToolbarVisible(boolean toolbarVisible) {
186: boolean oldToolbarVisible = this .toolbarVisible;
187:
188: this .toolbarVisible = toolbarVisible;
189: refreshComponent();
190:
191: propertyChangeSupport.firePropertyChange("toolbarVisible",
192: oldToolbarVisible, toolbarVisible);//NON-NLS
193: }
194:
195: public int getVisibleCategoryCount() {
196: return visibleCategoryCount;
197: }
198:
199: /**
200: * Sets how many items should be displayed as favorites buttons. This does not include the maximized Category.
201: *
202: * @param visibleCategoryCount
203: */
204: public void setVisibleCategoryCount(int visibleCategoryCount) {
205: if (visibleCategoryCount < 0
206: || visibleCategoryCount > categoryMap.size()) {
207: throw new IllegalArgumentException(
208: "visibleCategoryCount has to be in range [0, "
209: + (categoryMap.size()) + "]");
210: }
211:
212: int oldVisibleCategoryCount = this .visibleCategoryCount;
213:
214: this .visibleCategoryCount = visibleCategoryCount;
215:
216: activateButtonsPanel.removeAll();
217: activateButtons.clear();
218:
219: for (int i = 0; i < visibleCategoryCount; i++) {
220: JButton activateButton = new JButton("activateButton " + i);//NON-NLS
221: activateButton.setDefaultCapable(false);
222: activateButton.setHorizontalAlignment(JButton.LEFT);
223:
224: final int index = i;
225: activateButton.addActionListener(new ActionListener() {
226: public void actionPerformed(@NotNull
227: ActionEvent e) {
228: Category<?> category = minimizedCategoryList
229: .get(index);
230: setMaximizedCategory(category);
231: }
232: });
233:
234: activateButtons.add(activateButton);
235: activateButtonsPanel.add(activateButton);
236: }
237:
238: refreshComponent();
239:
240: propertyChangeSupport.firePropertyChange(
241: "visibleCategoryCount", oldVisibleCategoryCount,
242: visibleCategoryCount);//NON-NLS
243: }
244:
245: public void addCategory(@NotNull
246: Category<?> category) {
247: categoryMap.put(category.getKey(), category);
248:
249: category
250: .addPropertyChangeListener(new PropertyChangeListener() {
251: public void propertyChange(@NotNull
252: PropertyChangeEvent evt) {
253: refreshComponent();
254: }
255: });
256:
257: refreshComponent();
258: }
259:
260: public void removeCategory(@NotNull
261: Category<JComponent> category) {
262: categoryMap.remove(category.getKey());
263:
264: refreshComponent();
265: }
266:
267: public void setCategories(@NotNull
268: Category<?>... categories) {
269: //noinspection ConstantConditions
270: if (categories == null || categories.length == 0) {
271: throw new IllegalArgumentException(
272: "categories can not be null or empty");
273: }
274:
275: categoryMap.clear();
276:
277: for (Category<?> category : categories) {
278: categoryMap.put(category.getKey(), category);
279:
280: category
281: .addPropertyChangeListener(new PropertyChangeListener() {
282: public void propertyChange(@NotNull
283: PropertyChangeEvent evt) {
284: refreshComponent();
285: }
286: });
287: }
288: refreshComponent();
289: }
290:
291: public void setMaximizedCategory(@NotNull
292: Category<?> category) {
293: Category<?> oldMaximizedCategory = this .maximizedCategory;
294:
295: category.setLastAccessedMillis(System.currentTimeMillis());
296:
297: refreshComponent();
298:
299: propertyChangeSupport.firePropertyChange("maximizedCategory",
300: oldMaximizedCategory, maximizedCategory);//NON-NLS
301: }
302:
303: @NotNull
304: public Category<?> getMaximizedCategory() {
305: return maximizedCategory;
306: }
307:
308: public void executeMaximizedCategory() {
309: maximizedCategory.setLastAccessedMillis(System
310: .currentTimeMillis());
311: }
312:
313: private void refreshComponent() {
314: if (categoryMap.isEmpty()) {
315: return;
316: }
317:
318: ArrayList<Category<?>> categoryListByTime = new ArrayList<Category<?>>(
319: categoryMap.values());
320: Collections.sort(categoryListByTime,
321: new Comparator<Category<?>>() {
322: public int compare(@NotNull
323: Category<?> c1, @NotNull
324: Category<?> c2) {
325: return Long
326: .valueOf(c2.getLastAccessedMillis())
327: .compareTo(
328: new Long(
329: c1
330: .getLastAccessedMillis()));
331: }
332: });
333:
334: Category<?> maxCategory = categoryListByTime.get(0);
335:
336: if (maxCategory != null) {
337: headerComponent.setCategory(maxCategory);
338:
339: //noinspection ConstantConditions
340: if ((maximizedCategory != null)
341: && (maximizedCategory.getMainComponent() != null)) {
342: remove(maximizedCategory.getMainComponent());
343: }
344:
345: if (maxCategory.getMainComponent() != null) {
346: add(maxCategory.getMainComponent(), BorderLayout.CENTER);
347: } else {
348: add(new JPanel(), BorderLayout.CENTER);
349: }
350:
351: maximizedCategory = maxCategory;
352: }
353:
354: //create a list containing all visible (not maximized) categories
355: ArrayList<Category<?>> visibleCategoryList = new ArrayList<Category<?>>();
356: for (int i = 0; i < visibleCategoryCount; i++) {
357: visibleCategoryList.add(categoryListByTime.get(i));
358: }
359:
360: //order list by index of original list
361: Collections.sort(visibleCategoryList,
362: new Comparator<Category<?>>() {
363: public int compare(@NotNull
364: Category<?> o1, @NotNull
365: Category<?> o2) {
366: int index1 = new ArrayList<Category<?>>(
367: categoryMap.values()).indexOf(o1);
368: int index2 = new ArrayList<Category<?>>(
369: categoryMap.values()).indexOf(o2);
370: return Integer.valueOf(index1).compareTo(
371: Integer.valueOf(index2));
372: }
373: });
374:
375: for (int i = 0; i < visibleCategoryList.size(); i++) {
376: Category<?> category = visibleCategoryList.get(i);
377: JButton button = activateButtons.get(i);
378:
379: button.setMargin(new Insets(0, 0, 0, 0));
380: button.setIcon(category.getIconBig());
381: button.setText(category.getTitle());
382: }
383:
384: minimizedCategoryList.clear();
385: minimizedCategoryList.addAll(visibleCategoryList);
386:
387: final ArrayList<Category<?>> toolbarCategoryList = new ArrayList<Category<?>>(
388: categoryMap.values());
389:
390: toolbarButtonPanel.removeAll();
391:
392: if (toolbarVisible) {
393: for (int i = 0; i < toolbarCategoryList.size(); i++) {
394: Category<?> category = toolbarCategoryList.get(i);
395: JButton toolbarButton = new JButton(category
396: .getIconSmall());
397: toolbarButton.setDefaultCapable(false);
398:
399: toolbarButton.setMargin(new Insets(0, 0, 0, 0));
400: final int index = i;
401: toolbarButton.addActionListener(new ActionListener() {
402: public void actionPerformed(@NotNull
403: ActionEvent e) {
404: setMaximizedCategory(toolbarCategoryList
405: .get(index));
406: }
407: });
408: toolbarButton.setToolTipText(category.getTitle());
409:
410: toolbarButtonPanel.add(toolbarButton);
411: }
412: }
413:
414: updatePopupMenu();
415:
416: revalidate();
417: repaint();
418: }
419:
420: private void updatePopupMenu() {
421: popupMenu.removeAll();
422:
423: ArrayList<Category<?>> categoryList = new ArrayList<Category<?>>(
424: categoryMap.values());
425: for (final Category<?> category : categoryList) {
426: JMenuItem menuItem = new JMenuItem(category.getTitle(),
427: category.getIconBig());
428: menuItem.addActionListener(new ActionListener() {
429: public void actionPerformed(@NotNull
430: ActionEvent e) {
431: setMaximizedCategory(category);
432: }
433: });
434:
435: popupMenu.add(menuItem);
436: }
437:
438: popupMenu.addSeparator();
439:
440: moreElementsMenuItem
441: .setEnabled(getVisibleCategoryCount() < categoryList
442: .size());
443: popupMenu.add(moreElementsMenuItem);
444:
445: lessElementsMenuItem.setEnabled(getVisibleCategoryCount() > 0);
446: popupMenu.add(lessElementsMenuItem);
447: }
448:
449: @NotNull
450: public Category<?> getCategory(@NotNull
451: Object key) {
452: return categoryMap.get(key);
453: }
454:
455: @NotNull
456: public Category<?>[] getCategories() {
457: return categoryMap.values().toArray(
458: new Category[categoryMap.size()]);
459: }
460:
461: public void addPropertyChangeListener(@NotNull
462: PropertyChangeListener listener) {
463: propertyChangeSupport.addPropertyChangeListener(listener);
464: }
465:
466: public void removePropertyChangeListener(@NotNull
467: PropertyChangeListener listener) {
468: propertyChangeSupport.removePropertyChangeListener(listener);
469: }
470:
471: @NotNull
472: public PropertyChangeListener[] getPropertyChangeListeners() {
473: return propertyChangeSupport.getPropertyChangeListeners();
474: }
475:
476: public void addPropertyChangeListener(@NotNull
477: String propertyName, @NotNull
478: PropertyChangeListener listener) {
479: propertyChangeSupport.addPropertyChangeListener(propertyName,
480: listener);
481: }
482:
483: public void removePropertyChangeListener(@NotNull
484: String propertyName, @NotNull
485: PropertyChangeListener listener) {
486: propertyChangeSupport.removePropertyChangeListener(
487: propertyName, listener);
488: }
489:
490: @NotNull
491: public PropertyChangeListener[] getPropertyChangeListeners(@NotNull
492: String propertyName) {
493: return propertyChangeSupport
494: .getPropertyChangeListeners(propertyName);
495: }
496:
497: public boolean hasListeners(@NotNull
498: String propertyName) {
499: return propertyChangeSupport.hasListeners(propertyName);
500: }
501:
502: public void updateUI() {
503: super .updateUI();
504: //noinspection ConstantConditions
505: if (popupMenu != null) {
506: SwingUtilities.updateComponentTreeUI(popupMenu);
507: }
508:
509: //noinspection ConstantConditions
510: if (categoryMap != null) {
511: Collection<Category<?>> collection = categoryMap.values();
512: for (Category<?> category : collection) {
513: SwingUtilities.updateComponentTreeUI(category
514: .getMainComponent());
515: }
516: }
517: }
518:
519: }
|