001: /*
002: * Copyright (c) 2004-2006, Jean-François Brazeau. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * 1. Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * 2. Redistributions in binary form must reproduce the above copyright
011: * notice, this list of conditions and the following disclaimer in the
012: * documentation and/or other materials provided with the distribution.
013: *
014: * 3. The name of the author may not be used to endorse or promote products
015: * derived from this software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
018: * IMPLIEDWARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
019: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
020: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
021: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
022: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
023: * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
024: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
025: * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
026: * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: */
028: package jfb.tools.activitymgr.ui;
029:
030: import java.io.File;
031: import java.io.FileInputStream;
032: import java.io.FileOutputStream;
033: import java.io.IOException;
034: import java.util.ArrayList;
035: import java.util.Iterator;
036:
037: import javax.xml.parsers.ParserConfigurationException;
038:
039: import jfb.tools.activitymgr.core.DbException;
040: import jfb.tools.activitymgr.core.ModelException;
041: import jfb.tools.activitymgr.core.ModelMgr;
042: import jfb.tools.activitymgr.core.beans.Duration;
043: import jfb.tools.activitymgr.ui.util.CfgMgr;
044: import jfb.tools.activitymgr.ui.util.SafeRunner;
045: import jfb.tools.activitymgr.ui.util.UITechException;
046:
047: import org.apache.log4j.Logger;
048: import org.eclipse.jface.dialogs.MessageDialog;
049: import org.eclipse.jface.preference.FileFieldEditor;
050: import org.eclipse.jface.util.IPropertyChangeListener;
051: import org.eclipse.jface.util.PropertyChangeEvent;
052: import org.eclipse.swt.SWT;
053: import org.eclipse.swt.events.ModifyEvent;
054: import org.eclipse.swt.events.ModifyListener;
055: import org.eclipse.swt.events.SelectionAdapter;
056: import org.eclipse.swt.events.SelectionEvent;
057: import org.eclipse.swt.layout.FillLayout;
058: import org.eclipse.swt.layout.GridData;
059: import org.eclipse.swt.layout.GridLayout;
060: import org.eclipse.swt.widgets.Button;
061: import org.eclipse.swt.widgets.Combo;
062: import org.eclipse.swt.widgets.Composite;
063: import org.eclipse.swt.widgets.Control;
064: import org.eclipse.swt.widgets.Group;
065: import org.eclipse.swt.widgets.Label;
066: import org.eclipse.swt.widgets.TabItem;
067: import org.eclipse.swt.widgets.Text;
068: import org.xml.sax.SAXException;
069:
070: /**
071: * IHM associée à l'onglet de paramétrage de l'accès à la base de données.
072: */
073: public class DatabaseUI implements ModifyListener {
074:
075: /**
076: * Interface utilisée pour notifier de l'état de la connexion
077: * à la base de données.
078: */
079: public static interface IDbStatusListener {
080:
081: /**
082: * Notifie de l'ouverture de l'accès à la base de données.
083: */
084: public void databaseOpened();
085:
086: /**
087: * Notifie de l'ouverture de la fermeture.
088: */
089: public void databaseClosed();
090:
091: }
092:
093: /** Logger */
094: private static Logger log = Logger.getLogger(DatabaseUI.class);
095:
096: /** Constantes */
097: public static final int STANDALONE_MODE = 0;
098: public static final int MYSQL_SERVER_MODE = 1;
099: public static final int USER_DEFINED_MODE = 2;
100:
101: /** Listener */
102: private ArrayList listeners = new ArrayList();
103:
104: /** Composant parent */
105: private Composite parent;
106:
107: /** Panneau contenant les controles */
108: private Composite centeredPanel;
109:
110: /** Panneau contenant les données de connexion à la BDD */
111: private Composite conectionPanel;
112:
113: /** Panneau contenant les boutons d'export/import */
114: private Composite xmlPanel;
115:
116: /** Champs de saisie, controles et labels */
117: private Label dbTypeLabel;
118: private Combo dbTypeCombo;
119: private Label jdbcDriverLabel;
120: private Text jdbcDriverText;
121: private Label dbHostLabel;
122: private Text dbHostText;
123: private Label dbPortLabel;
124: private Text dbPortText;
125: private FileFieldEditor dbDataFileText;
126: private Label dbNameLabel;
127: private Text dbNameText;
128: private Label jdbcUrlLabel;
129: private Text jdbcUrlText;
130: private Label jdbcUserIdLabel;
131: private Text jdbcUserIdText;
132: private Label jdbcPasswordLabel;
133: private Text jdbcPasswordText;
134: private Label jdbcPasswordWarning;
135: private Button openDbButton;
136: private Button closeDbButton;
137: private Button resetDbDataButton;
138: private FileFieldEditor xmlFileText;
139: private Button xmlExportButton;
140: private Button xmlImportButton;
141:
142: /**
143: * Constructeur permettant de placer l'IHM dans un onglet.
144: * @param tabItem item parent.
145: */
146: public DatabaseUI(TabItem tabItem) {
147: this (tabItem.getParent());
148: tabItem.setControl(parent);
149: }
150:
151: /**
152: * Constructeur par défaut.
153: * @param parentComposite composant parent.
154: */
155: public DatabaseUI(Composite parentComposite) {
156: // Création du composite parent
157: parent = new Composite(parentComposite, SWT.NONE);
158: parent.setLayout(new GridLayout(1, false));
159: centeredPanel = new Composite(parent, SWT.NONE);
160: centeredPanel.setLayoutData(new GridData(SWT.CENTER,
161: SWT.CENTER, true, true));
162: centeredPanel.setLayout(new GridLayout(1, false));
163:
164: // Groupe et pannneau contenant les données de connexion à la BDD
165: Group conectionGroup = new Group(centeredPanel, SWT.NONE);
166: conectionGroup.setText("Connection properties");
167: FillLayout fillLayout = new FillLayout(SWT.VERTICAL);
168: fillLayout.marginWidth = 5;
169: fillLayout.marginHeight = 5;
170: conectionGroup.setLayout(fillLayout);
171: conectionPanel = new Composite(conectionGroup, SWT.NONE);
172: conectionPanel.setLayout(new GridLayout(3, false));
173:
174: // Type de BDD
175: dbTypeLabel = new Label(conectionPanel, SWT.NONE);
176: dbTypeLabel.setText("Database type :");
177: dbTypeCombo = new Combo(conectionPanel, SWT.READ_ONLY);
178: dbTypeCombo.add("Standalone mode (embedded HSQL database)");
179: dbTypeCombo.add("MySQL Server database");
180: dbTypeCombo.add("User defined database");
181: dbTypeCombo.select(STANDALONE_MODE);
182: GridData gridData = new GridData();
183: gridData.horizontalAlignment = SWT.FILL;
184: gridData.horizontalSpan = 2;
185: dbTypeCombo.setLayoutData(gridData);
186: dbTypeCombo.addSelectionListener(new SelectionAdapter() {
187: public void widgetSelected(SelectionEvent e) {
188: // Construction d'un contexte d'exécution sécurisé
189: SafeRunner runner = new SafeRunner() {
190: public Object runUnsafe() throws Exception {
191: dbTypeChanged();
192: return null;
193: }
194: };
195: // Exécution du traitement
196: runner.run(parent.getShell());
197: }
198: });
199:
200: // Driver JDBC
201: jdbcDriverLabel = new Label(conectionPanel, SWT.NONE);
202: jdbcDriverLabel.setText("JDBC Driver :");
203: jdbcDriverText = new Text(conectionPanel, SWT.BORDER);
204: gridData = new GridData();
205: gridData.horizontalAlignment = SWT.FILL;
206: gridData.horizontalSpan = 2;
207: jdbcDriverText.setLayoutData(gridData);
208:
209: // Nom d'hôte & port d'écoute de la BDD
210: dbHostLabel = new Label(conectionPanel, SWT.NONE);
211: dbHostLabel.setText("Database host :");
212: Composite hostAndPortPanel = new Composite(conectionPanel,
213: SWT.NONE);
214: GridLayout layout = new GridLayout(3, false);
215: layout.marginHeight = 0;
216: layout.marginWidth = 0;
217: hostAndPortPanel.setLayout(layout);
218: gridData = new GridData();
219: gridData.horizontalSpan = 2;
220: gridData.horizontalAlignment = SWT.FILL;
221: hostAndPortPanel.setLayoutData(gridData);
222: // Host
223: dbHostText = new Text(hostAndPortPanel, SWT.BORDER);
224: gridData = new GridData();
225: gridData.horizontalAlignment = SWT.FILL;
226: gridData.grabExcessHorizontalSpace = true;
227: dbHostText.setLayoutData(gridData);
228: // Port d'écoute de la BDD
229: dbPortLabel = new Label(hostAndPortPanel, SWT.NONE);
230: dbPortLabel.setText("Port :");
231: dbPortText = new Text(hostAndPortPanel, SWT.BORDER);
232: dbPortText.setText("XXXX");
233:
234: // Fichier de données
235: dbDataFileText = new FileFieldEditor("datafile", "Data file :",
236: conectionPanel);
237:
238: // Nom de la BDD
239: dbNameLabel = new Label(conectionPanel, SWT.NONE);
240: dbNameLabel.setText("Database name :");
241: dbNameText = new Text(conectionPanel, SWT.BORDER);
242: gridData = new GridData();
243: gridData.horizontalAlignment = SWT.FILL;
244: gridData.horizontalSpan = 2;
245: dbNameText.setLayoutData(gridData);
246:
247: // URL de connexion
248: jdbcUrlLabel = new Label(conectionPanel, SWT.NONE);
249: jdbcUrlLabel.setText("Server URL :");
250: jdbcUrlText = new Text(conectionPanel, SWT.BORDER);
251: gridData = new GridData();
252: gridData.widthHint = 250;
253: gridData.horizontalSpan = 2;
254: jdbcUrlText.setLayoutData(gridData);
255:
256: // User de connexion
257: jdbcUserIdLabel = new Label(conectionPanel, SWT.NONE);
258: jdbcUserIdLabel.setText("User ID :");
259: jdbcUserIdText = new Text(conectionPanel, SWT.BORDER);
260: gridData = new GridData();
261: gridData.widthHint = 80;
262: gridData.horizontalSpan = 2;
263: jdbcUserIdText.setLayoutData(gridData);
264:
265: // Password de connexion
266: jdbcPasswordLabel = new Label(conectionPanel, SWT.NONE);
267: jdbcPasswordLabel.setText("Password :");
268: // Panneau contenant le champ + le warning
269: Composite jdbcPasswordAndWarningPanel = new Composite(
270: conectionPanel, SWT.NONE);
271: layout = new GridLayout(2, false);
272: layout.marginHeight = 0;
273: layout.marginWidth = 0;
274: jdbcPasswordAndWarningPanel.setLayout(layout);
275: gridData = new GridData();
276: gridData.horizontalSpan = 2;
277: gridData.horizontalAlignment = SWT.FILL;
278: jdbcPasswordAndWarningPanel.setLayoutData(gridData);
279: // Champ password
280: jdbcPasswordText = new Text(jdbcPasswordAndWarningPanel,
281: SWT.BORDER | SWT.PASSWORD);
282: gridData = new GridData();
283: gridData.widthHint = 80;
284: jdbcPasswordText.setLayoutData(gridData);
285: // Warning
286: jdbcPasswordWarning = new Label(jdbcPasswordAndWarningPanel,
287: SWT.NONE);
288: jdbcPasswordWarning.setText("(password stored in plain text)");
289:
290: // Panneau contenant les boutons d'ouverture/fermeture de la BDD
291: Composite openCloseDbButtonsPanel = new Composite(
292: conectionPanel, SWT.NONE);
293: openCloseDbButtonsPanel.setLayout(new GridLayout(3, false));
294: gridData = new GridData(SWT.CENTER, SWT.CENTER, false, false);
295: gridData.horizontalSpan = 3;
296: openCloseDbButtonsPanel.setLayoutData(gridData);
297:
298: // Bouton d'ouverture/fermeture de la BDD
299: openDbButton = new Button(openCloseDbButtonsPanel, SWT.NONE);
300: openDbButton.setText("Open database");
301: gridData = new GridData(SWT.CENTER, SWT.CENTER, false, false);
302: openDbButton.setLayoutData(gridData);
303: openDbButton.addSelectionListener(new SelectionAdapter() {
304: public void widgetSelected(SelectionEvent e) {
305: SafeRunner runner = new SafeRunner() {
306: public Object runUnsafe() throws Exception {
307: openDatabase();
308: return null;
309: }
310: };
311: // Exécution du traitement
312: runner.run(parent.getShell());
313: }
314: });
315: closeDbButton = new Button(openCloseDbButtonsPanel, SWT.NONE);
316: closeDbButton.setText("Close database");
317: gridData = new GridData(SWT.CENTER, SWT.CENTER, false, false);
318: closeDbButton.setLayoutData(gridData);
319: closeDbButton.addSelectionListener(new SelectionAdapter() {
320: public void widgetSelected(SelectionEvent e) {
321: SafeRunner runner = new SafeRunner() {
322: public Object runUnsafe() throws Exception {
323: closeDatabase();
324: return null;
325: }
326: };
327: // Exécution du traitement
328: runner.run(parent.getShell());
329: }
330: });
331: // Désactivation du bouton
332: closeDbButton.setEnabled(false);
333:
334: // Bouton de réinstallation de la base de données
335: resetDbDataButton = new Button(openCloseDbButtonsPanel,
336: SWT.NONE);
337: resetDbDataButton.setText("Reset database data");
338: gridData = new GridData(SWT.CENTER, SWT.CENTER, false, false);
339: resetDbDataButton.setLayoutData(gridData);
340: resetDbDataButton.addSelectionListener(new SelectionAdapter() {
341: public void widgetSelected(SelectionEvent e) {
342: SafeRunner runner = new SafeRunner() {
343: public Object runUnsafe() throws Exception {
344: reinstallDatabaseWithWarnings();
345: return null;
346: }
347: };
348: // Exécution du traitement
349: runner.run(parent.getShell());
350: }
351: });
352: // Désactivation du bouton
353: resetDbDataButton.setEnabled(false);
354:
355: // Groupe et pannneau contenant les bouton d'export/import
356: Group xmlGroup = new Group(centeredPanel, SWT.NONE);
357: xmlGroup.setLayoutData(new GridData(SWT.FILL, SWT.NONE, false,
358: false));
359: xmlGroup.setText("Export/import");
360: xmlGroup.setLayout(fillLayout);
361: xmlPanel = new Composite(xmlGroup, SWT.NONE);
362: xmlPanel.setLayout(new GridLayout(3, false));
363:
364: // Fichier de données
365: xmlFileText = new FileFieldEditor("xmlFile", "XML file :",
366: xmlPanel);
367: disableField(xmlFileText, xmlPanel);
368:
369: // Panneau contenant les boutons d'ouverture/fermeture de la BDD
370: Composite xmlButtonsPanel = new Composite(xmlPanel, SWT.NONE);
371: xmlButtonsPanel.setLayout(new GridLayout(2, false));
372: gridData = new GridData(SWT.CENTER, SWT.CENTER, false, false);
373: gridData.horizontalSpan = 3;
374: xmlButtonsPanel.setLayoutData(gridData);
375:
376: // Bouton d'ouverture/fermeture de la BDD
377: xmlExportButton = new Button(xmlButtonsPanel, SWT.NONE);
378: xmlExportButton.setText("Export database");
379: gridData = new GridData(SWT.CENTER, SWT.CENTER, false, false);
380: xmlExportButton.setLayoutData(gridData);
381: xmlExportButton.addSelectionListener(new SelectionAdapter() {
382: public void widgetSelected(SelectionEvent e) {
383: SafeRunner runner = new SafeRunner() {
384: public Object runUnsafe() throws Exception {
385: exportToXML();
386: return null;
387: }
388: };
389: // Exécution du traitement
390: runner.run(parent.getShell());
391: }
392: });
393: disableField(xmlExportButton);
394: xmlImportButton = new Button(xmlButtonsPanel, SWT.NONE);
395: xmlImportButton.setText("Import from XML");
396: gridData = new GridData(SWT.CENTER, SWT.CENTER, false, false);
397: xmlImportButton.setLayoutData(gridData);
398: xmlImportButton.addSelectionListener(new SelectionAdapter() {
399: public void widgetSelected(SelectionEvent e) {
400: SafeRunner runner = new SafeRunner() {
401: public Object runUnsafe() throws Exception {
402: importFromXML();
403: return null;
404: }
405: };
406: // Exécution du traitement
407: runner.run(parent.getShell());
408: }
409: });
410: // Désactivation du bouton
411: disableField(xmlImportButton);
412:
413: }
414:
415: /**
416: * Initialise l'IHM avec les données en base.
417: */
418: public void initUI() {
419: // Valeurs par défaut (à supprimer)
420: int databaseType = 1;
421: try {
422: databaseType = Integer.parseInt(CfgMgr
423: .get(CfgMgr.DATABASE_TYPE));
424: } catch (NumberFormatException ignored) {
425: }
426: String jdbcDriver = CfgMgr.get(CfgMgr.JDBC_DRIVER);
427: String dbHost = CfgMgr.get(CfgMgr.DATABASE_HOST);
428: String dbPort = CfgMgr.get(CfgMgr.DATABASE_PORT);
429: String dbDataFile = CfgMgr.get(CfgMgr.DATABASE_DATA_FILE);
430: String dbName = CfgMgr.get(CfgMgr.DATABASE_NAME);
431: String jdbcUrl = CfgMgr.get(CfgMgr.JDBC_URL);
432: String jdbcUser = CfgMgr.get(CfgMgr.JDBC_USER);
433: String jdbcPassword = CfgMgr.get(CfgMgr.JDBC_PASSWORD);
434: dbTypeCombo.select(databaseType);
435: dbHostText.setText(dbHost != null ? dbHost : "");
436: dbPortText.setText(dbPort != null ? dbPort : "");
437: dbDataFileText.setStringValue(dbDataFile != null ? dbDataFile
438: : "");
439: dbNameText.setText(dbName != null ? dbName : "");
440: jdbcDriverText.setText(jdbcDriver != null ? jdbcDriver : "");
441: jdbcUrlText.setText(jdbcUrl != null ? jdbcUrl : "");
442: jdbcUserIdText.setText(jdbcUser != null ? jdbcUser : "");
443: jdbcPasswordText.setText(jdbcPassword != null ? jdbcPassword
444: : "");
445: // Mise à jour des données
446: dbTypeChanged();
447: }
448:
449: /**
450: * Méthode invoquée lorsque l'utilisateur change le type de BDD dans l'IHM.
451: */
452: protected void dbTypeChanged() {
453: log.debug("dbTypeCombo.getSelectionIndex()="
454: + dbTypeCombo.getSelectionIndex());
455: // Désactivation de tout les champs
456: disableField(jdbcDriverText);
457: disableField(dbHostText);
458: disableField(dbPortText);
459: disableField(dbDataFileText, conectionPanel);
460: disableField(dbNameText);
461: disableField(jdbcUrlText);
462: disableField(jdbcUserIdText);
463: disableField(jdbcPasswordText);
464: switch (dbTypeCombo.getSelectionIndex()) {
465: // Cas d'une connexion JDBC HSQL embarqué
466: case STANDALONE_MODE:
467: enabledField(dbDataFileText, conectionPanel,
468: "data/activitymgr", false);
469: break;
470: // Cas d'une connexion MySQL
471: case MYSQL_SERVER_MODE:
472: enabledField(dbHostText, "localhost", false);
473: enabledField(dbPortText, "3306", true);
474: enabledField(dbNameText, "taskmgr_db", false);
475: enabledField(jdbcUserIdText, "taskmgr_db", false);
476: enabledField(jdbcPasswordText, "", false);
477: break;
478: // Cas d'une connexion autre
479: case USER_DEFINED_MODE:
480: enabledField(jdbcDriverText, "<jdbc driver>", false);
481: enabledField(jdbcUrlText, "<jdbc url>", false);
482: enabledField(jdbcUserIdText, "<jdbc_user_id>", false);
483: enabledField(jdbcPasswordText, "", false);
484: break;
485: // Autre cas : erreur
486: default:
487: throw new Error("Unknown database type");
488: }
489: // Activation/désactivation des labels
490: jdbcDriverLabel.setEnabled(jdbcDriverText.getEnabled());
491: dbHostLabel.setEnabled(dbHostText.getEnabled());
492: dbPortLabel.setEnabled(dbPortText.getEnabled());
493: dbNameLabel.setEnabled(dbNameText.getEnabled());
494: jdbcUrlLabel.setEnabled(jdbcUrlText.getEnabled());
495: jdbcUserIdLabel.setEnabled(jdbcUserIdText.getEnabled());
496: jdbcPasswordLabel.setEnabled(jdbcPasswordText.getEnabled());
497: jdbcPasswordWarning.setEnabled(jdbcPasswordText.getEnabled());
498: // Mise à jour des champs
499: entriesChanged();
500: }
501:
502: /* (non-Javadoc)
503: * @see org.eclipse.swt.events.ModifyListener#modifyText(org.eclipse.swt.events.ModifyEvent)
504: */
505: public void modifyText(ModifyEvent e) {
506: entriesChanged();
507: }
508:
509: /**
510: * Désactive le champ spécifié.
511: * @param field le champ à désactiver.
512: */
513: private void disableField(Text field) {
514: Text text = (Text) field;
515: text.setEnabled(false);
516: text.removeModifyListener(this );
517: }
518:
519: /**
520: * Désactive le champ spécifié.
521: * @param field le champ à désactiver.
522: */
523: private void disableField(Control field) {
524: field.setEnabled(false);
525: }
526:
527: /**
528: * Désactive l'éditeur de nom de fichier.
529: * @param field le champ à désactiver.
530: * @param parent le composant parent.
531: */
532: private void disableField(FileFieldEditor field, Composite parent) {
533: FileFieldEditor fileFieldEditor = (FileFieldEditor) field;
534: fileFieldEditor.setEnabled(false, parent);
535: fileFieldEditor.setPropertyChangeListener(null);
536: }
537:
538: /**
539: * Active l'éditeur de nom de fichier.
540: * @param field le champ à désactiver.
541: * @param defaultValue valeur par défaut.
542: * @param forceDefaultValue booléen indiquant si la valeur par défaut doit
543: * être forcée même quand le champ a déjà une valeur.
544: */
545: private void enabledField(Text field, String defaultValue,
546: boolean forceDefaultValue) {
547: // Cas d'un textfield
548: field.setEnabled(true);
549: if (forceDefaultValue || "".equals(field.getText()))
550: field.setText(defaultValue);
551: field.addModifyListener(this );
552: }
553:
554: /**
555: * Active le champ.
556: * @param field le champ à désactiver.
557: * @param parent le composant parent.
558: * @param defaultValue valeur par défaut.
559: * @param forceDefaultValue booléen indiquant si la valeur par défaut doit
560: * être forcée même quand le champ a déjà une valeur.
561: */
562: private void enabledField(FileFieldEditor field, Composite parent,
563: String defaultValue, boolean forceDefaultValue) {
564: field.setEnabled(true, parent);
565: if (forceDefaultValue || "".equals(field.getStringValue()))
566: field.setStringValue(defaultValue);
567: field.setPropertyChangeListener(new IPropertyChangeListener() {
568: public void propertyChange(PropertyChangeEvent event) {
569: entriesChanged();
570: }
571: });
572: }
573:
574: /**
575: * Réagit à un changement des données saisies par l'utilisateur.
576: */
577: private void entriesChanged() {
578: log.debug("Entries changed");
579: switch (dbTypeCombo.getSelectionIndex()) {
580: // Cas d'une connexion JDBC HSQL embarqué
581: case STANDALONE_MODE:
582: jdbcDriverText.setText("org.hsqldb.jdbcDriver");
583: dbHostText.setText("");
584: dbPortText.setText("");
585: dbNameText.setText("");
586: jdbcUrlText.setText("jdbc:hsqldb:file:"
587: + dbDataFileText.getStringValue());
588: jdbcUserIdText.setText("sa");
589: jdbcPasswordText.setText("");
590: break;
591: // Cas d'une connexion MySQL
592: case MYSQL_SERVER_MODE:
593: jdbcDriverText.setText("com.mysql.jdbc.Driver");
594: dbDataFileText.setStringValue("");
595: jdbcUrlText.setText("jdbc:mysql://" + dbHostText.getText()
596: + ":" + dbPortText.getText() + "/"
597: + dbNameText.getText());
598: break;
599: // Cas d'une connexion autre
600: case USER_DEFINED_MODE:
601: dbHostText.setText("");
602: dbPortText.setText("");
603: dbNameText.setText("");
604: dbDataFileText.setStringValue("");
605: break;
606: // Autre cas : erreur
607: default:
608: throw new Error("Unknown database type");
609: }
610: }
611:
612: /**
613: * Ajoute un listener.
614: * @param listener le nouveau listener.
615: */
616: public void addDbStatusListener(IDbStatusListener listener) {
617: listeners.add(listener);
618: }
619:
620: /**
621: * Ajoute un listener.
622: * @param listener le nouveau listener.
623: */
624: public void removeDbStatusListener(IDbStatusListener listener) {
625: listeners.remove(listener);
626: }
627:
628: /**
629: * Ouvre la connexion à la base de données.
630: * @throws IOException levé en cas d'incident I/O lors du chargement de la
631: * configuration.
632: * @throws DbException levé en cas d'incident technique d'accès à la base.
633: * @throws UITechException levé en cas d'incident inattendu lors de la création des durées.
634: */
635: private void openDatabase() throws IOException, DbException,
636: UITechException {
637: // Récupération des paramètres de connexion
638: String databaseType = String.valueOf(dbTypeCombo
639: .getSelectionIndex());
640: String jdbcDriver = jdbcDriverText.getText().trim();
641: String dbHost = dbHostText.getText().trim();
642: String dbPort = dbPortText.getText().trim();
643: String dbDataFile = dbDataFileText.getStringValue().trim();
644: String dbName = dbNameText.getText().trim();
645: String jdbcUrl = jdbcUrlText.getText().trim();
646: String jdbcUser = jdbcUserIdText.getText().trim();
647: String jdbcPassword = jdbcPasswordText.getText();
648:
649: // Sauvagarde dans le fichier de config
650: CfgMgr.set(CfgMgr.DATABASE_TYPE, databaseType);
651: CfgMgr.set(CfgMgr.JDBC_DRIVER, jdbcDriver);
652: CfgMgr.set(CfgMgr.DATABASE_HOST, dbHost);
653: CfgMgr.set(CfgMgr.DATABASE_PORT, dbPort);
654: CfgMgr.set(CfgMgr.DATABASE_DATA_FILE, dbDataFile);
655: CfgMgr.set(CfgMgr.DATABASE_NAME, dbName);
656: CfgMgr.set(CfgMgr.JDBC_URL, jdbcUrl);
657: CfgMgr.set(CfgMgr.JDBC_USER, jdbcUser);
658: CfgMgr.set(CfgMgr.JDBC_PASSWORD, jdbcPassword);
659: CfgMgr.save();
660:
661: // Changement des paramètres de connexion
662: ModelMgr.initDatabaseAccess(jdbcDriver, jdbcUrl, jdbcUser,
663: jdbcPassword);
664:
665: // Test de l'existence du modèle en base
666: boolean dbModelOk = ModelMgr.tablesExist();
667: // Si le modèle n'est pas installé et que l'utilisateur
668: // le désire, l'application crée automatiquement les tables
669: if (!dbModelOk) {
670: if (MessageDialog
671: .openConfirm(
672: parent.getShell(),
673: "Confirmation",
674: "The database doesn't seem to be installed.\nWould you like to install it now ?")) {
675: // Création des tables
676: reinstallDatabase();
677: dbModelOk = true;
678: } else {
679: MessageDialog.openError(parent.getShell(), "Error",
680: "Database not installed.\nConnection failed.");
681: }
682: }
683:
684: // Si le modèle de données est bien installé
685: if (dbModelOk) {
686: // Activation/désactivation des boutons et des champs
687: disableField(dbTypeCombo);
688: disableField(dbTypeLabel);
689: disableField(jdbcDriverLabel);
690: disableField(jdbcDriverText);
691: disableField(dbHostLabel);
692: disableField(dbHostText);
693: disableField(dbPortLabel);
694: disableField(dbPortText);
695: disableField(dbDataFileText, conectionPanel);
696: disableField(dbNameLabel);
697: disableField(dbNameText);
698: disableField(jdbcUrlLabel);
699: disableField(jdbcUrlText);
700: disableField(jdbcUserIdLabel);
701: disableField(jdbcUserIdText);
702: disableField(jdbcPasswordLabel);
703: disableField(jdbcPasswordText);
704: disableField(jdbcPasswordWarning);
705: openDbButton.setEnabled(false);
706: closeDbButton.setEnabled(true);
707: resetDbDataButton.setEnabled(true);
708: enabledField(xmlFileText, xmlPanel, "", false);
709: xmlExportButton.setEnabled(true);
710: xmlImportButton.setEnabled(true);
711:
712: // Notification de changement de statut de la connexion
713: Iterator it = listeners.iterator();
714: while (it.hasNext()) {
715: IDbStatusListener listener = (IDbStatusListener) it
716: .next();
717: listener.databaseOpened();
718: }
719: }
720:
721: }
722:
723: /**
724: * Ferme la connexion à la base de données.
725: * @throws DbException levé en cas d'incident technique d'accès à la base.
726: */
727: private void closeDatabase() throws DbException {
728: // Changement des paramètres de connexion
729: ModelMgr.closeDatabaseAccess();
730: // Activation/désactivation des boutons et des champs
731: openDbButton.setEnabled(true);
732: closeDbButton.setEnabled(false);
733: resetDbDataButton.setEnabled(false);
734: dbTypeCombo.setEnabled(true);
735: dbTypeLabel.setEnabled(true);
736: disableField(xmlFileText, xmlPanel);
737: xmlExportButton.setEnabled(false);
738: xmlImportButton.setEnabled(false);
739: dbTypeChanged();
740:
741: // Notification de changement de statut de la connexion
742: Iterator it = listeners.iterator();
743: while (it.hasNext()) {
744: IDbStatusListener listener = (IDbStatusListener) it.next();
745: listener.databaseClosed();
746: }
747: }
748:
749: /**
750: * Réinstalle la base de données (tables drop + creation).
751: * @throws DbException levé en cas d'incident technique d'accès à la base.
752: * @throws UITechException levé en cas d'incident inattendu lors de la création des durées.
753: */
754: private void reinstallDatabase() throws DbException,
755: UITechException {
756: // Suppression et recréation des tables
757: ModelMgr.createTables();
758: // Question concernant le référentiel de durées par défaut
759: if (MessageDialog
760: .openQuestion(
761: parent.getShell(),
762: "Confirmation",
763: "Database tables initialization done.\n"
764: + "Do you want me to create default durations (0.25, 0.50, 0.75 & 1.00) ?\n"
765: + "Warning : \n"
766: + " - if you are about to import an XML file, choose no to avoid data conflicts.\n"
767: + " - if you choose no, you may have to create it manually.")) {
768: try {
769: Duration duration = new Duration();
770: duration.setId(25);
771: ModelMgr.createDuration(duration);
772: duration.setId(50);
773: ModelMgr.createDuration(duration);
774: duration.setId(75);
775: ModelMgr.createDuration(duration);
776: duration.setId(100);
777: ModelMgr.createDuration(duration);
778: } catch (ModelException e) {
779: log
780: .error(
781: "Unexpected error while creating default durations",
782: e);
783: throw new UITechException(
784: "Unexpected error while creating default durations",
785: e);
786: }
787: }
788: // Notification des listeners (reset équivalent à réouverture de la BDD)
789: Iterator it = listeners.iterator();
790: while (it.hasNext()) {
791: IDbStatusListener listener = (IDbStatusListener) it.next();
792: listener.databaseOpened();
793: }
794: }
795:
796: /**
797: * Réinstalle la base de données (tables drop + creation).
798: * @throws DbException levé en cas d'incident technique d'accès à la base.
799: * @throws UITechException levé en cas d'incident inattendu lors de la création des durées.
800: */
801: private void reinstallDatabaseWithWarnings() throws DbException,
802: UITechException {
803: if (MessageDialog.openQuestion(parent.getShell(),
804: "Confirmation",
805: "Are you sure you want to reset the database data ?")) {
806: if (MessageDialog
807: .openQuestion(parent.getShell(), "Confirmation",
808: "Really sure ???? (You may DEFINITELY loose your data)")) {
809: reinstallDatabase();
810: }
811: }
812: }
813:
814: /**
815: * Exporte le contenu de la BDD vers un fichier XML.
816: * @throws DbException levé en cas d'incident technique d'accès à la base.
817: * @throws IOException levé en cas d'incident I/O lors de l'écriture dans le fichier XML.
818: */
819: private void exportToXML() throws DbException, IOException {
820: String fileName = xmlFileText.getStringValue();
821: if ("".equals(fileName.trim())) {
822: MessageDialog.openWarning(parent.getShell(),
823: "File name error", "XML file name not specified!");
824: } else {
825: File xmlFile = new File(fileName);
826: if (!xmlFile.exists()
827: || MessageDialog.openConfirm(parent.getShell(),
828: "Confirmation", "File exists. Overwrite ?")) {
829: FileOutputStream out = new FileOutputStream(xmlFile);
830: ModelMgr.exportToXML(out);
831: out.close();
832: // Popup d'info de fin de traitement
833: MessageDialog.openInformation(parent.getShell(),
834: "Information",
835: "Database successfully exported.");
836: }
837: }
838: }
839:
840: /**
841: * Importe les données contenues dans un fichier XML.
842: * @throws IOException levé en cas d'incident I/O lors de la lecture du fichier XML.
843: * @throws ParserConfigurationException levé en cas de mauvaise configuration du parser XML.
844: * @throws SAXException levé en cas de mauvais format du fichier XML.
845: * @throws ModelException levé en cas de violation du modèle de données.
846: * @throws UITechException levé en cas d'incident inattendu.
847: * @throws DbException levé en cas d'incident technique d'accès à la base.
848: */
849: private void importFromXML() throws IOException,
850: ParserConfigurationException, SAXException, ModelException,
851: UITechException, DbException {
852: String fileName = xmlFileText.getStringValue();
853: File xmlFile = new File(fileName);
854: if ("".equals(fileName.trim())) {
855: MessageDialog.openWarning(parent.getShell(),
856: "File name error", "XML file name not specified!");
857: } else if (!xmlFile.exists()) {
858: MessageDialog
859: .openWarning(parent.getShell(), "File error",
860: "File doesn't exist. Please specify a valid file name.");
861: } else {
862: if (MessageDialog
863: .openConfirm(parent.getShell(), "Confirmation",
864: "Are you sure you want to perform this importation ?")) {
865: // Peut-être l'utilisateur veut faire un reset sur la base
866: // avant import
867: if (MessageDialog
868: .openQuestion(parent.getShell(),
869: "Confirmation",
870: "Do you want to reset the database tables before importing ?")) {
871: // Même traitement que pour le bouton 'Reset database data'
872: reinstallDatabaseWithWarnings();
873: }
874: // Importation des données
875: FileInputStream in = new FileInputStream(xmlFile);
876: ModelMgr.importFromXML(in);
877: in.close();
878: // Notification de fikn de chargement (équivalent ouverture BDD)
879: Iterator it = listeners.iterator();
880: while (it.hasNext()) {
881: IDbStatusListener listener = (IDbStatusListener) it
882: .next();
883: listener.databaseOpened();
884: }
885: // Popup d'info de fin de traitement
886: MessageDialog.openInformation(parent.getShell(),
887: "Information",
888: "XML file successfully imported.");
889: }
890: }
891: }
892:
893: }
|