QedeqMainFrame.java
001 /* This file is part of the project "Hilbert II" - http://www.qedeq.org
002  *
003  * Copyright 2000-2013,  Michael Meyling <mime@qedeq.org>.
004  *
005  * "Hilbert II" is free software; you can redistribute
006  * it and/or modify it under the terms of the GNU General Public
007  * License as published by the Free Software Foundation; either
008  * version 2 of the License, or (at your option) any later version.
009  *
010  * This program is distributed in the hope that it will be useful,
011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013  * GNU General Public License for more details.
014  */
015 
016 package org.qedeq.gui.se.main;
017 
018 import java.awt.BorderLayout;
019 import java.awt.Dimension;
020 import java.awt.event.WindowAdapter;
021 import java.awt.event.WindowEvent;
022 import java.io.File;
023 import java.io.FileOutputStream;
024 import java.io.IOException;
025 import java.io.PrintStream;
026 import java.net.URL;
027 
028 import javax.swing.JFrame;
029 import javax.swing.JMenuBar;
030 import javax.swing.JOptionPane;
031 import javax.swing.JPanel;
032 import javax.swing.SwingUtilities;
033 
034 import org.apache.log4j.PropertyConfigurator;
035 import org.apache.log4j.xml.DOMConfigurator;
036 import org.qedeq.base.io.IoUtility;
037 import org.qedeq.base.io.UrlUtility;
038 import org.qedeq.base.trace.Trace;
039 import org.qedeq.base.utility.StringUtility;
040 import org.qedeq.gui.se.control.QedeqController;
041 import org.qedeq.gui.se.pane.QedeqGuiConfig;
042 import org.qedeq.gui.se.util.GuiHelper;
043 import org.qedeq.kernel.bo.KernelContext;
044 import org.qedeq.kernel.bo.log.LogListenerImpl;
045 import org.qedeq.kernel.bo.log.ModuleEventListenerLog;
046 import org.qedeq.kernel.bo.log.ModuleEventLog;
047 import org.qedeq.kernel.bo.log.QedeqLog;
048 import org.qedeq.kernel.bo.log.TraceListener;
049 import org.qedeq.kernel.bo.service.DefaultInternalKernelServices;
050 import org.qedeq.kernel.xml.dao.XmlQedeqFileDao;
051 
052 import com.jgoodies.looks.LookUtils;
053 import com.jgoodies.looks.Options;
054 
055 /**
056  * This is the main frame of the GUI frontend for a standalone program
057  * version of <b>Hilbert II</b>.
058  *
059  @author  Michael Meyling
060  */
061 public class QedeqMainFrame extends JFrame {
062 
063     /** Initial frame resolution. */
064     protected static final Dimension PREFERRED_SIZE = (LookUtils.IS_LOW_RESOLUTION
065         new Dimension(650510new Dimension(740660));
066 
067     /**
068      * Constructor, configures the UI, and builds the content. Also some indirectly some GUI
069      * loggers are added.
070      *
071      @param   settings    GUI options.
072      @throws  IOException Initialization failed for IO reasons.
073      */
074     public QedeqMainFrame(final GuiOptions settingsthrows IOException {
075         GuiHelper.configureUI(settings);
076 
077         checkDirectoryExistenceAndOptionallyCreate(QedeqGuiConfig.getInstance());
078 
079         // add various loggers
080 //        QedeqLog.getInstance().addLog(new LogListenerImpl());   // System.out
081         QedeqLog.getInstance().addLog(new TraceListener());     // trace file
082         QedeqLog.getInstance()                                  // log file
083             .addLog(new LogListenerImpl(new PrintStream(
084             new FileOutputStream(QedeqGuiConfig.getInstance().getLogFile()true)true)));
085         ModuleEventLog.getInstance().addLog(new ModuleEventListenerLog());  // all loggers
086 
087         // initialize the kernel, this may create already some logging events
088         KernelContext.getInstance().init(
089             QedeqGuiConfig.getInstance(),
090             new DefaultInternalKernelServices(QedeqGuiConfig.getInstance(),
091                     KernelContext.getInstance()new XmlQedeqFileDao()));
092 
093         // create new controller for all possible actions
094         final QedeqController controller = new QedeqController(this);
095 
096         // assemble main GUI window
097         final JPanel panel = new JPanel(new BorderLayout());
098         panel.add(new QedeqMainPane(controller), BorderLayout.CENTER);
099         setContentPane(panel);
100         setTitle(" " + KernelContext.getInstance().getDescriptiveKernelVersion());
101         final JMenuBar menuBar =  new QedeqMenuBar(controller, settings);
102         setJMenuBar(menuBar);
103         setIconImage(GuiHelper.readImageIcon("qedeq/16x16/qedeq.png").getImage());
104         addWindowListener(new WindowAdapter() {
105             public void windowClosing(final WindowEvent e) {
106                 controller.getExitAction().actionPerformed(null);
107             }
108         });
109 
110     }
111 
112     private void checkDirectoryExistenceAndOptionallyCreate(final QedeqGuiConfig config)
113             throws IOException {
114         // application log file directory
115         {
116             final File file = config.getLogFile();
117             final File dir = file.getParentFile();
118             if (!dir.exists() &&  !dir.mkdirs()) {
119                 throw new IOException("can't create directory: " + dir.getAbsolutePath());
120             }
121         }
122     }
123 
124     /**
125      * Make local copy of Log4J properties if we don't find the Log4J property file in application
126      * config directory. This is necessary especially if the application was launched by
127      * Webstart.
128      <p>
129      * If the copy action fails, error messages are written to <code>System.err</code> but the
130      * application continues.
131      *
132      @param   config  Configuration file.
133      */
134     private static void initLog4J(final QedeqGuiConfig config) {
135         final String resourceName = "log4j.xml";
136         // LATER mime 20070927: hard coded entry "config":
137         String resourceDirectoryName = "config";
138         final File resourceDir = new File(config.getBasisDirectory(), resourceDirectoryName);
139         final File resource = new File(resourceDir, resourceName);
140         String res = "/" + resourceDirectoryName + "/" + resourceName;
141         if (!resource.exists()) {
142             final URL url = QedeqMainFrame.class.getResource(res);
143             if (url == null) {
144                 errorPrintln("Resource not found: " + res);
145             else {
146                 try {
147                     if (!resourceDir.exists()) {
148                         if (!resourceDir.mkdirs()) {
149                             errorPrintln("Creation of directory failed: "
150                                 + resourceDir.getAbsolutePath());
151                         }
152                     }
153                     final StringBuffer buffer = new StringBuffer();
154                     IoUtility.loadFile(url, buffer, "ISO-8859-1");
155                     File traceFile = config.createAbsolutePath("log/trace.txt");
156                     StringUtility.replace(buffer, "@trace_file_path@", traceFile.toString()
157                         .replace('\\''/'));
158 // for a properties file:
159 //                        IoUtility.escapeProperty(traceFile.toString().replace('\\', '/')));
160                     IoUtility.saveFile(resource, buffer, "ISO-8859-1");
161                     res = UrlUtility.toUrl(resource).toString();
162                 catch (IOException e1) {
163                     errorPrintln("Resource can not be saved: " + resource.getAbsolutePath());
164                     e1.printStackTrace();
165                 }
166             }
167         else {
168             res = UrlUtility.toUrl(resource).toString();
169         }
170         System.setProperty("log4j.configDebug""true");
171         System.setProperty("log4j.configuration", res);
172 
173         // init Log4J watchdog
174         try {
175             // set properties and watch file every 5 seconds
176             if (res.endsWith(".xml")) {
177                 DOMConfigurator.configureAndWatch(resource.getCanonicalPath()5000);
178             else {
179                 PropertyConfigurator.configureAndWatch(resource.getCanonicalPath()5000);
180             }
181         catch (Exception e) {
182             e.printStackTrace();
183         }
184     }
185 
186     /**
187      * Print error message. Writes to <code>System.err</code>.
188      *
189      @param   message Message to print.
190      */
191     private static void errorPrintln(final String message) {
192         System.err.println("ERROR>>> " + message);
193     }
194 
195     public static void main(final String[] args) {
196         // load configuration file
197         try {
198             QedeqGuiConfig.init(new File(IoUtility.getStartDirectory("qedeq"),
199                 "config/org.qedeq.properties"), IoUtility.getStartDirectory("qedeq"));
200         catch (Throwable e) {
201             e.printStackTrace();
202             JOptionPane.showInternalMessageDialog(null, "Configuration file not found!\n\n"
203                 + e, "Hilbert II - Error", JOptionPane.ERROR_MESSAGE);
204             System.exit(-1);
205             return;
206         }
207 
208         try {
209             // we make a local file copy of the log4j.properties if it dosen't exist already
210             initLog4J(QedeqGuiConfig.getInstance());
211         catch (Throwable e) {
212             e.printStackTrace();
213             JOptionPane.showMessageDialog(null, "Initialization of Log4J failed!\n\n"
214                 + e, "Hilbert II - Error", JOptionPane.ERROR_MESSAGE);
215             System.exit(-2);
216             return;
217         }
218 
219         try {
220             final GuiOptions options = new GuiOptions();
221             {
222                 String lafShortName = QedeqGuiConfig.getInstance().getLookAndFeel();
223                 String lafClassName;
224                 if ("Windows".equalsIgnoreCase(lafShortName)) {
225                     lafClassName = Options.JGOODIES_WINDOWS_NAME;
226                 else if ("Plastic".equalsIgnoreCase(lafShortName)) {
227                     lafClassName = Options.PLASTIC_NAME;
228                 else if ("Plastic3D".equalsIgnoreCase(lafShortName)) {
229                     lafClassName = Options.PLASTIC3D_NAME;
230                 else if ("PlasticXP".equalsIgnoreCase(lafShortName)) {
231                     lafClassName = Options.PLASTICXP_NAME;
232                 else if ("Metal".equalsIgnoreCase(lafShortName)) {
233                     lafClassName = "javax.swing.plaf.metal.MetalLookAndFeel";
234                 else {
235                     lafClassName = lafShortName;
236                 }
237                 options.setSelectedLookAndFeel(lafClassName);
238             }
239             final QedeqMainFrame instance;
240             try {
241                 instance = new QedeqMainFrame(options);
242             catch (IOException e) {
243                 e.printStackTrace(System.out);
244                 JOptionPane.showMessageDialog(null, "Application start failed!\n\n"
245                     + e, "Hilbert II - Error", JOptionPane.ERROR_MESSAGE);
246                 KernelContext.getInstance().shutdown();
247                 System.exit(-3);
248                 return;
249             }
250             instance.setSize(PREFERRED_SIZE);
251             Dimension paneSize = instance.getSize();
252             Dimension screenSize = instance.getToolkit().getScreenSize();
253             instance.setLocation(
254                 (screenSize.width  - paneSize.width)  2,
255                 (screenSize.height - paneSize.height2);
256             instance.setVisible(true);
257 
258             // wait till GUI is ready
259             SwingUtilities.invokeLater(new Runnable() {
260                 public void run() {
261                     // now we are ready to fire up the kernel
262                     KernelContext.getInstance().startup();
263                 }
264             });
265         catch (Throwable e) {
266             e.printStackTrace(System.out);
267             Trace.fatal(QedeqMainFrame.class, "main(String[])""Unexpected major failure!", e);
268             JOptionPane.showMessageDialog(null, "Unexpected major failure!\n\n"
269                 + e, "Hilbert II - Error", JOptionPane.ERROR_MESSAGE);
270             System.exit(-4);
271             return;
272         }
273     }
274 
275 }