001: package com.xoetrope.carousel.survey;
002:
003: import com.xoetrope.survey.Condition;
004: import com.xoetrope.survey.Question;
005: import java.awt.CardLayout;
006: import java.awt.Container;
007: import java.awt.Dimension;
008: import java.awt.Image;
009: import java.awt.Insets;
010: import java.awt.event.ActionEvent;
011: import java.awt.event.ActionListener;
012: import java.io.FileInputStream;
013: import java.lang.reflect.InvocationTargetException;
014: import java.net.URL;
015: import java.util.Enumeration;
016: import java.util.Observable;
017: import java.util.Observer;
018: import java.util.Properties;
019: import java.io.File;
020: import javax.swing.JComboBox;
021: import javax.swing.JOptionPane;
022:
023: import net.xoetrope.debug.DebugLogger;
024: import net.xoetrope.editor.project.XEditorProject;
025: import net.xoetrope.editor.project.XEditorProjectManager;
026: import net.xoetrope.swing.XLabel;
027: import net.xoetrope.xui.XStartupObject;
028: import java.awt.BorderLayout;
029: import java.awt.Toolkit;
030: import javax.swing.ButtonGroup;
031: import javax.swing.ImageIcon;
032: import javax.swing.JButton;
033: import javax.swing.JFileChooser;
034: import javax.swing.JFrame;
035: import javax.swing.JMenu;
036: import javax.swing.JMenuBar;
037: import javax.swing.JMenuItem;
038: import javax.swing.JPanel;
039: import javax.swing.JSplitPane;
040: import javax.swing.JToggleButton;
041: import javax.swing.JToolBar;
042: import javax.swing.filechooser.FileFilter;
043: import net.xoetrope.xui.XProject;
044: import net.xoetrope.xui.XProjectManager;
045:
046: /**
047: * The main frame of the survey editor
048: *
049: * <p> Copyright (c) Xoetrope Ltd., 2001-2006, This software is licensed under
050: * the GNU Public License (GPL), please see license.txt for more details. If
051: * you make commercial use of this software you must purchase a commercial
052: * license from Xoetrope.</p>
053: * <p> $Revision: 1.5 $</p>
054: */
055:
056: public class XSurveyEditorFrame extends JFrame {
057: private static final int FILE = 0;
058: private static final int DB = 1;
059: private static final Insets zeroInsets = new Insets(0, 0, 0, 0);
060:
061: private XProject currentProject;
062: private JPanel tabs;
063: private JToolBar toolBar;
064: private JMenuBar menuBar;
065: private JComboBox langCombo;
066: private CardLayout tabsLayout, iconsLayout;
067: private JToggleButton groupsTool, questionsTool, rulesTool,
068: rulesEditorTool;
069: private JFileChooser fileChooser;
070: private XSurvey survey;
071: private JSplitPane splitPaneGroups, splitPaneQuestions,
072: splitPaneRules;
073: private XGroupsPanel groupsPanel;
074: private XQuestionsPanel groupsQuestionsPanel;
075: private XRulesPanel rulesPanel;
076: private XConditionsPanel conditionsPanel;
077: private XRulesEditorPanel rulesEditorPanel;
078: private XQuestionsPanel questionsPanel;
079: private XOptionsPanel optionsPanel;
080: private String surveyDir;
081: private OutputDbDialog outputDbDialog;
082: private InputDbDialog inputDbDialog;
083: private boolean isStandalone;
084:
085: // properties
086: private Properties langProperties;
087: private String currentSurveyName;
088: private String selectedLangCode;
089:
090: private int surveyInputDataType;
091: private Properties surveyInputDbProperties;
092:
093: private File surveyFile;
094:
095: /**
096: * Creates a new instance of XSurveyEditorFrame
097: * @param standalone indicates whether the editor is run as a standalone application
098: * @param name the name of the survey
099: * @param sFile file containing survey's questions.
100: */
101: public XSurveyEditorFrame(boolean standalone, String name,
102: File sFile) {
103: surveyFile = sFile;
104: isStandalone = standalone;
105:
106: if (!standalone) {
107: currentProject = XEditorProjectManager.getCurrentProject();
108: if ((currentProject == null) && (surveyFile != null)) {
109: String path = surveyFile.getAbsolutePath();
110: currentProject = XEditorProjectManager
111: .getCurrentProject(path);
112: }
113: } else {
114: currentProject = XProjectManager
115: .getCurrentProject((XStartupObject) null);
116: }
117:
118: if (currentProject == null)
119: throw new RuntimeException(
120: "Associated XUI project not found");
121:
122: currentProject.setObject("EditorFrame", this );
123: survey = new XSurvey();
124: currentProject.setObject("Survey", survey);
125:
126: if (!standalone && (surveyFile == null))
127: retrieveProjectProperties();
128:
129: init();
130: setSize();
131:
132: if (!standalone) {
133: reloadCurrentSurvey();
134: rulesEditorPanel.getEditorPane().createView();
135: refreshPanels();
136: }
137:
138: }
139:
140: /**
141: * Creates a new instance of XSurveyEditorFrame
142: * @param standalone indicates whether the editor is run as a standalone application
143: * @param name the name of the survey
144: */
145: public XSurveyEditorFrame(boolean standalone, String name) {
146: this (standalone, name, null);
147: }
148:
149: private File getSurveyFile() {
150: File file = null;
151: if (surveyFile == null) {
152: String path = ((XEditorProject) currentProject).getPath();
153: String fileName = selectedLangCode + "_"
154: + currentSurveyName + ".xml";
155: file = new File(path + File.separator + "lang"
156: + File.separator + fileName);
157: } else {
158: file = surveyFile;
159: }
160: return file;
161: }
162:
163: private String getLanguageName(String langCode) {
164: String langName = null;
165: Enumeration langNamesEnum = langProperties.keys();
166: while ((langName == null) && langNamesEnum.hasMoreElements()) {
167: String ln = (String) langNamesEnum.nextElement();
168: if (langCode.equals(langProperties.getProperty(ln)))
169: langName = ln;
170: }
171: return langName;
172: }
173:
174: protected void retrieveProjectProperties() {
175: currentSurveyName = currentProject
176: .getStartupParam("SurveyName");
177:
178: // language properties
179: selectedLangCode = currentProject.getStartupParam("Language");
180: if (selectedLangCode == null)
181: selectedLangCode = "en";
182: String path = ((XEditorProject) currentProject).getPath();
183: File langsFile = new File(path + File.separator + "lang"
184: + File.separator + "LanguageList.properties");
185: try {
186: langProperties = new Properties();
187: langProperties.load(new FileInputStream(langsFile));
188: } catch (Exception ex) {
189: DebugLogger
190: .logWarning("SurveyEditor: couldn't read the language file.");
191: }
192:
193: // input data
194: String inputType = currentProject
195: .getStartupParam("SurveyInputType");
196: if ("Db".equals(inputType)) {
197: surveyInputDataType = DB;
198: // get the database configuration
199: String user = currentProject
200: .getStartupParam("SurveyInputDbUser");
201: String password = currentProject
202: .getStartupParam("SurveyInputDbPassword");
203: String url = currentProject
204: .getStartupParam("SurveyInputDbUrl");
205: String driver = currentProject
206: .getStartupParam("SurveyInputDbDriver");
207: surveyInputDbProperties = new Properties();
208: surveyInputDbProperties.put("user", user);
209: surveyInputDbProperties.put("password", password);
210: surveyInputDbProperties.put("url", url);
211: surveyInputDbProperties.put("driver", driver);
212: } else {
213: surveyInputDataType = FILE;
214: }
215:
216: }
217:
218: protected void saveCurrentSurvey() {
219: try {
220: if (surveyInputDataType == FILE) {
221: File surveyFile = getSurveyFile();
222: survey.saveSurveyFile(surveyFile);
223: } else if (surveyInputDataType == DB) {
224: String languageName = getLanguageName(selectedLangCode);
225: survey.saveSurveyDb(surveyInputDbProperties,
226: currentSurveyName, selectedLangCode);
227: }
228: } catch (Exception ex) {
229: ex.printStackTrace();
230: }
231: }
232:
233: protected void reloadCurrentSurvey() {
234: survey.clear();
235: try {
236: if (surveyInputDataType == FILE) {
237: File surveyFile = getSurveyFile();
238: survey.loadSurveyFile(surveyFile);
239: } else if (surveyInputDataType == DB) {
240: String languageName = getLanguageName(selectedLangCode);
241: survey.loadSurveyDb(surveyInputDbProperties,
242: currentSurveyName, languageName);
243: }
244: } catch (Exception ex) {
245: ex.printStackTrace();
246: }
247: }
248:
249: protected void setSize() {
250: Dimension size = new Dimension(1024, 768);
251: setSize(size);
252: setPreferredSize(size);
253: }
254:
255: public XRulesPanel getRulesPanel() {
256: return rulesPanel;
257: }
258:
259: public XConditionsPanel getResponsesPanel() {
260: return conditionsPanel;
261: }
262:
263: public XRulesEditorPanel getRulesEditorPanel() {
264: return rulesEditorPanel;
265: }
266:
267: private void init() {
268: setTitle("Survey Editor");
269: setLayout(new BorderLayout());
270:
271: createGroupsComponents();
272: createQuestionsComponents();
273: createRulesComponents();
274: createRulesEditorComponents();
275: createTabs();
276: createToolBar();
277:
278: if (isStandalone) {
279: fileChooser = new JFileChooser();
280: fileChooser.setFileFilter(new SurveyFileFilter());
281: createMenuBar();
282: setJMenuBar(menuBar);
283:
284: // create the dialogs
285: outputDbDialog = new OutputDbDialog();
286: inputDbDialog = new InputDbDialog();
287: }
288:
289: add(toolBar, BorderLayout.NORTH);
290: add(tabs, BorderLayout.CENTER);
291: }
292:
293: public boolean isStandalone() {
294: return isStandalone;
295: }
296:
297: private void createGroupsComponents() {
298: groupsPanel = new XGroupsPanel();
299: groupsQuestionsPanel = new XQuestionsPanel();
300: groupsQuestionsPanel.getGroupComboBox().setVisible(false);
301: groupsQuestionsPanel.getComboBoxLabel().setVisible(false);
302: splitPaneGroups = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
303: groupsPanel, groupsQuestionsPanel);
304: splitPaneGroups.setDividerLocation(400);
305: splitPaneGroups.setDividerSize(20);
306:
307: XGroupsTableModel groupsTableModel = groupsPanel
308: .getGroupsTableModel();
309: XQuestionsTableModel questionsTableModel = groupsQuestionsPanel
310: .getQuestionsTableModel();
311: questionsTableModel.setCurrentGroup(null);
312: questionsTableModel.refresh();
313: groupsTableModel.getNotifier().addObserver(questionsTableModel);
314: groupsTableModel.getNotifier().addObserver(new Observer() {
315: public void update(Observable o, Object arg) {
316: groupsQuestionsPanel.getAddQuestionB().setEnabled(
317: arg != null);
318: }
319: });
320:
321: }
322:
323: private void createQuestionsComponents() {
324: questionsPanel = new XQuestionsPanel();
325: optionsPanel = new XOptionsPanel();
326:
327: splitPaneQuestions = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
328: questionsPanel, optionsPanel);
329: splitPaneQuestions.setDividerLocation(400);
330: splitPaneQuestions.setDividerSize(20);
331:
332: XQuestionsTableModel questionsTableModel = questionsPanel
333: .getQuestionsTableModel();
334: XOptionsTableModel optionsTableModel = optionsPanel
335: .getOptionsTableModel();
336: questionsTableModel.getNotifier()
337: .addObserver(optionsTableModel);
338: questionsTableModel.getNotifier().addObserver(new Observer() {
339: public void update(Observable o, Object arg) {
340: optionsPanel.getAddOptionB().setEnabled(arg != null);
341: }
342: });
343: }
344:
345: private void createRulesComponents() {
346: rulesPanel = new XRulesPanel();
347: conditionsPanel = new XConditionsPanel();
348:
349: splitPaneRules = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
350: rulesPanel, conditionsPanel);
351: splitPaneRules.setDividerLocation(300);
352: splitPaneRules.setDividerSize(20);
353:
354: XRulesTableModel rulesTableModel = rulesPanel
355: .getRulesTableModel();
356: XConditionsTableModel responsesTableModel = conditionsPanel
357: .getResponsesTableModel();
358: rulesTableModel.getNotifier().addObserver(responsesTableModel);
359: rulesTableModel.getNotifier().addObserver(new Observer() {
360: public void update(Observable o, Object arg) {
361: conditionsPanel.getAddConditionB().setEnabled(
362: arg != null);
363: }
364: });
365: }
366:
367: private void createRulesEditorComponents() {
368: rulesEditorPanel = new XRulesEditorPanel();
369: }
370:
371: private void createTabs() {
372: tabs = new JPanel();
373: tabsLayout = new CardLayout();
374: tabs.setLayout(tabsLayout);
375: tabs.add(splitPaneQuestions, "Survey");
376: tabs.add(splitPaneGroups, "Groups");
377: tabs.add(splitPaneQuestions, "Questions");
378: tabs.add(splitPaneRules, "Rules");
379: tabs.add(rulesEditorPanel, "Editor");
380: }
381:
382: private void createMenuBar() {
383: menuBar = new JMenuBar();
384:
385: JMenu menuFile = new JMenu("File");
386: JMenuItem newFileItem = new JMenuItem("New");
387: JMenuItem openFileItem = new JMenuItem("Open...");
388: JMenuItem saveFileItem = new JMenuItem("Save");
389: JMenuItem saveDbItem = new JMenuItem("Save to database");
390: JMenuItem loadDbItem = new JMenuItem("Load from database");
391:
392: menuFile.add(newFileItem);
393: menuFile.add(openFileItem);
394: menuFile.add(saveFileItem);
395: menuFile.add(saveDbItem);
396: menuFile.add(loadDbItem);
397: menuBar.add(menuFile);
398:
399: newFileItem.addActionListener(new ActionListener() {
400: public void actionPerformed(ActionEvent e) {
401: newSurvey();
402: }
403: });
404: openFileItem.addActionListener(new ActionListener() {
405: public void actionPerformed(ActionEvent e) {
406: openSurvey();
407: }
408: });
409: saveFileItem.addActionListener(new ActionListener() {
410: public void actionPerformed(ActionEvent e) {
411: saveFileSurvey();
412: }
413: });
414: saveDbItem.addActionListener(new ActionListener() {
415: public void actionPerformed(ActionEvent e) {
416: saveDbSurvey();
417: }
418: });
419: loadDbItem.addActionListener(new ActionListener() {
420: public void actionPerformed(ActionEvent e) {
421: loadDbSurvey();
422: }
423: });
424: }
425:
426: public void showGroup(XQuestionGroup group) {
427: groupsPanel.getGroupsTableModel().selectGroup(group);
428: tabsLayout.show(tabs, "Groups");
429: groupsTool.setSelected(true);
430: }
431:
432: public void showQuestion(Question question) {
433: questionsPanel.showQuestion(question);
434: tabsLayout.show(tabs, "Questions");
435: questionsTool.setSelected(true);
436: }
437:
438: public void showRule(XRule rule) {
439: tabsLayout.show(tabs, "Rules");
440: rulesPanel.showRule(rule);
441: rulesTool.setSelected(true);
442: }
443:
444: public void showCondition(XRule rule, Condition condition) {
445: tabsLayout.show(tabs, "Rules");
446: rulesPanel.showRule(rule);
447: conditionsPanel.showCondition(condition);
448: rulesTool.setSelected(true);
449: }
450:
451: private void createLangCombo() {
452: XLabel langLabel = new XLabel();
453: langLabel.setText(" Language ");
454: toolBar.add(langLabel);
455:
456: Object[] langs = langProperties.keySet().toArray();
457: String langName = getLanguageName(selectedLangCode);
458: langCombo = new JComboBox(langs);
459: langCombo.setSelectedItem(langName);
460: langCombo.addActionListener(new ActionListener() {
461: public void actionPerformed(ActionEvent e) {
462: String langName = (String) langCombo.getSelectedItem();
463: selectedLangCode = langProperties.getProperty(langName);
464: reloadCurrentSurvey();
465: rulesEditorPanel.getEditorPane().createView();
466: refreshPanels();
467: }
468: });
469:
470: Dimension size = new Dimension(128, 18);
471: langCombo.setSize(size);
472: langCombo.setPreferredSize(size);
473: langCombo.setMaximumSize(size);
474:
475: toolBar.add(langCombo);
476: }
477:
478: private void createToolBar() {
479: toolBar = new JToolBar();
480:
481: rulesEditorTool = addToggleButton("editor.png", "rules editor",
482: toolBar);
483: groupsTool = addToggleButton("group.png",
484: "question groups properties", toolBar);
485: questionsTool = addToggleButton("question.png",
486: "questions properties", toolBar);
487: rulesTool = addToggleButton("rule.png", "rules properties",
488: toolBar);
489:
490: ButtonGroup buttonGroup = new ButtonGroup();
491: buttonGroup.add(rulesEditorTool);
492: buttonGroup.add(groupsTool);
493: buttonGroup.add(questionsTool);
494: buttonGroup.add(rulesTool);
495:
496: // we show the language combo box only when there was no
497: // survey file given explicitly
498: if (!isStandalone && (surveyFile == null))
499: createLangCombo();
500:
501: groupsTool.addActionListener(new ActionListener() {
502: public void actionPerformed(ActionEvent e) {
503: tabsLayout.show(tabs, "Groups");
504: refreshPanels();
505: }
506: });
507: questionsTool.addActionListener(new ActionListener() {
508: public void actionPerformed(ActionEvent e) {
509: tabsLayout.show(tabs, "Questions");
510: refreshPanels();
511: }
512: });
513: rulesTool.addActionListener(new ActionListener() {
514: public void actionPerformed(ActionEvent e) {
515: tabsLayout.show(tabs, "Rules");
516: refreshPanels();
517: }
518: });
519: rulesEditorTool.addActionListener(new ActionListener() {
520: public void actionPerformed(ActionEvent e) {
521: tabsLayout.show(tabs, "Editor");
522: }
523: });
524:
525: questionsTool.setSelected(true);
526: tabsLayout.show(tabs, "Questions");
527: }
528:
529: private void refreshPanels() {
530: questionsPanel.refresh();
531: rulesPanel.refresh();
532: if (survey.getGroups().size() > 0) {
533: questionsPanel.getGroupComboBox().setSelectedIndex(0);
534: rulesPanel.getGroupComboBox().setSelectedIndex(0);
535: }
536: questionsPanel.getQuestionsTableModel().refresh();
537: optionsPanel.getOptionsTableModel().refresh();
538: rulesPanel.getRulesTableModel().refresh();
539: conditionsPanel.getResponsesTableModel().refresh();
540: groupsPanel.getGroupsTableModel().refresh();
541: groupsQuestionsPanel.getQuestionsTableModel().refresh();
542: }
543:
544: private JToggleButton addToggleButton(String imageName,
545: String toolTipText, Container container) {
546: JToggleButton tool = new JToggleButton();
547: ImageIcon icon = loadImageIcon(imageName, toolTipText);
548: if (icon != null)
549: tool.setIcon(icon);
550: tool.setSize(new Dimension(24, 24));
551: tool.setActionCommand(toolTipText);
552: tool.setMargin(zeroInsets);
553: tool.setToolTipText(toolTipText);
554: container.add(tool);
555: return tool;
556: }
557:
558: public JButton addButton(String imageName, String tooltipText,
559: Container container) {
560: JButton tool = new JButton();
561: ImageIcon icon = loadImageIcon(imageName, tooltipText);
562: if (icon != null)
563: tool.setIcon(icon);
564: tool.setSize(new Dimension(24, 24));
565: tool.setActionCommand(tooltipText);
566: tool.setMargin(zeroInsets);
567: tool.setToolTipText(tooltipText);
568: container.add(tool);
569: return tool;
570: }
571:
572: public ImageIcon loadImageIcon(String filename, String description) {
573: ImageIcon icon = null;
574: try {
575: URL url = getClass().getResource(
576: "/com/xoetrope/resources/icons/" + filename);
577: Image image = Toolkit.getDefaultToolkit().createImage(url);
578: icon = new ImageIcon(image, description);
579: } catch (RuntimeException ex) {
580: }
581: return icon;
582: }
583:
584: protected void newSurvey() {
585: saveFileSurvey();
586: survey.clear();
587: refreshPanels();
588: }
589:
590: protected void openSurvey() {
591: String surveyDirectoryName = ".";
592: fileChooser.setCurrentDirectory(new File(surveyDirectoryName));
593: int returnVal = fileChooser.showOpenDialog(this );
594: if (returnVal == JFileChooser.APPROVE_OPTION) {
595: File file = fileChooser.getSelectedFile();
596: try {
597: survey.clear();
598: survey.loadSurveyFile(file);
599: rulesEditorPanel.getEditorPane().createView();
600: refreshPanels();
601: } catch (Exception e) {
602: e.printStackTrace();
603: }
604: }
605: }
606:
607: protected void saveFileSurvey() {
608: int returnVal = fileChooser.showSaveDialog(this );
609: if (returnVal == JFileChooser.APPROVE_OPTION) {
610: File file = fileChooser.getSelectedFile();
611: try {
612: survey.saveSurveyFile(file);
613: } catch (Exception e) {
614: e.printStackTrace(); //@todo show an error dialog
615: }
616: }
617: }
618:
619: protected void saveDbSurvey() {
620: if (outputDbDialog.showDialog()) {
621: String user = outputDbDialog.getDbUser();
622: String password = outputDbDialog.getDbPassword();
623: String url = outputDbDialog.getDbUrl();
624: String driver = outputDbDialog.getDbDriver();
625: String surveyName = outputDbDialog.getSurveyName();
626: String surveyLanguage = outputDbDialog.getSurveyLanguage();
627:
628: Properties outputDbConfig = new Properties();
629: outputDbConfig.put("user", user);
630: outputDbConfig.put("password", password);
631: outputDbConfig.put("url", url);
632: outputDbConfig.put("driver", driver);
633:
634: try {
635: survey.saveSurveyDb(outputDbConfig, surveyName,
636: surveyLanguage);
637: } catch (Exception ex) {
638: ex.printStackTrace();
639: JOptionPane
640: .showMessageDialog(this ,
641: "Couldn't save the survey. Please check the database connection settings.");
642: }
643: }
644: }
645:
646: public void loadDbSurvey() {
647: if (inputDbDialog.showDialog()) {
648: String user = inputDbDialog.getDbUser();
649: String password = inputDbDialog.getDbPassword();
650: String url = inputDbDialog.getDbUrl();
651: String driver = inputDbDialog.getDbDriver();
652: String surveyName = inputDbDialog.getSurveyName();
653: String surveyLanguage = inputDbDialog.getSurveyLanguage();
654:
655: Properties inputDbConfig = new Properties();
656: inputDbConfig.put("user", user);
657: inputDbConfig.put("password", password);
658: inputDbConfig.put("url", url);
659: inputDbConfig.put("driver", driver);
660:
661: try {
662: survey.clear();
663: survey.loadSurveyDb(inputDbConfig, surveyName,
664: surveyLanguage);
665: rulesEditorPanel.getEditorPane().createView();
666: refreshPanels();
667: } catch (Exception ex) {
668: ex.printStackTrace();
669: JOptionPane.showMessageDialog(this ,
670: "Couldn't load the survey.");
671: }
672: }
673: }
674:
675: private class SurveyFileFilter extends FileFilter {
676: public boolean accept(File file) {
677: if (file.isDirectory())
678: return true;
679: return file.getName().endsWith(".xml");
680: }
681:
682: public String getDescription() {
683: return "surveys (*.xml)";
684: }
685: }
686:
687: }
|