Java tutorial
/* Storybook: Open Source software for novelists and authors. Copyright (C) 2008 - 2012 Martin Mustun This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package storybook; import java.awt.Component; import java.awt.Font; import java.awt.HeadlessException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.channels.FileLock; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Locale; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.plaf.FontUIResource; import org.apache.commons.io.FileUtils; import storybook.SbConstants.BookKey; import storybook.SbConstants.PreferenceKey; import storybook.action.OpenFileAction; import storybook.controller.PreferenceController; import storybook.model.DbFile; import storybook.model.PreferenceModel; import storybook.model.hbn.entity.Preference; import storybook.model.oldModel.ModelMigration; import storybook.toolkit.BookUtil; import storybook.toolkit.I18N; import storybook.toolkit.PrefUtil; import storybook.toolkit.net.Updater; import storybook.toolkit.swing.SwingUtil; import storybook.ui.MainFrame; import storybook.ui.dialog.ExceptionDialog; import storybook.ui.dialog.FirstStartDialog; import storybook.ui.dialog.PostModelUpdateDialog; import storybook.ui.dialog.SplashDialog; import storybook.ui.dialog.file.NewFileDialog; public class SbApp extends Component { private static boolean bTrace = false; private static boolean bTraceHibernate = false; private static SbApp instance; private static String i18nFile; private static boolean bDevTest = false; public static boolean isDevTest() { return (bDevTest); } private PreferenceModel preferenceModel; private PreferenceController preferenceController; private final List<MainFrame> mainFrames; private Font defaultFont; private SbApp() { mainFrames = new ArrayList<>(); } private void init() { trace("SbApp.init()"); SplashDialog dlgStart = new SplashDialog("oStorybook init"); try { MainFrame mainFrame = new MainFrame(); // preference model and controller trace("-->PreferenceController()"); preferenceController = new PreferenceController(); trace("-->PreferenceModel()"); preferenceModel = new PreferenceModel(mainFrame); trace("-->PreferenceModel.attachModel()"); preferenceController.attachModel(preferenceModel); trace("-->PreferenceController.attachView()"); preferenceController.attachView(this); trace("-->initI18N()"); initI18N(); trace("-->SwingUtil.setLookAndFeel()"); SwingUtil.setLookAndFeel(); restoreDefaultFont(); // first start dialog Preference prefFirstStart = PrefUtil.get(PreferenceKey.FIRST_START_4, true); if (prefFirstStart.getBooleanValue()) { FirstStartDialog dlg = new FirstStartDialog(); SwingUtil.showModalDialog(dlg, null); PrefUtil.set(PreferenceKey.FIRST_START_4, false); } Preference pref = PrefUtil.get(PreferenceKey.OPEN_LAST_FILE, false); boolean fileHasBeenOpened = false; if (pref.getBooleanValue()) { Preference pref2 = PrefUtil.get(PreferenceKey.LAST_OPEN_FILE, ""); DbFile dbFile = new DbFile(pref2.getStringValue()); trace("SbApp.init(): loading... " + dbFile); fileHasBeenOpened = openFile(dbFile); } if (fileHasBeenOpened) { // check for updates Updater.checkForUpdate(); dlgStart.dispose(); return; } mainFrame.init(); mainFrame.initBlankUi(); addMainFrame(mainFrame); // check for updates Updater.checkForUpdate(); /* abandon de l'appel au garbarge collector, utilisation non recommande Timer t1 = new Timer(10000, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { runGC(); } }); t1.start(); */ } catch (Exception e) { error("SbApp.init()", e); dlgStart.dispose(); ExceptionDialog dlg = new ExceptionDialog(e); SwingUtil.showModalDialog(dlg, null); } dlgStart.dispose(); } public void initI18N() { trace("SbApp.initI18N()"); String localeStr = PrefUtil.get(PreferenceKey.LANG, SbConstants.DEFAULT_LANG).getStringValue(); SbConstants.Language lang = SbConstants.Language.valueOf(localeStr); Locale locale = lang.getLocale(); setLocale(locale); I18N.initResourceBundles(getLocale()); } public PreferenceModel getPreferenceModel() { return preferenceModel; } public PreferenceController getPreferenceController() { return preferenceController; } public List<MainFrame> getMainFrames() { return mainFrames; } public void addMainFrame(MainFrame mainFrame) { trace("SbApp.addMainFrame(" + mainFrame.getName() + ")"); mainFrames.add(mainFrame); } public void removeMainFrame(MainFrame mainFrame) { trace("SbApp.removeMainFrame(" + mainFrame.getName() + ")"); for (MainFrame m : mainFrames) m.saveAllTableDesign(); mainFrames.remove(mainFrame); } public void closeBlank() { trace("SbApp.closeBlank()"); for (MainFrame mainFrame : mainFrames) { if (mainFrame.isBlank()) { mainFrames.remove(mainFrame); mainFrame.dispose(); } } } /* suppression de l'appel du garbage collector public void runGC(){ System.gc(); } */ public static SbApp getInstance() { if (instance == null) { instance = new SbApp(); } return instance; } public void createNewFile() { trace("SbApp.createNewFile()"); try { NewFileDialog dlg = new NewFileDialog(); SwingUtil.showModalDialog(dlg, null); if (dlg.isCanceled()) { return; } DbFile dbFile = new DbFile(dlg.getFile()); String dbName = dbFile.getDbName(); if (dbName == null) { return; } final MainFrame newMainFrame = new MainFrame(); newMainFrame.init(dbFile); newMainFrame.getBookModel().initEntites(); BookUtil.store(newMainFrame, BookKey.USE_HTML_SCENES, dlg.getUseHtmlScenes()); BookUtil.store(newMainFrame, BookKey.USE_HTML_DESCR, dlg.getUseHtmlDescr()); BookUtil.store(newMainFrame, BookKey.BOOK_CREATION_DATE, new SimpleDateFormat("dd/MM/yy").format(new Date())); newMainFrame.initUi(); newMainFrame.getBookController().fireAgain(); addMainFrame(newMainFrame); closeBlank(); updateFilePref(dbFile); setDefaultCursor(); } catch (Exception e) { error("SbApp.createNewFile()", e); } } public void renameFile(final MainFrame mainFrame, File file) { trace("SbApp.renameFile(" + mainFrame.getName() + "," + file.getAbsolutePath() + ")"); try { FileUtils.copyFile(mainFrame.getDbFile().getFile(), file); DbFile dbFile = new DbFile(file); OpenFileAction act = new OpenFileAction("", dbFile); act.actionPerformed(null); Timer t1 = new Timer(1000, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { mainFrame.close(); } }); t1.setRepeats(false); t1.start(); Timer t2 = new Timer(4000, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { mainFrame.getDbFile().getFile().delete(); } }); t2.setRepeats(false); t2.start(); } catch (IOException e) { error("SbApp.renameFile(" + mainFrame.getName() + "," + file.getName() + ")", e); } } public boolean openFile() { trace("SbApp.openFile()"); final DbFile dbFile = BookUtil.openDocumentDialog(); if (dbFile == null) { return false; } return openFile(dbFile); } public boolean openFile(final DbFile dbFile) { trace("SbApp.openFile(" + dbFile.getDbName() + ")"); try { // file doesn't exist if (!dbFile.getFile().exists()) { String txt = I18N.getMsg("msg.dlg.project.not.exits.text", dbFile.getFile().getPath()); JOptionPane.showMessageDialog(null, txt, I18N.getMsg("msg.dlg.project.not.exits.title"), JOptionPane.ERROR_MESSAGE); return false; } // file is read-only if (!dbFile.getFile().canWrite()) { String txt = I18N.getMsg("msg.error.db.read.only", dbFile.getFile().getPath()); JOptionPane.showMessageDialog(null, txt, I18N.getMsg("msg.common.warning"), JOptionPane.ERROR_MESSAGE); return false; } // file already opened String dbName = dbFile.getDbName(); if (checkIfAlreadyOpened(dbName)) { return true; } // model update from Storybook 3.x to 4.0 final ModelMigration oldPersMngr = ModelMigration.getInstance(); oldPersMngr.open(dbFile); try { if (!oldPersMngr.checkAndAlterModel()) { oldPersMngr.closeConnection(); return false; } } catch (Exception e) { oldPersMngr.closeConnection(); SbApp.error("SbApp.openFile(" + dbFile.getDbName() + ")", e); ExceptionDialog dlg = new ExceptionDialog(e); SwingUtil.showModalDialog(dlg, null); return false; } oldPersMngr.closeConnection(); setWaitCursor(); String text = I18N.getMsg("msg.common.loading", dbFile.getName()); //final HourglassSplash dlg = new HourglassSplash(text); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { try { MainFrame newMainFrame = new MainFrame(); newMainFrame.init(dbFile); newMainFrame.initUi(); addMainFrame(newMainFrame); closeBlank(); updateFilePref(dbFile); reloadMenuBars(); setDefaultCursor(); //dlg.dispose(); if (oldPersMngr.hasAlteredDbModel()) { PostModelUpdateDialog dlg2 = new PostModelUpdateDialog(newMainFrame); SwingUtil.showModalDialog(dlg2, newMainFrame); } } catch (Exception e) { e.printStackTrace(); } } }); } catch (HeadlessException e) { } return true; } private boolean checkIfAlreadyOpened(String dbName) { trace("SbApp.checkIfAlreadyOpened(" + dbName + ")"); for (MainFrame mainFrame : mainFrames) { if (mainFrame.isBlank()) { continue; } if (mainFrame.getDbFile().getDbName().equals(dbName)) { mainFrame.setVisible(true); return true; } } return false; } private void updateFilePref(DbFile dbFile) { trace("SbApp.updateFilePref(" + dbFile.getDbName() + ")"); // save last open directory and file File file = dbFile.getFile(); PrefUtil.set(PreferenceKey.LAST_OPEN_DIR, file.getParent()); PrefUtil.set(PreferenceKey.LAST_OPEN_FILE, file.getPath()); // save recent files List<DbFile> list = PrefUtil.getDbFileList(); if (!list.contains(dbFile)) { list.add(dbFile); } // check recent files and remove non-existing entries Iterator<DbFile> it = list.iterator(); while (it.hasNext()) { DbFile dbFile2 = it.next(); if (!dbFile2.getFile().exists()) { it.remove(); } } PrefUtil.setDbFileList(list); reloadMenuBars(); } public void clearRecentFiles() { trace("SbApp.clearRecentFiles()"); PrefUtil.setDbFileList(new ArrayList<DbFile>()); reloadMenuBars(); } public void exit() { trace("SbApp.exit()"); if (mainFrames.size() > 0) { Preference pref = PrefUtil.get(PreferenceKey.CONFIRM_EXIT, true); if (pref.getBooleanValue()) { int n = JOptionPane.showConfirmDialog(null, I18N.getMsg("msg.mainframe.want.exit"), I18N.getMsg("msg.common.exit"), JOptionPane.YES_NO_OPTION); if (n == JOptionPane.NO_OPTION || n == JOptionPane.CLOSED_OPTION) { return; } } saveAll(); } System.exit(0); } public void resetUiFont() { if (defaultFont == null) { return; } SwingUtil.setUIFont( new FontUIResource(defaultFont.getName(), defaultFont.getStyle(), defaultFont.getSize())); } public void setDefaultFont(Font font) { if (font == null) { return; } defaultFont = font; resetUiFont(); PrefUtil.set(PreferenceKey.DEFAULT_FONT_NAME, font.getName()); PrefUtil.set(PreferenceKey.DEFAULT_FONT_SIZE, font.getSize()); PrefUtil.set(PreferenceKey.DEFAULT_FONT_STYLE, font.getStyle()); } public Font getDefaultFont() { return this.defaultFont; } public void restoreDefaultFont() { Preference pref = PrefUtil.get(PreferenceKey.DEFAULT_FONT_NAME, SbConstants.DEFAULT_FONT_NAME); String name = SbConstants.DEFAULT_FONT_NAME; if (pref != null && !pref.getStringValue().isEmpty()) { name = pref.getStringValue(); } pref = PrefUtil.get(PreferenceKey.DEFAULT_FONT_STYLE, SbConstants.DEFAULT_FONT_STYLE); int style = 0; if (pref != null) { style = pref.getIntegerValue(); } pref = PrefUtil.get(PreferenceKey.DEFAULT_FONT_SIZE, SbConstants.DEFAULT_FONT_SIZE); int size = 0; if (pref != null) { size = pref.getIntegerValue(); } // set default font setDefaultFont(new Font(name, style, size)); } public void refresh() { trace("SbApp.refresh()"); for (MainFrame mainFrame : mainFrames) { int width = mainFrame.getWidth(); int height = mainFrame.getHeight(); boolean maximized = mainFrame.isMaximized(); mainFrame.getSbActionManager().reloadMenuToolbar(); mainFrame.setSize(width, height); if (maximized) { mainFrame.setMaximized(); } mainFrame.refresh(); } } public void reloadMenuBars() { for (MainFrame mainFrame : mainFrames) { mainFrame.getSbActionManager().reloadMenuToolbar(); } } public void reloadStatusBars() { for (MainFrame mainFrame : mainFrames) { mainFrame.refreshStatusBar(); } } public void setWaitCursor() { for (MainFrame mainFrame : mainFrames) { SwingUtil.setWaitingCursor(mainFrame); } } public void setDefaultCursor() { for (MainFrame mainFrame : mainFrames) { SwingUtil.setDefaultCursor(mainFrame); } } public void saveAll() { trace("SbApp.saveAll()"); for (MainFrame mainFrame : mainFrames) { mainFrame.getSbActionManager().getActionHandler().handleFileSave(); } } public void modelPropertyChange(PropertyChangeEvent evt) { // works, but currently not used // may be used for entity copying between files // String propName = evt.getPropertyName(); // Object newValue = evt.getNewValue(); // Object oldValue = evt.getOldValue(); } public static void main(String[] args) { String tempDir = System.getProperty("java.io.tmpdir"); String fn = tempDir + File.separator + "storybook.lck"; if (args.length > 0) { for (int i = 0; i < args.length; i++) { if (args[i].equalsIgnoreCase("--trace")) { SbApp.bTrace = true; System.out.println("Storybook execution in trace mode"); } if (args[i].equalsIgnoreCase("--hibernate")) { SbApp.bTraceHibernate = true; System.out.println("Hibernate in trace mode"); } if (args[i].equalsIgnoreCase("--dev")) { SbApp.bDevTest = true; System.out.println("Development test"); } if (args[i].equalsIgnoreCase("--msg")) { File f = new File(args[i + 1] + ".properties"); if (!f.exists()) { System.out.println("Msg test file not exists : " + args[i + 1]); } else { SbApp.i18nFile = args[i + 1]; System.out.println("Msg test file is : " + SbApp.i18nFile); } } } } if (!lockInstance(fn)) { Object[] options = { I18N.getMsg("msg.running.remove"), I18N.getMsg("msg.common.cancel") }; int n = JOptionPane.showOptionDialog(null, I18N.getMsg("msg.running.msg"), I18N.getMsg("msg.running.title"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[1]); if (n == 0) { File file = new File(fn); if (file.exists() && file.canWrite()) { if (!file.delete()) { JOptionPane.showMessageDialog(null, "Delete failed", "File\n" + file.getAbsolutePath() + "\ncould not be deleted.", JOptionPane.ERROR_MESSAGE); } } } return; } SwingUtilities.invokeLater(new Runnable() { @Override public void run() { SbApp app = SbApp.getInstance(); app.init(); } }); } private static boolean lockInstance(final String lockFile) { try { final File file = new File(lockFile); final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); final FileLock fileLock = randomAccessFile.getChannel().tryLock(); if (fileLock != null) { Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { try { fileLock.release(); randomAccessFile.close(); file.delete(); } catch (IOException e) { System.err.println("Unable to remove lock file: " + lockFile + "->" + e.getMessage()); } } }); return true; } } catch (IOException e) { System.err.println("Unable to create and/or lock file: " + lockFile + "->" + e.getMessage()); } return false; } public static void error(String txt, Exception e) { System.err.println(txt + " Exception:" + e.getMessage()); } public static void trace(String msg) { if (bTrace) { System.out.println(msg); } } public static boolean getTrace() { return (bTrace); } public static boolean getTraceHibernate() { return (bTraceHibernate); } public static String getI18nFile() { return (i18nFile); } public static void setI18nFile(String file) { i18nFile = file; } public static void setTrace(boolean b) { bTrace = b; System.out.println((b ? "Enter" : "Exit") + " trace mode"); } }