QedeqMainFrame.java
001 /* This file is part of the project "Hilbert II" - http://www.qedeq.org
002  *
003  * Copyright 2000-2014,  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.internal.DefaultInternalKernelServices;
050 import org.qedeq.kernel.xml.dao.XmlQedeqFileDao;
051 
052 import com.jgoodies.looks.Options;
053 
054 /**
055  * This is the main frame of the GUI frontend for a standalone program
056  * version of <b>Hilbert II</b>.
057  *
058  @author  Michael Meyling
059  */
060 public class QedeqMainFrame extends JFrame {
061 
062     /** Directory for start within IDE. */
063     private static final String QEDEQ_IDE = "qedeq_ide_run";
064 
065     /** Directory for start within IDE. */
066     private static final String QEDEQ_IDE_START = "../../" + QEDEQ_IDE;
067 
068     /** Initial frame resolution. */
069 //    protected static final Dimension PREFERRED_SIZE = (LookUtils.IS_LOW_RESOLUTION
070 //        ? new Dimension(650, 510) : new Dimension(740, 660));
071     protected static final Dimension PREFERRED_SIZE = (GuiHelper.IS_LOW_RESOLUTION
072         new Dimension(650510new Dimension(900660));
073 
074     /**
075      * Constructor, configures the UI, and builds the content. Also some indirectly some GUI
076      * loggers are added.
077      *
078      @param   settings    GUI options.
079      @throws  IOException Initialization failed for IO reasons.
080      */
081     public QedeqMainFrame(final GuiOptions settingsthrows IOException {
082         GuiHelper.configureUI(settings);
083 
084         checkDirectoryExistenceAndOptionallyCreate(QedeqGuiConfig.getInstance());
085 
086         // add various loggers
087 //        QedeqLog.getInstance().addLog(new LogListenerImpl());   // System.out
088         QedeqLog.getInstance().addLog(new TraceListener());     // trace file
089         QedeqLog.getInstance()                                  // log file
090             .addLog(new LogListenerImpl(new PrintStream(
091             new FileOutputStream(QedeqGuiConfig.getInstance().getLogFile()true), true, "UTF8")));
092         ModuleEventLog.getInstance().addLog(new ModuleEventListenerLog());  // all loggers
093 
094         // initialize the kernel, this may create already some logging events
095         KernelContext.getInstance().init(
096             QedeqGuiConfig.getInstance(),
097             new DefaultInternalKernelServices(QedeqGuiConfig.getInstance(),
098                     KernelContext.getInstance()new XmlQedeqFileDao()));
099 
100         // create new controller for all possible actions
101         final QedeqController controller = new QedeqController(this);
102 
103         // assemble main GUI window
104         final JPanel panel = new JPanel(new BorderLayout());
105         panel.add(new QedeqMainPane(controller), BorderLayout.CENTER);
106         setContentPane(panel);
107         setTitle(" " + KernelContext.getInstance().getDescriptiveKernelVersion());
108         final JMenuBar menuBar =  new QedeqMenuBar(controller, settings);
109         setJMenuBar(menuBar);
110         setIconImage(GuiHelper.readImageIcon("qedeq/16x16/qedeq.png").getImage());
111         setIconImage(GuiHelper.readImageIcon("qedeq/48x48/qedeq.png").getImage());
112         addWindowListener(new WindowAdapter() {
113             public void windowClosing(final WindowEvent e) {
114                 controller.getExitAction().actionPerformed(null);
115             }
116         });
117 
118     }
119 
120     private void checkDirectoryExistenceAndOptionallyCreate(final QedeqGuiConfig config)
121             throws IOException {
122         // application log file directory
123         {
124             final File file = config.getLogFile();
125             final File dir = file.getParentFile();
126             if (!dir.exists() &&  !dir.mkdirs()) {
127                 throw new IOException("can't create directory: " + dir.getAbsolutePath());
128             }
129         }
130     }
131 
132     /**
133      * Make local copy of Log4J properties if we don't find the Log4J property file in application
134      * config directory. This is necessary especially if the application was launched by
135      * Webstart.
136      <p>
137      * If the copy action fails, error messages are written to <code>System.err</code> but the
138      * application continues.
139      *
140      @param   config  Configuration file.
141      */
142     private static void initLog4J(final QedeqGuiConfig config) {
143         final String resourceName = "log4j.xml";
144         // LATER mime 20070927: hard coded entry "config":
145         String resourceDirectoryName = "config";
146         final File resourceDir = new File(config.getBasisDirectory(), resourceDirectoryName);
147         final File log4jConfig = new File(resourceDir, resourceName);
148         String res = "/" + resourceDirectoryName + "/" + resourceName;
149         // if the config file doesn't exist in the file system, we take it from the class path
150         // and save it in the file system!
151         if (!log4jConfig.exists()) {
152             final URL log4jConfigUrl = QedeqMainFrame.class.getResource(res);
153             if (log4jConfigUrl == null) {
154                 errorPrintln("Resource not found: " + res);
155             else {
156                 try {
157                     if (!resourceDir.exists()) {
158                         if (!resourceDir.mkdirs()) {
159                             errorPrintln("Creation of directory failed: "
160                                 + resourceDir.getAbsolutePath());
161                         }
162                     }
163                     final StringBuffer buffer = new StringBuffer();
164                     // if this would be a properties file would have to load it with ISO-8859-1
165                     IoUtility.loadFile(log4jConfigUrl, buffer, "UTF-8");
166                     // if we start this within our IDE we don't want to fiddle with our SCM system
167                     System.out.println("basis dir: " + config.getBasisDirectory());
168                     if (config.getBasisDirectory().toString().endsWith(QEDEQ_IDE)) {
169                         StringUtility.replace(buffer, "log/trace.log", QEDEQ_IDE_START + "/log/trace.log");
170                     }
171                     IoUtility.saveFile(log4jConfig, buffer, "UTF-8");
172                 catch (IOException e1) {
173                     errorPrintln("Resource can not be saved: " + log4jConfig.getAbsolutePath());
174                     e1.printStackTrace();
175                 }
176             }
177         else {
178             res = UrlUtility.toUrl(log4jConfig).toString();
179         }
180         System.setProperty("log4j.configDebug""true");
181         System.setProperty("log4j.configuration", res);
182 
183         // init Log4J watchdog
184         try {
185             // set properties and watch file every 5 seconds
186             if (res.endsWith(".xml")) {
187                 DOMConfigurator.configureAndWatch(log4jConfig.getCanonicalPath()5000);
188             else {
189                 PropertyConfigurator.configureAndWatch(log4jConfig.getCanonicalPath()5000);
190             }
191         catch (Exception e) {
192             e.printStackTrace();
193         }
194     }
195 
196     /**
197      * Print error message. Writes to <code>System.err</code>.
198      *
199      @param   message Message to print.
200      */
201     private static void errorPrintln(final String message) {
202         System.err.println("ERROR>>> " + message);
203     }
204 
205     public static void main(final String[] args) {
206         // load configuration file
207         try {
208             File startDirectory = IoUtility.getStartDirectory("qedeq");
209             // if we start this within our IDE we don't want to fiddle with our SCM system
210             if (startDirectory.toString().equals("."&& startDirectory.getCanonicalFile().getName()
211                     .equals("QedeqGuiSe")) {
212                 startDirectory = new File(QEDEQ_IDE_START);
213             }
214             QedeqGuiConfig.init(new File(startDirectory,
215                 "config/org.qedeq.properties"), startDirectory);
216         catch (Throwable e) {
217             e.printStackTrace();
218             JOptionPane.showInternalMessageDialog(null, "Configuration file not found!\n\n"
219                 + e, "Hilbert II - Error", JOptionPane.ERROR_MESSAGE);
220             System.exit(-1);
221             return;
222         }
223 
224         try {
225             // we make a local file copy of the log4j.properties if it dosen't exist already
226             initLog4J(QedeqGuiConfig.getInstance());
227         catch (Throwable e) {
228             e.printStackTrace();
229             JOptionPane.showMessageDialog(null, "Initialization of Log4J failed!\n\n"
230                 + e, "Hilbert II - Error", JOptionPane.ERROR_MESSAGE);
231             System.exit(-2);
232             return;
233         }
234 
235         try {
236             final GuiOptions options = new GuiOptions();
237             {
238                 String lafShortName = QedeqGuiConfig.getInstance().getLookAndFeel();
239                 String lafClassName;
240                 if ("Windows".equalsIgnoreCase(lafShortName)) {
241                     lafClassName = Options.JGOODIES_WINDOWS_NAME;
242                 else if ("Plastic".equalsIgnoreCase(lafShortName)) {
243                     lafClassName = Options.PLASTIC_NAME;
244                 else if ("Plastic3D".equalsIgnoreCase(lafShortName)) {
245                     lafClassName = Options.PLASTIC3D_NAME;
246                 else if ("PlasticXP".equalsIgnoreCase(lafShortName)) {
247                     lafClassName = Options.PLASTICXP_NAME;
248                 else if ("Metal".equalsIgnoreCase(lafShortName)) {
249                     lafClassName = "javax.swing.plaf.metal.MetalLookAndFeel";
250                 else {
251                     lafClassName = lafShortName;
252                 }
253                 options.setSelectedLookAndFeel(lafClassName);
254             }
255             final QedeqMainFrame instance;
256             try {
257                 instance = new QedeqMainFrame(options);
258             catch (IOException e) {
259                 e.printStackTrace(System.out);
260                 JOptionPane.showMessageDialog(null, "Application start failed!\n\n"
261                     + e, "Hilbert II - Error", JOptionPane.ERROR_MESSAGE);
262                 KernelContext.getInstance().shutdown();
263                 System.exit(-3);
264                 return;
265             }
266             instance.setSize(PREFERRED_SIZE);
267             Dimension paneSize = instance.getSize();
268             Dimension screenSize = instance.getToolkit().getScreenSize();
269             instance.setLocation(
270                 (screenSize.width  - paneSize.width)  2,
271                 (screenSize.height - paneSize.height2);
272             instance.setVisible(true);
273 
274             // wait till GUI is ready
275             SwingUtilities.invokeLater(new Runnable() {
276                 public void run() {
277                     // now we are ready to fire up the kernel
278                     KernelContext.getInstance().startup();
279                 }
280             });
281         catch (Throwable e) {
282             e.printStackTrace(System.out);
283             Trace.fatal(QedeqMainFrame.class, "main(String[])""Unexpected major failure!", e);
284             JOptionPane.showMessageDialog(null, "Unexpected major failure!\n\n"
285                 + e, "Hilbert II - Error", JOptionPane.ERROR_MESSAGE);
286             System.exit(-4);
287             return;
288         }
289     }
290 
291 }