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.crm.report.wizard.reportgeneratewizard;
015:
016: import com.jgoodies.forms.layout.CellConstraints;
017: import com.jgoodies.forms.layout.FormLayout;
018: import org.jetbrains.annotations.NonNls;
019: import org.jetbrains.annotations.NotNull;
020: import org.jetbrains.annotations.Nullable;
021: import org.pentaho.reportdesigner.crm.report.IconLoader;
022: import org.pentaho.reportdesigner.crm.report.connection.ColumnInfo;
023: import org.pentaho.reportdesigner.crm.report.wizard.AbstractWizardPage;
024: import org.pentaho.reportdesigner.crm.report.wizard.WizardData;
025: import org.pentaho.reportdesigner.lib.client.components.ComponentFactory;
026: import org.pentaho.reportdesigner.lib.client.i18n.TranslationManager;
027:
028: import javax.swing.*;
029: import javax.swing.event.ListSelectionEvent;
030: import javax.swing.event.ListSelectionListener;
031: import java.awt.*;
032: import java.awt.event.ActionEvent;
033: import java.awt.event.ActionListener;
034: import java.awt.event.MouseAdapter;
035: import java.awt.event.MouseEvent;
036: import java.awt.geom.Rectangle2D;
037: import java.util.ArrayList;
038: import java.util.Collections;
039: import java.util.LinkedHashSet;
040:
041: /**
042: * User: Martin
043: * Date: 20.01.2006
044: * Time: 09:48:17
045: */
046: public class WizardPageGroups extends AbstractWizardPage {
047: @NotNull
048: private JPanel centerPanel;
049:
050: @NotNull
051: private JButton addButton;
052: @NotNull
053: private JButton removeButton;
054:
055: @NotNull
056: private JButton upButton;
057: @NotNull
058: private JButton downButton;
059:
060: @NotNull
061: private GroupsPanel groupsPanel;
062: @NotNull
063: private JList columnsList;
064: @NotNull
065: private DefaultListModel columnListModel;
066:
067: @NotNull
068: private GroupsModel groupsModel;
069:
070: public WizardPageGroups() {
071: addButton = ComponentFactory.createButton("R",
072: "WizardPageGroup.ButtonAdd");
073: removeButton = ComponentFactory.createButton("R",
074: "WizardPageGroup.ButtonRemove");
075:
076: upButton = ComponentFactory.createButton("R",
077: "WizardPageGroup.ButtonUp");
078: downButton = ComponentFactory.createButton("R",
079: "WizardPageGroup.ButtonDown");
080:
081: @NonNls
082: FormLayout formLayout = new FormLayout(
083: "4dlu, fill:10dlu:grow, 4dlu, default, 4dlu, fill:10dlu:grow, 4dlu, default, 4dlu",
084: "4dlu, " + "fill:pref:grow, " + "4dlu, " + "pref, "
085: + "4dlu, " + "pref, " + "4dlu, "
086: + "fill:pref:grow, " + "4dlu");
087:
088: centerPanel = new JPanel(formLayout);
089: @NonNls
090: CellConstraints cc = new CellConstraints();
091:
092: columnListModel = new DefaultListModel();
093: columnsList = new JList(columnListModel);
094: columnsList.setCellRenderer(new ColumnInfoListCellRenderer());
095: centerPanel.add(new JScrollPane(columnsList), cc.xywh(2, 2, 1,
096: 7, "fill, fill"));
097:
098: centerPanel.add(addButton, cc.xy(4, 4));
099: centerPanel.add(removeButton, cc.xy(4, 6));
100:
101: groupsModel = new GroupsModel();
102: groupsPanel = new GroupsPanel(groupsModel,
103: new ArrayList<ColumnInfo>(), columnsList
104: .getBackground(), columnsList.getForeground(),
105: columnsList.getSelectionBackground(), columnsList
106: .getSelectionForeground());
107: centerPanel.add(new JScrollPane(groupsPanel), cc.xywh(6, 2, 1,
108: 7, "fill, fill"));
109:
110: centerPanel.add(upButton, cc.xy(8, 4));
111: centerPanel.add(downButton, cc.xy(8, 6));
112:
113: addButton.setEnabled(false);
114: removeButton.setEnabled(false);
115:
116: upButton.setEnabled(false);
117: downButton.setEnabled(false);
118:
119: columnsList
120: .addListSelectionListener(new ListSelectionListener() {
121: public void valueChanged(@NotNull
122: ListSelectionEvent e) {
123: if (!e.getValueIsAdjusting()) {
124: addButton.setEnabled(columnsList
125: .getSelectedValues().length > 0);
126: }
127: }
128: });
129:
130: groupsPanel.addMouseListener(new MouseAdapter() {
131: public void mouseClicked(@NotNull
132: MouseEvent e) {
133: boolean selected = false;
134: ArrayList<Rectangle> groupLocations = groupsPanel
135: .getGroupLocations();
136: for (int i = 0; i < groupLocations.size(); i++) {
137: Rectangle rectangle = groupLocations.get(i);
138: if (rectangle.contains(e.getPoint())) {
139: groupsPanel.setSelectedGroup(groupsModel
140: .getGroupInfos().get(i));
141: removeButton.setEnabled(true);
142: selected = true;
143: }
144: }
145:
146: if (!selected) {
147: groupsPanel.setSelectedGroup(null);
148: removeButton.setEnabled(false);
149: upButton.setEnabled(false);
150: downButton.setEnabled(false);
151: } else {
152: int index = groupsModel.getGroupInfos().indexOf(
153: groupsPanel.getSelectedGroup());
154: upButton.setEnabled(index > 0);
155: downButton.setEnabled(index < groupsModel
156: .getGroupInfos().size() - 1);
157: }
158: }
159: });
160:
161: addButton.addActionListener(new ActionListener() {
162: public void actionPerformed(@NotNull
163: ActionEvent e) {
164: int[] selectedIndices = columnsList
165: .getSelectedIndices();
166: ArrayList<ColumnInfo> columnInfos = new ArrayList<ColumnInfo>();
167: for (int i = selectedIndices.length - 1; i >= 0; i--) {
168: int selectedIndice = selectedIndices[i];
169: ColumnInfo element = (ColumnInfo) columnListModel
170: .getElementAt(selectedIndice);
171: columnListModel.removeElementAt(selectedIndice);
172: columnInfos.add(element);
173: }
174:
175: Collections.reverse(columnInfos);
176:
177: groupsModel.addGroup(new GroupInfo(columnInfos));
178: }
179: });
180:
181: removeButton.addActionListener(new ActionListener() {
182: public void actionPerformed(@NotNull
183: ActionEvent e) {
184: GroupInfo selectedGroup = groupsPanel
185: .getSelectedGroup();
186:
187: if (selectedGroup != null) {
188: groupsModel.removeGroupInfo(selectedGroup);
189: groupsPanel.setSelectedGroup(null);
190:
191: //noinspection unchecked
192: @Nullable
193: ArrayList<ColumnInfo> columnInfos = (ArrayList<ColumnInfo>) getWizardDialog()
194: .getWizardDatas().get(
195: WizardData.COLUMN_INFOS).getValue();
196: columnListModel.clear();
197: if (columnInfos != null) {
198: for (ColumnInfo columnInfo : columnInfos) {
199: columnListModel.addElement(columnInfo);
200: }
201: }
202: }
203:
204: removeButton.setEnabled(false);
205: upButton.setEnabled(false);
206: downButton.setEnabled(false);
207: }
208: });
209:
210: upButton.addActionListener(new ActionListener() {
211: public void actionPerformed(@NotNull
212: ActionEvent e) {
213: if (groupsPanel.getSelectedGroup() != null) {
214: int index = groupsModel.getGroupInfos().indexOf(
215: groupsPanel.getSelectedGroup());
216: if (index > 0) {
217: groupsModel.moveGroup(index, index - 1);
218: }
219: index = groupsModel.getGroupInfos().indexOf(
220: groupsPanel.getSelectedGroup());
221: upButton.setEnabled(index > 0);
222: downButton.setEnabled(index < groupsModel
223: .getGroupInfos().size() - 1);
224: }
225: }
226: });
227:
228: downButton.addActionListener(new ActionListener() {
229: public void actionPerformed(@NotNull
230: ActionEvent e) {
231: if (groupsPanel.getSelectedGroup() != null) {
232: int index = groupsModel.getGroupInfos().indexOf(
233: groupsPanel.getSelectedGroup());
234: if (index < groupsModel.getGroupInfos().size() - 1) {
235: groupsModel.moveGroup(index, index + 1);
236: }
237: index = groupsModel.getGroupInfos().indexOf(
238: groupsPanel.getSelectedGroup());
239: upButton.setEnabled(index > 0);
240: downButton.setEnabled(index < groupsModel
241: .getGroupInfos().size() - 1);
242: }
243: }
244: });
245: }
246:
247: @NotNull
248: public JComponent getCenterPanel() {
249: @Nullable
250: WizardData wizardData = getWizardDialog().getWizardDatas().get(
251: WizardData.COLUMN_INFOS);
252: if (wizardData != null) {
253: Object ci = wizardData.getValue();
254: if (ci instanceof ArrayList) {
255: //noinspection unchecked
256: ArrayList<ColumnInfo> columnInfos = (ArrayList<ColumnInfo>) ci;
257: columnListModel.clear();
258: for (ColumnInfo columnInfo : columnInfos) {
259: columnListModel.addElement(columnInfo);
260: }
261: groupsPanel.setSelectedGroup(null);
262: groupsPanel.setPossibleColumnInfos(columnInfos);
263: }
264: }
265: return centerPanel;
266: }
267:
268: @NotNull
269: public String getTitle() {
270: return TranslationManager.getInstance().getTranslation("R",
271: "WizardPageGroup.Title");
272: }
273:
274: @Nullable
275: public ImageIcon getIcon() {
276: return IconLoader.getInstance().getWizardPageGroupIcon();
277: }
278:
279: @NotNull
280: public String getDescription() {
281: return TranslationManager.getInstance().getTranslation("R",
282: "WizardPageGroup.Description");
283: }
284:
285: public void dispose() {
286: }
287:
288: public boolean canNext() {
289: return true;
290: }
291:
292: public boolean canPrevious() {
293: return true;
294: }
295:
296: public boolean canCancel() {
297: return true;
298: }
299:
300: public boolean canFinish() {
301: return true;
302: }
303:
304: @NotNull
305: public WizardData[] getWizardDatas() {
306: return new WizardData[] { new WizardData(
307: WizardData.COLUMN_GROUPS, new ArrayList<GroupInfo>(
308: groupsModel.getGroupInfos())) };
309: }
310:
311: private static class GroupsPanel extends JPanel implements
312: GroupsModelListener {
313: @NotNull
314: private GroupsModel groupsModel;
315: @NotNull
316: private Color background;
317: @NotNull
318: private Color foreground;
319: @NotNull
320: private Color selectionBackgrouond;
321: @NotNull
322: private Color selectionForeground;
323: @Nullable
324: private GroupInfo selectedGroup;
325:
326: @NotNull
327: private ArrayList<Rectangle> groupLocations;
328: @NotNull
329: private ArrayList<ColumnInfo> possibleColumnInfos;
330:
331: private GroupsPanel(@NotNull
332: GroupsModel groupsModel, @NotNull
333: ArrayList<ColumnInfo> possibleColumnInfos, @NotNull
334: Color background, @NotNull
335: Color foreground, @NotNull
336: Color selectionBackgrouond, @NotNull
337: Color selectionForeground) {
338: this .groupsModel = groupsModel;
339: this .background = background;
340: this .foreground = foreground;
341: this .selectionBackgrouond = selectionBackgrouond;
342: this .selectionForeground = selectionForeground;
343:
344: groupLocations = new ArrayList<Rectangle>();
345: groupsModel.addGroupsModelListener(this );
346: this .possibleColumnInfos = possibleColumnInfos;
347: }
348:
349: public void setPossibleColumnInfos(@NotNull
350: ArrayList<ColumnInfo> possibleColumnInfos) {
351: this .possibleColumnInfos = possibleColumnInfos;
352: }
353:
354: @Nullable
355: public GroupInfo getSelectedGroup() {
356: return selectedGroup;
357: }
358:
359: public void setSelectedGroup(@Nullable
360: GroupInfo groupInfo) {
361: this .selectedGroup = groupInfo;
362: repaint();
363: }
364:
365: @NotNull
366: public ArrayList<Rectangle> getGroupLocations() {
367: return new ArrayList<Rectangle>(groupLocations);
368: }
369:
370: public void modelChanged() {
371: if (!groupsModel.getGroupInfos().contains(selectedGroup)) {
372: selectedGroup = null;
373: }
374: repaint();
375: }
376:
377: protected void paintComponent(@NotNull
378: Graphics g) {
379: int borderInset = 5;
380: int paperInset = 10;
381: int inset = 5;
382: int insetPerGroup = 20;
383: int currentY = paperInset + borderInset;
384:
385: g.setColor(Color.WHITE);
386: g.fillRect(0, 0, getWidth(), getHeight());
387:
388: groupLocations.clear();
389:
390: ArrayList<ColumnInfo> pci = new ArrayList<ColumnInfo>(
391: possibleColumnInfos);
392:
393: ArrayList<GroupInfo> groupInfos = groupsModel
394: .getGroupInfos();
395: for (int i = 0; i < groupInfos.size(); i++) {
396: GroupInfo groupInfo = groupInfos.get(i);
397: StringBuilder sb = new StringBuilder(100);
398: ArrayList<ColumnInfo> columnInfos = groupInfo
399: .getColumnInfos();
400: for (int j = 0; j < columnInfos.size(); j++) {
401: ColumnInfo columnInfo = columnInfos.get(j);
402: sb.append(columnInfo.getColumnName());
403: if (j < columnInfos.size() - 1) {
404: sb.append(", ");
405: }
406: pci.remove(columnInfo);
407: }
408:
409: Rectangle2D stringBounds = g.getFontMetrics()
410: .getStringBounds(sb.toString(), g);
411: Rectangle rectangle = new Rectangle(i * insetPerGroup
412: + paperInset + borderInset, currentY,
413: getWidth() - (i * insetPerGroup) - 2
414: * paperInset - 2 * borderInset - 1,
415: (int) (stringBounds.getHeight() + 0.5) + 2
416: * inset);
417: groupLocations.add(rectangle);
418:
419: //noinspection ObjectEquality
420: if (selectedGroup == groupInfo) {
421: g.setColor(selectionBackgrouond);
422: } else {
423: g.setColor(background);
424: }
425: g.fillRect(rectangle.x, rectangle.y, rectangle.width,
426: rectangle.height);
427:
428: g.setColor(Color.DARK_GRAY);
429: g.drawRect(rectangle.x, rectangle.y, rectangle.width,
430: rectangle.height);
431:
432: //noinspection ObjectEquality
433: if (selectedGroup == groupInfo) {
434: g.setColor(selectionForeground);
435: } else {
436: g.setColor(foreground);
437: }
438:
439: Shape clip = g.getClip();
440: g.clipRect(rectangle.x, rectangle.y, rectangle.width,
441: rectangle.height);
442: g.drawString(sb.toString(), i * insetPerGroup + inset
443: + paperInset + borderInset, (int) (currentY
444: + -stringBounds.getY() + inset));
445: g.setClip(clip);
446:
447: currentY += (int) (stringBounds.getHeight() + 0.5) + 2
448: * inset + 5;
449: }
450:
451: StringBuilder sb2 = new StringBuilder(100);
452: for (int j = 0; j < pci.size(); j++) {
453: ColumnInfo columnInfo = pci.get(j);
454: sb2.append(columnInfo.getColumnName());
455: if (j < pci.size() - 1) {
456: sb2.append(", ");
457: }
458: }
459:
460: int i = groupInfos.size() - 1;
461: if (i == -1) {
462: i = 0;
463: insetPerGroup = 0;
464: }
465: Rectangle2D stringBounds = g.getFontMetrics()
466: .getStringBounds(sb2.toString(), g);
467: Rectangle rectangle = new Rectangle(i * insetPerGroup
468: + (insetPerGroup / 2) + paperInset + borderInset,
469: currentY, getWidth() - (i * insetPerGroup)
470: - insetPerGroup / 2 - 1 - 2 * paperInset
471: - 2 * borderInset, getHeight() - currentY
472: - paperInset - borderInset - 1);
473:
474: g.setColor(Color.LIGHT_GRAY);
475: g.drawRect(rectangle.x, rectangle.y, rectangle.width,
476: rectangle.height);
477:
478: g.setColor(foreground);
479: Shape clip = g.getClip();
480: g.clipRect(rectangle.x, rectangle.y, rectangle.width,
481: rectangle.height);
482: g.drawString(sb2.toString(), i * insetPerGroup
483: + insetPerGroup / 2 + inset + paperInset
484: + borderInset, (int) (currentY
485: + -stringBounds.getY() + inset));
486: g.setClip(clip);
487:
488: g.setColor(Color.GRAY);
489: g.fillRect(0, 0, getWidth(), paperInset);
490: g.fillRect(getWidth() - paperInset, 0, paperInset,
491: getHeight());
492: g.fillRect(0, getHeight() - paperInset, getWidth(),
493: paperInset);
494: g.fillRect(0, 0, paperInset, getHeight());
495:
496: g.setColor(Color.DARK_GRAY);
497: g.fillRect(getWidth() - paperInset, paperInset + paperInset
498: / 2, paperInset / 2, getHeight()
499: - (paperInset + paperInset));
500: g.fillRect(paperInset + paperInset / 2, getHeight()
501: - paperInset, getWidth() - (2 * paperInset),
502: paperInset / 2);
503:
504: }
505: }
506:
507: private static interface GroupsModelListener {
508: void modelChanged();
509: }
510:
511: private static class GroupsModel {
512: @NotNull
513: private LinkedHashSet<GroupsModelListener> groupsModelListeners;
514: @NotNull
515: private ArrayList<GroupInfo> groupInfos;
516:
517: private GroupsModel() {
518: groupsModelListeners = new LinkedHashSet<GroupsModelListener>();
519: groupInfos = new ArrayList<GroupInfo>();
520: }
521:
522: public void addGroup(@NotNull
523: GroupInfo groupInfo) {
524: groupInfos.add(groupInfo);
525: fireModelChanged();
526: }
527:
528: public void removeGroupInfo(@NotNull
529: GroupInfo groupInfo) {
530: groupInfos.remove(groupInfo);
531: fireModelChanged();
532: }
533:
534: public void moveGroup(int index, int destIndex) {
535: GroupInfo groupInfo = groupInfos.remove(index);
536: groupInfos.add(destIndex, groupInfo);
537: fireModelChanged();
538: }
539:
540: @NotNull
541: public ArrayList<GroupInfo> getGroupInfos() {
542: return groupInfos;
543: }
544:
545: public void addGroupsModelListener(@NotNull
546: GroupsModelListener groupsModelListener) {
547: groupsModelListeners.add(groupsModelListener);
548: }
549:
550: public void fireModelChanged() {
551: LinkedHashSet<GroupsModelListener> listeners = new LinkedHashSet<GroupsModelListener>(
552: groupsModelListeners);
553: for (GroupsModelListener groupsModelListener : listeners) {
554: groupsModelListener.modelChanged();
555: }
556: }
557: }
558:
559: }
|