001 /** 002 * iFish - An iRiver iHP jukebox database creation tool 003 * 004 * Copyright (C) 2009 Richard "Shred" Körber 005 * http://ifish.shredzone.org 006 * 007 * This program is free software: you can redistribute it and/or modify 008 * it under the terms of the GNU General Public License as published by 009 * the Free Software Foundation, either version 3 of the License, or 010 * (at your option) any later version. 011 * 012 * This program is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 * GNU General Public License for more details. 016 * 017 * You should have received a copy of the GNU General Public License 018 * along with this program. If not, see <http://www.gnu.org/licenses/>. 019 */ 020 package net.shredzone.ifish; 021 022 import java.awt.BorderLayout; 023 import java.awt.Container; 024 import java.awt.Dimension; 025 import java.awt.Frame; 026 import java.awt.Point; 027 import java.awt.event.WindowAdapter; 028 import java.awt.event.WindowEvent; 029 import java.beans.PropertyChangeEvent; 030 import java.beans.PropertyChangeListener; 031 import java.text.DateFormat; 032 import java.text.NumberFormat; 033 import java.util.Locale; 034 import java.util.prefs.Preferences; 035 036 import javax.swing.Action; 037 import javax.swing.Box; 038 import javax.swing.JCheckBoxMenuItem; 039 import javax.swing.JFrame; 040 import javax.swing.JMenu; 041 import javax.swing.JMenuBar; 042 import javax.swing.JMenuItem; 043 import javax.swing.JOptionPane; 044 import javax.swing.JToolBar; 045 import javax.swing.event.ChangeEvent; 046 import javax.swing.event.ChangeListener; 047 048 import net.shredzone.ifish.actions.AboutAction; 049 import net.shredzone.ifish.actions.IFishAction; 050 import net.shredzone.ifish.actions.QuitAction; 051 import net.shredzone.ifish.actions.ReadDatabaseAction; 052 import net.shredzone.ifish.actions.SyncDatabaseAction; 053 import net.shredzone.ifish.gui.ExceptionDialog; 054 import net.shredzone.ifish.gui.NaviDbTableModel; 055 import net.shredzone.ifish.i18n.L; 056 import net.shredzone.ifish.pool.ImgPool; 057 import net.shredzone.jshred.swing.JLAFSelector; 058 import net.shredzone.jshred.swing.JToolbarButton; 059 import net.shredzone.jshred.swing.MenuActionProxy; 060 import net.shredzone.jshred.swing.SwingUtils; 061 062 /** 063 * This is the IFish starter class, for application and WebStart. 064 * 065 * @author Richard Körber <dev@shredzone.de> 066 * @version $Id: IFish.java 291 2009-04-28 21:29:27Z shred $ 067 */ 068 public class IFish extends JFrame implements QuitAction.Quittable, PropertyChangeListener, Version { 069 private static final long serialVersionUID = 3257290223015638579L; 070 071 private IFishPane fishpane; 072 private JMenuBar menubar; 073 private JToolBar toolbar; 074 075 /** 076 * Create a new IFish. 077 */ 078 public IFish() { 079 //--- Set title and icon --- 080 setIconImage( ImgPool.get( "icon.png" ).getImage() ); 081 setTitle( L.tr("generic.title")+" v"+VERSION ); 082 setDefaultCloseOperation( DO_NOTHING_ON_CLOSE ); 083 084 //--- Create the IFishPane --- 085 fishpane = new IFishPane(); 086 fishpane.addPropertyChangeListener( this ); 087 088 //--- Set the quit implementation --- 089 QuitAction qa = (QuitAction) fishpane.getAction( IFishPane.ACTION_QUIT ); 090 qa.setQuitter( this ); 091 092 //--- Create the Menu bar --- 093 menubar = new JMenuBar(); 094 setJMenuBar( menubar ); 095 096 //--- Set the main layout --- 097 Container jPane = getContentPane(); 098 jPane.setLayout( new BorderLayout() ); 099 { 100 //--- Create the Tool bar --- 101 toolbar = new JToolBar( L.tr("generic.toolbar") ); 102 toolbar.setRollover( true ); 103 jPane.add( toolbar, BorderLayout.NORTH ); 104 105 //--- Add the fishpane --- 106 jPane.add( fishpane, BorderLayout.CENTER ); 107 } 108 109 //--- Create the menu --- 110 createMenu( menubar ); 111 createToolbar( toolbar ); 112 113 //--- Set location and size --- 114 IFishPrefs prefs = fishpane.getPrefs(); 115 116 int pw = prefs.getNode().getInt( "win.size.w", -1 ); 117 int ph = prefs.getNode().getInt( "win.size.h", -1 ); 118 if( pw>=0 && ph>=0 ) { 119 setSize( pw, ph ); 120 }else { 121 pack(); 122 } 123 124 int px = prefs.getNode().getInt( "win.pos.x", -9999 ); 125 int py = prefs.getNode().getInt( "win.pos.y", -9999 ); 126 if( px!=-9999 && py!=-9999 ) { 127 setLocation( px, py ); 128 }else { 129 setLocationRelativeTo( null ); 130 } 131 132 setExtendedState( prefs.getNode().getInt( "win.ext", Frame.NORMAL ) ); 133 134 fishpane.recallGUI( prefs.getNode() ); 135 136 //--- Show up --- 137 setVisible( true ); 138 139 //--- Set closing functionality --- 140 addWindowListener( new WindowAdapter() { 141 @Override 142 public void windowClosing( WindowEvent e ) { 143 fishpane.getAction( IFishPane.ACTION_QUIT ).perform(); 144 } 145 }); 146 147 //--- Show warning dialog --- 148 if( prefs.isFirstTime() ) { 149 final String message = L.tr("first.message"); 150 final String title = L.tr("first.title"); 151 JOptionPane.showMessageDialog( this, message, title, JOptionPane.INFORMATION_MESSAGE ); 152 prefs.setFirstTime( false ); 153 } 154 155 //--- Read database for the first time --- 156 IFishAction aReadDatabase = fishpane.getAction( IFishPane.ACTION_READDATABASE ); 157 aReadDatabase.perform(); 158 } 159 160 /** 161 * Create the menu items 162 */ 163 protected void createMenu( JMenuBar menubar ) { 164 final JCheckBoxMenuItem debugItem; 165 166 JMenu jmFile = SwingUtils.createJMenu( L.tr("menu.file") ); 167 menubar.add( jmFile ); 168 JMenu jmTab = SwingUtils.createJMenu( L.tr("menu.tab") ); 169 menubar.add( jmTab ); 170 JMenu jmPlayer = SwingUtils.createJMenu( L.tr("menu.player") ); 171 menubar.add( jmPlayer ); 172 menubar.add( Box.createHorizontalGlue() ); 173 JMenu jmHelp = SwingUtils.createJMenu( L.tr("menu.help") ); 174 menubar.add( jmHelp ); 175 176 jmFile.add( new JMenuItem( new MenuActionProxy( fishpane.getAction( IFishPane.ACTION_READDATABASE ) ) ) ); 177 jmFile.add( new JMenuItem( new MenuActionProxy( fishpane.getAction( IFishPane.ACTION_SYNCDATABASE ) ) ) ); 178 jmFile.add( new JMenuItem( new MenuActionProxy( fishpane.getAction( IFishPane.ACTION_SAVEDATABASE ) ) ) ); 179 jmFile.add( new JMenuItem( new MenuActionProxy( fishpane.getAction( IFishPane.ACTION_DELETEDATABASE ) ) ) ); 180 jmFile.addSeparator(); 181 jmFile.add( new JMenuItem( new MenuActionProxy( fishpane.getAction( IFishPane.ACTION_EXPORTDATABASE ) ) ) ); 182 jmFile.addSeparator(); 183 jmFile.add( new JMenuItem( new MenuActionProxy( fishpane.getAction( IFishPane.ACTION_PREFS ) ) ) ); 184 jmFile.addSeparator(); 185 jmFile.add( new JMenuItem( new MenuActionProxy( fishpane.getAction( IFishPane.ACTION_QUIT ) ) ) ); 186 187 jmTab.add( new JMenuItem( new MenuActionProxy( fishpane.getAction( IFishPane.ACTION_TAB_SCANNER ) ) ) ); 188 jmTab.add( new JMenuItem( new MenuActionProxy( fishpane.getAction( IFishPane.ACTION_TAB_DB ) ) ) ); 189 jmTab.add( new JMenuItem( new MenuActionProxy( fishpane.getAction( IFishPane.ACTION_TAB_PLAYLIST ) ) ) ); 190 191 jmPlayer.add( new JMenuItem( new MenuActionProxy( fishpane.getAction( IFishPane.ACTION_PLAYER_PLAY ) ) ) ); 192 jmPlayer.add( new JMenuItem( new MenuActionProxy( fishpane.getAction( IFishPane.ACTION_PLAYER_PAUSE ) ) ) ); 193 jmPlayer.add( new JMenuItem( new MenuActionProxy( fishpane.getAction( IFishPane.ACTION_PLAYER_STOP ) ) ) ); 194 195 jmHelp.add( debugItem = new JCheckBoxMenuItem( L.tr("menu.debug") , false ) ); 196 jmHelp.addSeparator(); 197 jmHelp.add( new JMenuItem( new MenuActionProxy( fishpane.getAction( IFishPane.ACTION_ABOUT ) ) ) ); 198 199 debugItem.addChangeListener( new ChangeListener() { 200 @Override 201 public void stateChanged( ChangeEvent e ) { 202 ExceptionDialog.setDebug( debugItem.isSelected() ); 203 } 204 }); 205 } 206 207 /** 208 * Create the Toolbar 209 * 210 * @param toolbar Toolbar to add the buttons to 211 */ 212 protected void createToolbar( JToolBar toolbar ) { 213 toolbar.add( new JToolbarButton( fishpane.getAction( IFishPane.ACTION_READDATABASE ) ) ); 214 toolbar.add( new JToolbarButton( fishpane.getAction( IFishPane.ACTION_SYNCDATABASE ) ) ); 215 toolbar.add( new JToolbarButton( fishpane.getAction( IFishPane.ACTION_SAVEDATABASE ) ) ); 216 // toolbar.add( new JToolbarButton( fishpane.getAction( IFishPane.ACTION_DELETEDATABASE ) ) ); 217 toolbar.addSeparator(); 218 toolbar.add( new JToolbarButton( fishpane.getAction( IFishPane.ACTION_PLAYER_PLAY ) ) ); 219 toolbar.add( new JToolbarButton( fishpane.getAction( IFishPane.ACTION_PLAYER_PAUSE ) ) ); 220 toolbar.add( new JToolbarButton( fishpane.getAction( IFishPane.ACTION_PLAYER_STOP ) ) ); 221 toolbar.addSeparator(); 222 toolbar.add( new JToolbarButton( fishpane.getAction( IFishPane.ACTION_PREFS ) ) ); 223 toolbar.add( Box.createGlue() ); 224 toolbar.add( new JToolbarButton( new MyAboutAction( fishpane ) ) ); 225 } 226 227 /** 228 * Quittable implementation: close the iFish. 229 */ 230 @Override 231 public void quit() { 232 //--- Hide the window --- 233 setVisible( false ); 234 235 Preferences prefs = fishpane.getPrefs().getNode(); 236 237 //--- Remember the IFishPane --- 238 fishpane.storeGUI( prefs ); 239 240 //--- Remember position and size --- 241 int state = getExtendedState(); 242 if( state==Frame.NORMAL || state==Frame.ICONIFIED ) { 243 Point pnt = getLocation(); 244 Dimension dim = getSize(); 245 prefs.putInt( "win.pos.x" , pnt.x ); 246 prefs.putInt( "win.pos.y" , pnt.y ); 247 prefs.putInt( "win.size.w", dim.width ); 248 prefs.putInt( "win.size.h", dim.height ); 249 } 250 prefs.putInt( "win.ext", state ); 251 252 //--- Dispose the window, quitting the application --- 253 dispose(); 254 } 255 256 /** 257 * PropertyChangeListener implementation, do not use. 258 * 259 * @param evt PropertyChangeEvent 260 */ 261 @Override 262 public void propertyChange( PropertyChangeEvent evt ) { 263 if( evt.getPropertyName().equals("unsaved") ) { 264 String title = ""; 265 if( evt.getNewValue().equals( Boolean.TRUE ) ) { 266 title += "* "; 267 } 268 title += L.tr("generic.title")+" v"+VERSION; 269 setTitle( title ); 270 } 271 } 272 273 /** 274 * Synchronizing without GUI 275 */ 276 public static void syncNoGUI() { 277 final NumberFormat fmt = NumberFormat.getIntegerInstance(); 278 final DateFormat fmtDate = DateFormat.getDateTimeInstance(); 279 final IFishPane fishpane = new IFishPane(); 280 281 System.out.println( L.tr("shell.reading") ); 282 System.out.println( " "+L.tr("shell.basedir")+" "+fishpane.getPrefs().getDirectory() ); 283 ((ReadDatabaseAction) fishpane.getAction( IFishPane.ACTION_READDATABASE )).performSync(); 284 285 System.out.println( L.tr("shell.syncing") ); 286 ((SyncDatabaseAction) fishpane.getAction( IFishPane.ACTION_SYNCDATABASE )).performSync(); 287 288 NaviDbTableModel model = fishpane.getDatabase(); 289 System.out.println( " "+L.tr("shell.added")+" "+fmt.format( model.getAddCounter() ) ); 290 System.out.println( " "+L.tr("shell.updated")+" "+fmt.format( model.getUpdateCounter() ) ); 291 System.out.println( " "+L.tr("shell.removed")+" "+fmt.format( model.getRemoveCounter() ) ); 292 System.out.println( " "+L.tr("shell.entries")+" "+fmt.format( model.size() ) ); 293 System.out.println( " "+L.tr("shell.date")+" "+fmtDate.format( model.getCreationDate() ) ); 294 295 System.out.println( L.tr("shell.done") ); 296 } 297 298 /** 299 * Starting iFish... 300 * 301 * @param args Arguments 302 */ 303 public static void main( String args[] ) { 304 //--- Check parameters --- 305 if( args.length==1 && args[0].equals("--sync") ) { 306 //--- Sync without GUI --- 307 syncNoGUI(); 308 309 }else { 310 //--- Do some MacX patches --- 311 boolean isMacOS = ( System.getProperty("mrj.version") != null ); 312 if( isMacOS ) { 313 System.setProperty( "apple.laf.useScreenMenuBar", "true" ); 314 System.setProperty( "com.apple.mrj.application.apple.menu.about.name", "iFish" ); 315 } 316 317 //--- Show GUI --- 318 final IFishPrefs prefs = IFishPrefs.instance(); 319 320 final Locale loc = prefs.getLanguage(); 321 if( loc!=null ) { 322 Locale.setDefault( loc ); 323 } 324 325 final String laf = prefs.getLAF(); 326 JLAFSelector.setLookAndFeel( laf ); 327 328 new IFish(); 329 } 330 } 331 332 /*--------------------------------------------------------------------*/ 333 334 /** 335 * Overrides the AboutAction and replaces the standard icon by the 336 * nice I-fish. :) 337 */ 338 private static class MyAboutAction extends AboutAction { 339 private static final long serialVersionUID = 3978424715302023216L; 340 341 public MyAboutAction( IFishPane fish ) { 342 super(fish); 343 putValue( Action.SMALL_ICON, ImgPool.get("ifish-button.png") ); 344 } 345 } 346 347 348 }