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.gui.se.control.QedeqController;
040 import org.qedeq.gui.se.pane.QedeqGuiConfig;
041 import org.qedeq.gui.se.util.GuiHelper;
042 import org.qedeq.kernel.bo.KernelContext;
043 import org.qedeq.kernel.bo.log.LogListenerImpl;
044 import org.qedeq.kernel.bo.log.ModuleEventListenerLog;
045 import org.qedeq.kernel.bo.log.ModuleEventLog;
046 import org.qedeq.kernel.bo.log.QedeqLog;
047 import org.qedeq.kernel.bo.log.TraceListener;
048 import org.qedeq.kernel.bo.service.DefaultInternalKernelServices;
049 import org.qedeq.kernel.xml.dao.XmlQedeqFileDao;
050 
051 import com.jgoodies.looks.Options;
052 
053 /**
054  * This is the main frame of the GUI frontend for a standalone program
055  * version of <b>Hilbert II</b>.
056  *
057  @author  Michael Meyling
058  */
059 public class QedeqMainFrame extends JFrame {
060 
061     /** Initial frame resolution. */
062 //    protected static final Dimension PREFERRED_SIZE = (LookUtils.IS_LOW_RESOLUTION
063 //        ? new Dimension(650, 510) : new Dimension(740, 660));
064     protected static final Dimension PREFERRED_SIZE = (GuiHelper.IS_LOW_RESOLUTION
065         new Dimension(650510new Dimension(900660));
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 log4jConfig = new File(resourceDir, resourceName);
140         String res = "/" + resourceDirectoryName + "/" + resourceName;
141         // if the config file doesn't exist in the file system, we take it from the class path
142         // and save it in the file system!
143         if (!log4jConfig.exists()) {
144             final URL log4jConfigUrl = QedeqMainFrame.class.getResource(res);
145             if (log4jConfigUrl == null) {
146                 errorPrintln("Resource not found: " + res);
147             else {
148                 try {
149                     if (!resourceDir.exists()) {
150                         if (!resourceDir.mkdirs()) {
151                             errorPrintln("Creation of directory failed: "
152                                 + resourceDir.getAbsolutePath());
153                         }
154                     }
155                     final StringBuffer buffer = new StringBuffer();
156                     // if this would be a properties file would have to load it with ISO-8859-1
157                     IoUtility.loadFile(log4jConfigUrl, buffer, "UTF-8");
158                     IoUtility.saveFile(log4jConfig, buffer, "UTF-8");
159                 catch (IOException e1) {
160                     errorPrintln("Resource can not be saved: " + log4jConfig.getAbsolutePath());
161                     e1.printStackTrace();
162                 }
163             }
164         else {
165             res = UrlUtility.toUrl(log4jConfig).toString();
166         }
167         System.setProperty("log4j.configDebug""true");
168         System.setProperty("log4j.configuration", res);
169 
170         // init Log4J watchdog
171         try {
172             // set properties and watch file every 5 seconds
173             if (res.endsWith(".xml")) {
174                 DOMConfigurator.configureAndWatch(log4jConfig.getCanonicalPath()5000);
175             else {
176                 PropertyConfigurator.configureAndWatch(log4jConfig.getCanonicalPath()5000);
177             }
178         catch (Exception e) {
179             e.printStackTrace();
180         }
181     }
182 
183     /**
184      * Print error message. Writes to <code>System.err</code>.
185      *
186      @param   message Message to print.
187      */
188     private static void errorPrintln(final String message) {
189         System.err.println("ERROR>>> " + message);
190     }
191 
192     public static void main(final String[] args) {
193         // load configuration file
194         try {
195             QedeqGuiConfig.init(new File(IoUtility.getStartDirectory("qedeq"),
196                 "config/org.qedeq.properties"), IoUtility.getStartDirectory("qedeq"));
197         catch (Throwable e) {
198             e.printStackTrace();
199             JOptionPane.showInternalMessageDialog(null, "Configuration file not found!\n\n"
200                 + e, "Hilbert II - Error", JOptionPane.ERROR_MESSAGE);
201             System.exit(-1);
202             return;
203         }
204 
205         try {
206             // we make a local file copy of the log4j.properties if it dosen't exist already
207             initLog4J(QedeqGuiConfig.getInstance());
208         catch (Throwable e) {
209             e.printStackTrace();
210             JOptionPane.showMessageDialog(null, "Initialization of Log4J failed!\n\n"
211                 + e, "Hilbert II - Error", JOptionPane.ERROR_MESSAGE);
212             System.exit(-2);
213             return;
214         }
215 
216         try {
217             final GuiOptions options = new GuiOptions();
218             {
219                 String lafShortName = QedeqGuiConfig.getInstance().getLookAndFeel();
220                 String lafClassName;
221                 if ("Windows".equalsIgnoreCase(lafShortName)) {
222                     lafClassName = Options.JGOODIES_WINDOWS_NAME;
223                 else if ("Plastic".equalsIgnoreCase(lafShortName)) {
224                     lafClassName = Options.PLASTIC_NAME;
225                 else if ("Plastic3D".equalsIgnoreCase(lafShortName)) {
226                     lafClassName = Options.PLASTIC3D_NAME;
227                 else if ("PlasticXP".equalsIgnoreCase(lafShortName)) {
228                     lafClassName = Options.PLASTICXP_NAME;
229                 else if ("Metal".equalsIgnoreCase(lafShortName)) {
230                     lafClassName = "javax.swing.plaf.metal.MetalLookAndFeel";
231                 else {
232                     lafClassName = lafShortName;
233                 }
234                 options.setSelectedLookAndFeel(lafClassName);
235             }
236             final QedeqMainFrame instance;
237             try {
238                 instance = new QedeqMainFrame(options);
239             catch (IOException e) {
240                 e.printStackTrace(System.out);
241                 JOptionPane.showMessageDialog(null, "Application start failed!\n\n"
242                     + e, "Hilbert II - Error", JOptionPane.ERROR_MESSAGE);
243                 KernelContext.getInstance().shutdown();
244                 System.exit(-3);
245                 return;
246             }
247             instance.setSize(PREFERRED_SIZE);
248             Dimension paneSize = instance.getSize();
249             Dimension screenSize = instance.getToolkit().getScreenSize();
250             instance.setLocation(
251                 (screenSize.width  - paneSize.width)  2,
252                 (screenSize.height - paneSize.height2);
253             instance.setVisible(true);
254 
255             // wait till GUI is ready
256             SwingUtilities.invokeLater(new Runnable() {
257                 public void run() {
258                     // now we are ready to fire up the kernel
259                     KernelContext.getInstance().startup();
260                 }
261             });
262         catch (Throwable e) {
263             e.printStackTrace(System.out);
264             Trace.fatal(QedeqMainFrame.class, "main(String[])""Unexpected major failure!", e);
265             JOptionPane.showMessageDialog(null, "Unexpected major failure!\n\n"
266                 + e, "Hilbert II - Error", JOptionPane.ERROR_MESSAGE);
267             System.exit(-4);
268             return;
269         }
270     }
271 
272 }