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 &lt;dev@shredzone.de&gt;
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    }