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.Component;
024    import java.awt.event.ActionEvent;
025    import java.awt.event.KeyEvent;
026    import java.util.HashMap;
027    import java.util.Map;
028    import java.util.prefs.Preferences;
029    
030    import javax.swing.Action;
031    import javax.swing.Icon;
032    import javax.swing.JCheckBoxMenuItem;
033    import javax.swing.JOptionPane;
034    import javax.swing.JPanel;
035    import javax.swing.JTabbedPane;
036    import javax.swing.KeyStroke;
037    
038    import net.shredzone.ifish.actions.AboutAction;
039    import net.shredzone.ifish.actions.DeleteDatabaseAction;
040    import net.shredzone.ifish.actions.ExportDatabaseAction;
041    import net.shredzone.ifish.actions.IFishAction;
042    import net.shredzone.ifish.actions.PlayerAction;
043    import net.shredzone.ifish.actions.PrefsAction;
044    import net.shredzone.ifish.actions.QuitAction;
045    import net.shredzone.ifish.actions.ReadDatabaseAction;
046    import net.shredzone.ifish.actions.SaveDatabaseAction;
047    import net.shredzone.ifish.actions.SyncDatabaseAction;
048    import net.shredzone.ifish.db.Entry;
049    import net.shredzone.ifish.db.PlaylistDb;
050    import net.shredzone.ifish.gui.DatabasePane;
051    import net.shredzone.ifish.gui.NaviDbTableModel;
052    import net.shredzone.ifish.gui.PlaylistPane;
053    import net.shredzone.ifish.gui.ScannerPane;
054    import net.shredzone.ifish.gui.StatusProgressBar;
055    import net.shredzone.ifish.i18n.L;
056    import net.shredzone.ifish.pool.ImgPool;
057    
058    /**
059     * This is the IFish's main pane, with all the buttons and stuff.
060     *
061     * @author  Richard Körber &lt;dev@shredzone.de&gt;
062     * @version $Id: IFishPane.java 291 2009-04-28 21:29:27Z shred $
063     */
064    public class IFishPane extends JPanel {
065      private static final long serialVersionUID = 3257850965439559731L;
066    
067      public static final String ACTION_READDATABASE   = "db.read";
068      public static final String ACTION_SYNCDATABASE   = "db.sync";
069      public static final String ACTION_SAVEDATABASE   = "db.save";
070      public static final String ACTION_DELETEDATABASE = "db.delete";
071      public static final String ACTION_EXPORTDATABASE = "db.export";
072      public static final String ACTION_ABOUT          = "about";
073      public static final String ACTION_PREFS          = "prefs";
074      public static final String ACTION_QUIT           = "quit";
075      public static final String ACTION_TAB_SCANNER    = "tab.scanner";
076      public static final String ACTION_TAB_DB         = "tab.db";
077      public static final String ACTION_TAB_PLAYLIST   = "tab.playlist";
078      public static final String ACTION_PLAYER_PLAY    = "player.play";
079      public static final String ACTION_PLAYER_PAUSE   = "player.pause";
080      public static final String ACTION_PLAYER_STOP    = "player.stop";
081      
082      private StatusProgressBar jprProgress;
083      private NaviDbTableModel model;
084      private PlaylistDb       plmodel;
085      private DatabasePane database;
086      private PlaylistPane plpane;
087      private JTabbedPane tabpane;
088      private ScannerPane scanner;
089      private final String plBaseDir;
090      private PlaylistSource plsource = null;
091      private IFishPrefs prefs;
092      private Map<String, Action> mActions = new HashMap<String, Action>();
093      private boolean hasChanges = false;
094      
095      /**
096       * Create the IFish's main pane.
097       */
098      public IFishPane() {
099        setLayout( new BorderLayout() );
100    
101        //--- Get preferences ---
102        prefs = IFishPrefs.instance();
103        
104        //--- Get basic settings ---
105        plBaseDir = prefs.getPLBaseDir();
106    
107        //--- Create all actions ---
108        mActions.put( ACTION_QUIT          , new QuitAction( this ) );
109        mActions.put( ACTION_ABOUT         , new AboutAction( this ) );
110        mActions.put( ACTION_PREFS         , new PrefsAction( this ) );
111        mActions.put( ACTION_READDATABASE  , new ReadDatabaseAction( this ) );
112        mActions.put( ACTION_SYNCDATABASE  , new SyncDatabaseAction( this ) );
113        mActions.put( ACTION_SAVEDATABASE  , new SaveDatabaseAction( this ) );
114        mActions.put( ACTION_DELETEDATABASE, new DeleteDatabaseAction( this ) );
115        mActions.put( ACTION_EXPORTDATABASE, new ExportDatabaseAction( this ) );
116        mActions.put( ACTION_PLAYER_PLAY   , new PlayerAction( this, PlayerAction.PLAY  ) );
117        mActions.put( ACTION_PLAYER_PAUSE  , new PlayerAction( this, PlayerAction.PAUSE ) );
118        mActions.put( ACTION_PLAYER_STOP   , new PlayerAction( this, PlayerAction.STOP  ) );
119    
120        //--- Create the database table ---
121        database = new DatabasePane( this );
122        model = new NaviDbTableModel();
123        database.setModel( model );
124        
125        //--- Create the playlist ---
126        plpane = new PlaylistPane( this );
127        
128        //--- The Progress bar ---
129        jprProgress = new StatusProgressBar();
130        add( jprProgress, BorderLayout.SOUTH );
131    
132        //--- Create the TabbedPane ---
133        scanner = new ScannerPane( this );
134        tabpane = new JTabbedPane();
135    
136        addTab( 
137          L.tr("main.tab.scanner"),
138          ImgPool.get("tab_sync.png"),
139          scanner,
140          L.tr("main.tab.scanner.tt"),
141          ACTION_TAB_SCANNER,
142          KeyStroke.getKeyStroke( KeyEvent.VK_1, ActionEvent.CTRL_MASK )
143        );
144    
145        addTab(
146          L.tr("main.tab.database"),
147          ImgPool.get("tab_database.png"),
148          database,
149          L.tr("main.tab.database.tt"),
150          ACTION_TAB_DB,
151          KeyStroke.getKeyStroke( KeyEvent.VK_2, ActionEvent.CTRL_MASK )
152        );
153    
154        addTab(
155          L.tr("main.tab.playlist"),
156          ImgPool.get("tab_playlist.png"),
157          plpane,
158          L.tr("main.tab.playlist.tt"),
159          ACTION_TAB_PLAYLIST,
160          KeyStroke.getKeyStroke( KeyEvent.VK_3, ActionEvent.CTRL_MASK )
161        );
162    
163        add( tabpane, BorderLayout.CENTER );
164      }
165      
166      /**
167       * Get the Action named with the given key.
168       *
169       * @param   key     Action you are asking for
170       * @return  The Action or null
171       */
172      public IFishAction getAction( String key ) {
173        return (IFishAction) mActions.get( key );
174      }
175      
176      /**
177       * Get the Preferences
178       *
179       * @return  Preferences
180       */
181      public IFishPrefs getPrefs() {
182        return prefs;
183      }
184      
185      /**
186       * Get the Playlist's base directory.
187       * 
188       * @return  Base directory, default is "ifish".
189       */
190      public String getPLBase() {
191        return plBaseDir;
192      }
193      
194      /**
195       * Set that there have been unsaved changes.
196       * This is a bound property with the name "unsaved".
197       * 
198       * @param   unsaved       Unsaved changes
199       */
200      public void setUnsaved( boolean unsaved ) {
201        boolean old = hasChanges;
202        hasChanges = unsaved;
203        if( old!=unsaved ) {
204          firePropertyChange( "unsaved", Boolean.valueOf(old), Boolean.valueOf(unsaved) );
205        }
206      }
207      
208      /**
209       * Check if there are unsaved changes.
210       * 
211       * @return  true if there are unsaved changes.
212       */
213      public boolean isUnsaved() {
214        return hasChanges;
215      }
216      
217      /**
218       * Confirm if the user really wants to lose all unsaved changes.
219       * 
220       * @return    true: there are no unsaved changes, or the user wants to lose
221       *            them. false: there are unsaved changes and the user aborted the
222       *            operation.
223       */
224      public boolean confirmChanges() {
225        if(! isUnsaved() ) return true;
226        return JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(
227            this,
228            L.tr("lose.confirm"),
229            L.tr("lose.confirm.title"),
230            JOptionPane.YES_NO_OPTION,
231            JOptionPane.QUESTION_MESSAGE
232        );
233      }
234      
235      /**
236       * Get the StatusProgressBar that shows the status.
237       *
238       * @return  StatusProgressBar
239       */
240      public StatusProgressBar getStatusBar() {
241        return jprProgress;
242      }
243      
244      /**
245       * Get the current NaviDb database
246       *
247       * @return  Current Database
248       */
249      public NaviDbTableModel getDatabase() {
250        return model;
251      }
252      
253      /**
254       * Set a new database.
255       * This is a bound property with the name "database".
256       *
257       * @param   model       Database model to be shown
258       */
259      public void setDatabase( NaviDbTableModel model ) {
260        NaviDbTableModel old = this.model;
261        this.model = model;
262        database.setModel( model );
263        firePropertyChange( "database", old, model );
264      }
265      
266      /**
267       * Get the current PlaylistDb database
268       * 
269       * @return  Current Playlist database
270       */
271      public PlaylistDb getPlaylist() {
272        return plmodel;
273      }
274      
275      /**
276       * Set a new playlist database.
277       * This is a bound property with the name "playlist".
278       * 
279       * @param playlist    Playlist database
280       */
281      public void setPlaylist( PlaylistDb playlist ) {
282        PlaylistDb old = this.plmodel;
283        this.plmodel = playlist;
284        plpane.setPlaylistDb( playlist );
285        firePropertyChange( "playlist", old, playlist );
286      }
287      
288      /**
289       * Update the status panes with the data of the given model. This
290       * is not necessarily the current database.
291       *
292       * @param   model       Database model to be shown
293       */
294      public void updateStatus( NaviDbTableModel model ) {
295        scanner.update( model );
296      }
297      
298      /**
299       * Set the playlist source which is to be used for playlist selection.
300       * This is a bound property with the name "playlistsource".
301       * 
302       * @param source    Playlist Source
303       */
304      public void setPlaylistSource( PlaylistSource source ) {
305        PlaylistSource old = plsource;
306        plsource = source;
307        firePropertyChange( "playlistsource", old, source );
308      }
309      
310      /**
311       * Get the playlist source which is to be used for playlist selection.
312       * 
313       * @return Playlist source or null if none was set yet.
314       */
315      public PlaylistSource getPlaylistSource() {
316        return plsource;
317      }
318    
319      /**
320       * Get the currently selected Entries in the database or the playlist.
321       *
322       * @return    Array of Entry, might be empty but never null
323       */
324      public Entry[] getSelectedEntries() {
325        if( plsource==null ) return new Entry[0];
326        return plsource.getSelectedEntries();
327      }
328      
329      /**
330       * Get the entries currently selected in the database pane.
331       * 
332       * @return    Array of Entry, might be empty but never null
333       */
334      public Entry[] getSelectedDatabaseEntries() {
335        return database.getSelectedEntries();
336      }
337      
338      /**
339       * Add a tab to the main tabbed pane and the tab menu.
340       *
341       * @param   title       Tab title
342       * @param   icon        Tab icon
343       * @param   component   Component shown in the tab
344       * @param   tip         Tooltip
345       * @param   action      Action name that will show this tab
346       */
347      private void addTab( String title, Icon icon, Component component, String tip, String action, KeyStroke accel ) {
348        final int index = tabpane.getTabCount();
349        tabpane.addTab( title, icon, component, tip );
350        mActions.put( action, new IFishAction( this, title, icon, tip, accel ) {
351          private static final long serialVersionUID = 4050762710675110196L;
352          @Override
353          protected void action() {
354            tabpane.setSelectedIndex( index );
355          }
356        });
357      }
358      
359      /**
360       * Store the GUI settings, like selected tabs.
361       * 
362       * @param prefs   Preferences context to store into.
363       */
364      public void storeGUI( Preferences prefs ) {
365        prefs.putInt( "pane.tab.ix", tabpane.getSelectedIndex() );
366      }
367      
368      /**
369       * Recall previously stored GUI settings, or use reasonable defaults
370       * if there are none stored yet.
371       * 
372       * @param prefs   Preferences context to recall from.
373       */
374      public void recallGUI( Preferences prefs ) {
375        tabpane.setSelectedIndex( prefs.getInt( "pane.tab.ix", 0) );
376      }
377      
378    }
379