1 /*
2 * (C) 2002 David Carr david@carr.name
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 package net.sourceforge.mflow.confwiz;
20
21 import javax.swing;
22 import java.awt;
23 import java.awt.event;
24 import java.util;
25 import javax.swing.border;
26 import net.sourceforge.mflow;
27 import net.sourceforge.mflow.folder;
28
29 /**
30 * Configuration Wizard Dialog
31 *
32 * @author <a href="mailto:david@carr.name">David Carr</a>
33 */
34 public class ConfWizard extends JDialog {
35 /**
36 * The different screens of the wizard
37 */
38 private JPanel cards;
39 /**
40 * The id of the current screen
41 */
42 private int curPos;
43 /**
44 * The id of the last screen
45 */
46 private static final int maxPos = 6;
47 /**
48 * The button to proceed with the wizard
49 */
50 private JButton btnNext;
51 /**
52 * The button to review your work with the wizard
53 */
54 private JButton btnPrevious = null;
55 /**
56 * Private storage for the dialog's owner
57 */
58 private Frame mOwner = null;
59 /**
60 * Private storage for the MsgSources currently chosen
61 */
62 private Vector vSources = new Vector();
63 /**
64 * Private storage for the MsgReceivers currently chosen
65 */
66 private Vector vReceivers = new Vector();
67 /**
68 * Private storage for the MsgFolders currently chosen
69 */
70 private Vector vFolders = new Vector();
71 /**
72 * Private storage for the pre-MsgFilters currently chosen
73 */
74 private Vector vPreFilters = new Vector();
75 /**
76 * Private storage for the post-MsgFilters currently chosen
77 */
78 private Vector vPostFilters = new Vector();
79 /**
80 * Private storage for the index of the default ReceiveFolder
81 */
82 private int indexDefaultFolder = -1;
83
84
85 /**
86 * Default constructor, creates the interface and event listeners
87 */
88 public ConfWizard(Frame owner) {
89 super(owner);
90 setTitle("MFlow Configuration Wizard");
91 mOwner = owner;
92
93 curPos = 0;
94 Container contentPane = getContentPane();
95
96 cards = new JPanel();
97 cards.setLayout(new CardLayout());
98
99 importConfiguration();
100
101 ClassDefinitionRenderer cdr = new ClassDefinitionRenderer();
102 MsgFlowComponentRenderer mcr = new MsgFlowComponentRenderer();
103
104 JPanel p1 = new JPanel();
105 p1.setBorder(new TitledBorder("Welcome"));
106 JTextArea ta1 = new JTextArea("Welcome to the MFlow Configuration Wizard. WARNING: Using this wizard will over-write any previous configuration. It will provide you with an easy way to configure MFlow to send and receive your messages. First, we'll add MsgSources, where your incoming messages come from. Second, we'll add MsgReceivers, where your outgoing message go. Third, we'll add MsgFolders, where you will view your messages and where your outgoing messages will enter the system. Fourth, we will add any filters that you wish to apply to messages before they reach your incoming message folders. Fifth, we will add any filters that you wish to apply to messages before they are sent.");
107 ta1.setRows(5);
108 ta1.setLineWrap(true);
109 ta1.setColumns(40);
110 ta1.setWrapStyleWord(true);
111 ta1.setBackground(p1.getBackground());
112 ta1.setForeground(Color.BLACK);
113 p1.add(ta1);
114
115 JPanel p2 = new JPanel();
116 p2.setBorder(new TitledBorder("Add MsgSources"));
117 p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS));
118 String[] configedSourceArray = {"AIMSource (davidmc24)", "POPSource (mail.rpi.edu)", "IMAPSource (david.carr.name)"};
119 JPanel pp21 = new JPanel();
120 JPanel pp22 = new JPanel();
121 p2.add(pp21);
122 JComboBox cmb2 = new JComboBox(MFlow.getMsgSourceList());
123 cmb2.setRenderer(cdr);
124 pp21.add(cmb2);
125 pp21.add(new JButton("Add"));
126 JList lst2 = new JList(vSources);
127 lst2.setCellRenderer(mcr);
128 p2.add(new JScrollPane(lst2));
129 pp22.add(new JButton("Remove"));
130 pp22.add(new JButton("Configure"));
131 p2.add(pp22);
132
133 JPanel p3 = new JPanel();
134 p3.setBorder(new TitledBorder("Add MsgReceivers"));
135 p3.setLayout(new BoxLayout(p3, BoxLayout.Y_AXIS));
136 JPanel pp31 = new JPanel();
137 JPanel pp32 = new JPanel();
138 p3.add(pp31);
139 JComboBox cmb3 = new JComboBox(MFlow.getMsgReceiverList());
140 cmb3.setRenderer(cdr);
141 pp31.add(cmb3);
142 pp31.add(new JButton("Add"));
143 JList lst3 = new JList(vReceivers);
144 lst3.setCellRenderer(mcr);
145 p3.add(new JScrollPane(lst3));
146 pp32.add(new JButton("Remove"));
147 pp32.add(new JButton("Configure"));
148 p3.add(pp32);
149
150 JPanel p4 = new JPanel();
151 p4.setBorder(new TitledBorder("Add MsgFolders"));
152 p4.setLayout(new BoxLayout(p4, BoxLayout.Y_AXIS));
153 JPanel pp41 = new JPanel();
154 JPanel pp42 = new JPanel();
155 p4.add(pp41);
156 JComboBox cmb4 = new JComboBox(MFlow.getMsgFolderList());
157 cmb4.setRenderer(cdr);
158 pp41.add(cmb4);
159 pp41.add(new JButton("Add"));
160 JList lst4 = new JList(vFolders);
161 lst4.setCellRenderer(mcr);
162 p4.add(new JScrollPane(lst4));
163 pp42.add(new JButton("Remove"));
164 pp42.add(new JButton("Configure"));
165 pp42.add(new JButton("Set Default"));
166 p4.add(pp42);
167
168 JPanel p5 = new JPanel();
169 p5.setBorder(new TitledBorder("Add Pre-Filters"));
170 p5.setLayout(new BoxLayout(p5, BoxLayout.Y_AXIS));
171 JPanel pp51 = new JPanel();
172 JPanel pp52 = new JPanel();
173 p5.add(pp51);
174 JComboBox cmb5 = new JComboBox(MFlow.getMsgFilterList());
175 cmb5.setRenderer(cdr);
176 pp51.add(cmb5);
177 pp51.add(new JButton("Add"));
178 JList lst5 = new JList(vPreFilters);
179 lst5.setCellRenderer(mcr);
180 p5.add(new JScrollPane(lst5));
181 pp52.add(new JButton("Remove"));
182 pp52.add(new JButton("Configure"));
183 pp52.add(new JButton("Move Up"));
184 pp52.add(new JButton("Move Down"));
185 p5.add(pp52);
186
187 JPanel p6 = new JPanel();
188 p6.setBorder(new TitledBorder("Add Post-Filters"));
189 p6.setLayout(new BoxLayout(p6, BoxLayout.Y_AXIS));
190 JPanel pp61 = new JPanel();
191 JPanel pp62 = new JPanel();
192 p6.add(pp61);
193 JComboBox cmb6 = new JComboBox(MFlow.getMsgFilterList());
194 cmb6.setRenderer(cdr);
195 pp61.add(cmb6);
196 pp61.add(new JButton("Add"));
197 JList lst6 = new JList(vPostFilters);
198 lst6.setCellRenderer(mcr);
199 p6.add(new JScrollPane(lst6));
200 pp62.add(new JButton("Remove"));
201 pp62.add(new JButton("Configure"));
202 pp62.add(new JButton("Move Up"));
203 pp62.add(new JButton("Move Down"));
204 p6.add(pp62);
205
206 JPanel p7 = new JPanel();
207 p7.setBorder(new TitledBorder("Finish Configuration"));
208 JTextArea ta7 = new JTextArea("Congratulations. You have completed MFlow configuration.");
209 ta7.setRows(5);
210 ta7.setLineWrap(true);
211 ta7.setColumns(40);
212 ta7.setWrapStyleWord(true);
213 ta7.setBackground(p1.getBackground());
214 ta7.setForeground(Color.BLACK);
215 p7.add(ta7);
216
217 cards.add(p1, "Intro");
218 cards.add(p2, "Add Sources");
219 cards.add(p3, "Add Receivers");
220 cards.add(p4, "Add Folders");
221 cards.add(p5, "Add Pre-Filters");
222 cards.add(p6, "Add Post-Filters");
223 cards.add(p7, "Finish");
224 contentPane.add(cards, BorderLayout.CENTER);
225
226 JPanel buttonPane = new JPanel();
227 btnPrevious = new JButton("Previous");
228 btnPrevious.setEnabled(false);
229 btnPrevious.addActionListener(new ActionListener() {
230 public void actionPerformed(ActionEvent ae) {
231 if(curPos != 0) {
232 CardLayout cl = (CardLayout)(cards.getLayout());
233 cl.previous(cards);
234 }
235 curPos--;
236 if(curPos < maxPos) {
237 btnNext.setText("Next");
238 } else {
239 btnNext.setText("Finish");
240 }
241 if(curPos > 0) {
242 btnPrevious.setEnabled(true);
243 } else {
244 btnPrevious.setEnabled(false);
245 }
246 }
247 });
248 buttonPane.add(btnPrevious);
249 btnNext = new JButton("Next");
250 btnNext.addActionListener(new ActionListener() {
251 public void actionPerformed(ActionEvent ae) {
252 if(curPos < maxPos) {
253 CardLayout cl = (CardLayout)(cards.getLayout());
254 cl.next(cards);
255 } else {
256 exportConfiguration();
257 close();
258 }
259 curPos++;
260 if(curPos < maxPos) {
261 btnNext.setText("Next");
262 } else {
263 btnNext.setText("Finish");
264 }
265 if(curPos > 0) {
266 btnPrevious.setEnabled(true);
267 } else {
268 btnPrevious.setEnabled(false);
269 }
270 }
271 });
272 buttonPane.add(btnNext);
273
274 contentPane.add(buttonPane, BorderLayout.SOUTH);
275
276 addWindowListener(new WindowAdapter() {
277 public void windowClosing(WindowEvent e) {
278 close();
279 }
280 });
281
282 pack();
283 }
284
285 /**
286 * Disposes of the dialog
287 */
288 private void close() {
289 dispose();
290 }
291
292 /**
293 * Determines whether the passed component is exclusively a MsgSource
294 *
295 * @param c the component to evaluate
296 * @return whether or not it is exclusively a MsgSource
297 */
298 private boolean isSource(MsgFlowComponent c) {
299 return (c instanceof MsgSource) && !(c instanceof MsgReceiver) && !(c instanceof MsgFolder);
300 }
301
302 /**
303 * Determines whether the passed component is exclusively a MsgReceiver
304 *
305 * @param c the component to evaluate
306 * @return whether or not it is exclusively a MsgReceiver
307 */
308 private boolean isReceiver(MsgFlowComponent c) {
309 return (c instanceof MsgReceiver) && !(c instanceof MsgSource) && !(c instanceof MsgFolder);
310 }
311
312 /**
313 * Determines whether the passed component is a MsgFilter
314 *
315 * @param c the component to evaluate
316 * @return whether or not it is exclusively a MsgFilter
317 */
318 private boolean isFilter(MsgFlowComponent c) {
319 return (c instanceof MsgFilter);
320 }
321
322 /**
323 * Determines whether the passed component is a MsgFolder
324 *
325 * @param c the component to evaluate
326 * @return whether or not it is exclusively a MsgFolder
327 */
328 private boolean isFolder(MsgFlowComponent c) {
329 return (c instanceof MsgFolder);
330 }
331
332 /**
333 * Recursive function to determine how many receivers are in the receiver-chain of a MsgSource
334 *
335 * @param src the source to count its receivers
336 * @return the number of receivers of this MsgSource and all its children
337 */
338 private int receiverCount(MsgSource src) {
339 MsgReceiver[] receivers = src.getReceivers();
340 int sum = receivers.length;
341 for(int i=0; i<receivers.length; i++) {
342 if(receivers[i] instanceof MsgSource) {
343 sum += receiverCount((MsgSource) receivers[i]);
344 }
345 }
346 return sum;
347 }
348
349 /**
350 * Imports the current configuration from MFlow
351 */
352 private void importConfiguration() {
353 MsgFlowComponent[] comps = MFlow.getCurrentComponents();
354 for(int i=0; i<comps.length; i++) {
355 MsgFlowComponent c = comps[i];
356 if(isSource(c)) {
357 vSources.add(c);
358 } else if(isReceiver(c)) {
359 vReceivers.add(c);
360 } else if(isFolder(c)) {
361 vFolders.add(c);
362 } else if(isFilter(c)) {
363 MsgFilter f = (MsgFilter)c;
364 MsgReceiver[] receivers = f.getReceivers();
365 boolean allFolders = true;
366 boolean allReceivers = true;
367 for(int j=0; j<receivers.length; j++) {
368 MsgReceiver rCur = receivers[j];
369 if(isFolder(rCur)) {
370 allReceivers = false;
371 }
372 if(isReceiver(rCur)) {
373 allFolders = false;
374 }
375 }
376 if(allFolders) {
377 vPreFilters.add(f);
378 } else if(allReceivers) {
379 vPostFilters.add(f);
380 }//otherwise drop it
381 }//otherwise drop it
382 }
383 int[] rcvCount = new int[vFolders.size()];
384 for(int i=0; i<vSources.size(); i++) {
385 MsgReceiver[] receivers = ((MsgSource)vSources.get(i)).getReceivers();
386 for(int j=0; j<receivers.length; j++) {
387 for(int k=0; k<vFolders.size(); k++) {
388 if(receivers[j].equals(vFolders.get(k))) {
389 rcvCount[k]++;
390 }
391 }
392 }
393 }
394 for(int i=0; i<vPreFilters.size(); i++) {
395 MsgReceiver[] receivers = ((MsgFilter)vPreFilters.get(i)).getReceivers();
396 for(int j=0; j<receivers.length; j++) {
397 for(int k=0; k<vFolders.size(); k++) {
398 if(receivers[j].equals(vFolders.get(k))) {
399 rcvCount[k]++;
400 }
401 }
402 }
403 }
404
405 int maxSourceVal = 0;
406 int maxSourceIndex = -1;
407 int maxReceiveVal = 0;
408 int maxReceiveIndex = -1;
409 for(int i=0; i<vFolders.size(); i++) {
410 Object o = vFolders.get(i);
411 if(o instanceof ReceiveFolder) {
412 if(maxSourceIndex == -1 || rcvCount[i] > maxSourceVal) {
413 maxSourceVal = rcvCount[i];
414 maxSourceIndex = i;
415 }
416 } else if(o instanceof SendFolder) {
417 int rCount = receiverCount((SendFolder) o);
418 if(maxReceiveIndex == -1 || rCount > maxReceiveVal) {
419 maxReceiveVal = rCount;
420 maxReceiveIndex = i;
421 }
422 }
423 }
424
425 Object inbox = null;
426 if(maxSourceIndex != -1) {
427 inbox = vFolders.get(maxSourceIndex);
428 }
429 if(maxReceiveIndex != -1) {
430 SendFolder s = (SendFolder) vFolders.get(maxReceiveIndex);
431 Iterator i = vFolders.iterator();
432 while(i.hasNext()) {
433 Object o = i.next();
434 if(o instanceof SendFolder) {
435 if(s != o) {//keep the one with the most receivers
436 i.remove();//remove extra sendfolders
437 }
438 }
439 }
440 }
441
442 if(inbox != null) {
443 indexDefaultFolder = vFolders.indexOf(inbox);
444 }
445 }
446
447 /**
448 * Exports the new configuration back to MFlow
449 */
450 private void exportConfiguration() {
451 MsgFlowComponent[] curComp = MFlow.getCurrentComponents();
452 for(int i=0; i<curComp.length; i++) {
453 if(curComp[i] instanceof MsgSource) {
454 MsgSource src = (MsgSource) curComp[i];
455 src.setReceivers(new MsgReceiver[0]);
456 }
457 }
458
459 ReceiveFolder inbox = null;
460 SendFolder outbox = null;
461 for(int i=0; i<vFolders.size(); i++) {
462 if(vFolders.get(i) instanceof SendFolder) {
463 outbox = (SendFolder) vFolders.get(i);
464 break;
465 }
466 }
467 try{
468 inbox = (ReceiveFolder) vFolders.get(indexDefaultFolder);
469 } catch(Exception e) {
470 if(MFlow.isDebug()) {
471 e.printStackTrace();
472 }
473 }
474 MsgReceiver firstReceiver = null;
475 MsgSource previousSource = null;
476 for(int i=0; i<vPreFilters.size(); i++) {
477 if(firstReceiver == null) {
478 firstReceiver = (MsgReceiver)vPreFilters.get(i);
479 } else {
480 previousSource.addReceiver((MsgFilter)vPreFilters.get(i));
481 }
482 previousSource = (MsgSource)vPreFilters.get(i);
483 }
484 if(inbox != null) {
485 if(firstReceiver == null) {
486 firstReceiver = inbox;
487 } else {
488 previousSource.addReceiver(inbox);
489 }
490 } else {
491 System.err.println("No inbox");
492 }
493 if(outbox != null) {
494 previousSource = outbox;
495 } else {
496 if(MFlow.isDebug()) {
497 System.err.println("No SendFolder");
498 }
499 }
500 for(int i=0; i<vPostFilters.size(); i++) {
501 previousSource.addReceiver((MsgFilter)vPostFilters.get(i));
502 previousSource = (MsgSource)vPostFilters.get(i);
503 }
504 if(firstReceiver != null) {
505 for(int i=0; i<vSources.size(); i++) {
506 MsgSource src = (MsgSource) vSources.get(i);
507 src.addReceiver(firstReceiver);
508 }
509 } else {
510 if(MFlow.isDebug()) {
511 System.err.println("No first receiver");
512 }
513 }
514 if(previousSource != null) {
515 for(int i=0; i<vReceivers.size(); i++) {
516 MsgReceiver rcv = (MsgReceiver) vReceivers.get(i);
517 previousSource.addReceiver(rcv);
518 }
519 } else {
520 System.err.println("No previous source");
521 }
522
523 Vector master = new Vector();
524 master.addAll(vSources);
525 master.addAll(vReceivers);
526 master.addAll(vFolders);
527 master.addAll(vPreFilters);
528 master.addAll(vPostFilters);
529 MFlow.setCurrentComponents((MsgFlowComponent[])master.toArray(new MsgFlowComponent[master.size()]));
530 }
531 }