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.gui;
021    
022    import java.awt.BorderLayout;
023    import java.awt.Dimension;
024    import java.awt.event.ActionEvent;
025    import java.awt.event.KeyEvent;
026    import java.awt.event.MouseAdapter;
027    import java.awt.event.MouseEvent;
028    import java.util.prefs.Preferences;
029    
030    import javax.swing.BorderFactory;
031    import javax.swing.Icon;
032    import javax.swing.JButton;
033    import javax.swing.JList;
034    import javax.swing.JOptionPane;
035    import javax.swing.JPanel;
036    import javax.swing.JScrollPane;
037    import javax.swing.JSplitPane;
038    import javax.swing.JTable;
039    import javax.swing.JToolBar;
040    import javax.swing.KeyStroke;
041    import javax.swing.ListSelectionModel;
042    import javax.swing.event.ListSelectionEvent;
043    import javax.swing.event.ListSelectionListener;
044    
045    import net.shredzone.ifish.IFishPane;
046    import net.shredzone.ifish.IFishPrefs;
047    import net.shredzone.ifish.PlaylistSource;
048    import net.shredzone.ifish.actions.IFishAction;
049    import net.shredzone.ifish.db.Entry;
050    import net.shredzone.ifish.db.Playlist;
051    import net.shredzone.ifish.db.PlaylistDb;
052    import net.shredzone.ifish.i18n.L;
053    import net.shredzone.ifish.pool.ImgPool;
054    import net.shredzone.jshred.swing.JToolbarButton;
055    import net.shredzone.jshred.swing.SwingUtils;
056    
057    /**
058     * This panel allows to see the playlists.
059     *
060     * @author    Richard Körber &lt;dev@shredzone.de&gt;
061     * @version   $Id: PlaylistPane.java 291 2009-04-28 21:29:27Z shred $
062     */
063    public class PlaylistPane extends JPanel implements PlaylistSource, ListSelectionListener  {
064      private static final long serialVersionUID = 3834587690816844855L;
065    
066      private final IFishPane   fish;
067      private final IFishPrefs  prefs;
068      protected final MoveAction actionTop, actionUp, actionDown, actionBottom;
069      protected final SortAction actionAsc, actionDesc, actionShuffle;
070      protected final AllAction  actionAll;
071      protected final PasteAction actionPaste;
072      protected final RemoveAction actionRemove;
073      protected final CreateAction actionPLCreate;
074      protected final RenameAction actionPLRename;
075      protected final DeleteAction actionPLDelete;
076      
077      private JList       jlDirectory;
078      private JTable      jtPlaylist;
079      private JToolBar    jTools;
080      private JToolBar    jPLTools;
081      private Playlist    pl;
082      private JButton     jbCreate;
083      private JButton     jbRename;
084    
085      /**
086       * Create a PlaylistPane.
087       * 
088       * @param   fish      Reference to IFishPane
089       */
090      public PlaylistPane( IFishPane fish ) {
091        this.fish = fish;
092        this.prefs = fish.getPrefs();
093        
094        //--- Left: the playlist list ---
095        setLayout( new BorderLayout() );
096        
097        JSplitPane jSplit = new JSplitPane();
098        jSplit.setContinuousLayout( true );
099        jSplit.setBorder( null );
100        jSplit.setDividerSize( 3 );
101        add( jSplit, BorderLayout.CENTER );
102        
103        JPanel jpLeft = new JPanel( new BorderLayout() );
104        {
105          jlDirectory = new JList();
106          jlDirectory.setCellRenderer( new PlaylistCellRenderer() );
107          jlDirectory.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
108          jlDirectory.addListSelectionListener( this );
109    
110          jpLeft.add( new JScrollPane( jlDirectory ), BorderLayout.CENTER );
111    
112          jPLTools = new JToolBar( L.tr("pl.pltoolbar") );
113          jPLTools.setFloatable( false );
114          jPLTools.setRollover( true );
115          jpLeft.add( jPLTools, BorderLayout.NORTH );
116        }
117        jpLeft.setMinimumSize( new Dimension( 150, jpLeft.getMinimumSize().height ) );
118        jpLeft.setPreferredSize( new Dimension( 150, jpLeft.getPreferredSize().height ) );
119        jSplit.setLeftComponent( jpLeft );
120        
121        //--- Right: the playlist entries ---
122        JPanel jpRight = new JPanel( new BorderLayout() );
123        {
124          jtPlaylist = new JTable();
125          jtPlaylist.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
126          jtPlaylist.setSelectionMode( ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );
127          jtPlaylist.getSelectionModel().addListSelectionListener( this );
128          jtPlaylist.setTransferHandler( new EntryTransferHandler( fish ) );
129          jtPlaylist.setDragEnabled( true );
130          
131          jpRight.add( new JScrollPane( jtPlaylist ), BorderLayout.CENTER );
132          
133          jTools = new JToolBar( L.tr("pl.toolbar") );
134          jTools.setFloatable( false );
135          jTools.setRollover( true );
136          jpRight.add( jTools, BorderLayout.NORTH );
137        }
138        jSplit.setRightComponent( jpRight );
139        
140        //--- React on double clicks ---
141        jtPlaylist.addMouseListener( new MouseAdapter() {
142          @Override
143          public void mouseClicked( MouseEvent e ) {
144            if( e.getClickCount()==2 ) {
145              IFishAction action = PlaylistPane.this.fish.getAction( IFishPane.ACTION_PLAYER_PLAY );
146              if( action.isEnabled() ) {
147                action.perform();
148              }
149            }
150          }
151        });
152    
153        //--- Create actions ---
154        actionTop      = new MoveAction(   this, fish, L.tr("pl.action.top")    , ImgPool.get("pl_top.png")    , L.tr("pl.action.top.tt"), MoveAction.MODE_TOP );
155        actionUp       = new MoveAction(   this, fish, L.tr("pl.action.up")     , ImgPool.get("pl_up.png")     , L.tr("pl.action.up.tt"), MoveAction.MODE_UP );
156        actionDown     = new MoveAction(   this, fish, L.tr("pl.action.down")   , ImgPool.get("pl_down.png")   , L.tr("pl.action.down.tt"), MoveAction.MODE_DOWN );
157        actionBottom   = new MoveAction(   this, fish, L.tr("pl.action.bottom") , ImgPool.get("pl_bottom.png") , L.tr("pl.action.bottom.tt"), MoveAction.MODE_BOTTOM );
158        actionAsc      = new SortAction(   this, fish, L.tr("pl.action.asc")    , ImgPool.get("pl_asc.png")    , L.tr("pl.action.asc.tt"), SortAction.MODE_ASC );
159        actionDesc     = new SortAction(   this, fish, L.tr("pl.action.desc")   , ImgPool.get("pl_desc.png")   , L.tr("pl.action.desc.tt"), SortAction.MODE_DESC );
160        actionShuffle  = new SortAction(   this, fish, L.tr("pl.action.shuffle"), ImgPool.get("pl_shuffle.png"), L.tr("pl.action.shuffle.tt"), SortAction.MODE_SHUFFLE );
161        actionAll      = new AllAction(    this, fish, L.tr("pl.action.all")    , ImgPool.get("pl_all.png")    , L.tr("pl.action.all.tt") );
162        actionPaste    = new PasteAction(  this, fish, L.tr("pl.action.paste")  , ImgPool.get("pl_paste.png")  , L.tr("pl.action.paste.tt") );
163        actionRemove   = new RemoveAction( this, fish, L.tr("pl.action.remove") , ImgPool.get("pl_remove.png") , L.tr("pl.action.remove.tt") );
164        actionPLCreate = new CreateAction( this, fish, L.tr("pl.action.create") , ImgPool.get("pl_add.png")    , L.tr("pl.action.create.tt") );
165        actionPLRename = new RenameAction( this, fish, L.tr("pl.action.rename") , ImgPool.get("pl_rename.png") , L.tr("pl.action.rename.tt") );
166        actionPLDelete = new DeleteAction( this, fish, L.tr("pl.action.delete") , ImgPool.get("pl_remove.png") , L.tr("pl.action.delete.tt") );
167    
168        //--- Add buttons to Toolbar ---
169        jTools.add( new JToolbarButton( actionTop ) );
170        jTools.add( new JToolbarButton( actionUp ) );
171        jTools.add( new JToolbarButton( actionDown ) );
172        jTools.add( new JToolbarButton( actionBottom ) );
173        jTools.addSeparator();
174        jTools.add( new JToolbarButton( actionAsc ) );
175        jTools.add( new JToolbarButton( actionDesc ) );
176        jTools.add( new JToolbarButton( actionShuffle ) );
177        jTools.addSeparator();
178        jTools.add( new JToolbarButton( actionAll ) );
179        jTools.addSeparator();
180        jTools.add( new JToolbarButton( actionPaste ) );
181        jTools.add( new JToolbarButton( actionRemove ) );
182        
183        //--- Add buttons to Playlist Toolbar ---
184        jPLTools.add( jbCreate = new JToolbarButton( actionPLCreate ) );
185        jPLTools.add( jbRename = new JToolbarButton( actionPLRename ) );
186        jPLTools.add( new JToolbarButton( actionPLDelete ) );
187      }
188      
189      /**
190       * Set a playlist database. Its contents will be shown in the playlist
191       * list on the left.
192       * 
193       * @param   playlist      New PlaylistDb
194       */
195      public void setPlaylistDb( PlaylistDb playlist ) {
196        if( playlist!=null ) {
197          jlDirectory.setModel( playlist );
198          clearPlaylist();
199        }
200      }
201    
202      /**
203       * Internal ListSelectionListener implementation, do not use.
204       * 
205       * @param   e       ListSelectionEvent
206       */
207      @Override
208      public void valueChanged( ListSelectionEvent e ) {
209        Object src = e.getSource();
210        
211        if( src.equals( jlDirectory ) ) {
212          Playlist pl = (Playlist) jlDirectory.getSelectedValue();
213          if( pl!=null ) {
214            setPlaylist( pl );
215          }else {
216            clearPlaylist();
217          }
218        }
219    
220        fish.setPlaylistSource( this );
221      }
222      
223      /**
224       * Set a selected playlist, showing it in the contents table.
225       * 
226       * @param   pl    Playlist to be shown.
227       */
228      protected void setPlaylist( Playlist pl ) {
229        this.pl = pl;
230        jtPlaylist.setModel( new PlaylistTableModel( pl ) );
231        SwingUtils.spreadColumns( jtPlaylist, 300 );
232      }
233      
234      /**
235       * Clear the playlist contents, setting an empty list.
236       */
237      protected void clearPlaylist() {
238        setPlaylist( new Playlist("empty") );
239      }
240      
241      /**
242       * Get an array of all Entry to be played.
243       * 
244       * @return  Array of Entry, might be empty.
245       */
246      @Override
247      public Entry[] getSelectedEntries() {
248        int[] rows = jtPlaylist.getSelectedRows();
249        if( rows.length>=0 ) {
250          Entry[] result = new Entry[rows.length];
251          for( int ix=0; ix<rows.length; ix++ ) {
252            result[ix] = (Entry) pl.getElementAt( rows[ix] );
253          }
254          return result;
255        }else {
256          return new Entry[0];
257        }
258      }
259      
260      protected static boolean isValid( String name ) {
261        if( name==null || name.length()==0 || name.length()>50 ) return false;
262        for( int ix=0; ix<name.length(); ix++ ) {
263          char ch = name.charAt(ix);
264          if( ch=='\\' || ch=='/' || ch=='.' ) return false;
265          if( Character.isISOControl(ch) ) return false;
266        }
267        return true;
268      }
269      
270      
271    /*----------------------------------------------------------------------------*/
272      
273      public static class MoveAction extends IFishAction implements ListSelectionListener {
274        private static final long serialVersionUID = 3761968259188144435L;
275        public final static int MODE_TOP    = 0;
276        public final static int MODE_UP     = 1;
277        public final static int MODE_DOWN   = 2;
278        public final static int MODE_BOTTOM = 3;
279        private final static KeyStroke STROKES[] = new KeyStroke[] {
280          KeyStroke.getKeyStroke( KeyEvent.VK_NUMPAD9, 0 ),
281          KeyStroke.getKeyStroke( KeyEvent.VK_NUMPAD8, 0 ),
282          KeyStroke.getKeyStroke( KeyEvent.VK_NUMPAD2, 0 ),
283          KeyStroke.getKeyStroke( KeyEvent.VK_NUMPAD3, 0 ),
284        };
285        private final PlaylistPane pl;
286        private final int mode;
287        
288        public MoveAction( PlaylistPane pl, IFishPane fish, String name, Icon icon, String tip, int mode ) {
289          super( fish, name, icon, tip, STROKES[mode] );
290          this.pl = pl;
291          this.mode = mode;
292          pl.jtPlaylist.getSelectionModel().addListSelectionListener( this );
293          updateState();
294        }
295        
296        @Override
297        protected void action() {
298          int pos = pl.jtPlaylist.getSelectedRow();
299          Entry entry = (Entry) pl.pl.getElementAt( pos );
300          switch( mode ) {
301            case MODE_TOP:    pos=0;  break;
302            case MODE_UP:     pos--;  break;
303            case MODE_DOWN:   pos+=2; break;
304            case MODE_BOTTOM: pos=pl.pl.getSize(); break;
305          }
306          pl.pl.insertEntry( pos, entry );
307          fish.setUnsaved( true );
308          if( mode==MODE_DOWN || mode==MODE_BOTTOM )
309            pos--;
310          pl.jtPlaylist.setRowSelectionInterval( pos,pos );
311        }
312    
313        @Override
314        public void valueChanged( ListSelectionEvent e ) {
315          updateState();
316        }
317        
318        protected void updateState() {
319          //--- Exactly one row selected? ---
320          if( pl.jtPlaylist.getSelectedRowCount() != 1 ) {
321            setEnabled( false );
322            return;
323          }
324          
325          //--- Don't shift past the top ---
326          int row = pl.jtPlaylist.getSelectedRow();
327          if( row==0 && ( mode==MODE_TOP || mode==MODE_UP ) ) {
328            setEnabled( false );
329            return;
330          }
331          
332          //--- Don't shift past the bottom ---
333          if( row==pl.jtPlaylist.getRowCount()-1 && ( mode==MODE_BOTTOM || mode==MODE_DOWN ) ) {
334            setEnabled( false );
335            return;
336          }
337          
338          setEnabled( true );
339        }
340      }
341      
342    /*----------------------------------------------------------------------------*/
343      
344      public static class SortAction extends IFishAction implements ListSelectionListener {
345        private static final long serialVersionUID = 3257288023992777015L;
346        public final static int MODE_ASC     = 0;
347        public final static int MODE_DESC    = 1;
348        public final static int MODE_SHUFFLE = 2;
349        private final static KeyStroke STROKES[] = new KeyStroke[] {
350          KeyStroke.getKeyStroke( KeyEvent.VK_NUMPAD1, 0 ),
351          KeyStroke.getKeyStroke( KeyEvent.VK_NUMPAD7, 0 ),
352          KeyStroke.getKeyStroke( KeyEvent.VK_NUMPAD4, 0 ),
353        };
354        private final PlaylistPane pl;
355        private final int mode;
356        
357        public SortAction( PlaylistPane pl, IFishPane fish, String name, Icon icon, String tip, int mode ) {
358          super( fish, name, icon, tip, STROKES[mode] );
359          this.pl = pl;
360          this.mode = mode;
361          pl.jtPlaylist.getSelectionModel().addListSelectionListener( this );
362          updateState();
363        }
364        
365        @Override
366        protected void action() {
367          int[] rows = pl.jtPlaylist.getSelectedRows();
368          if( mode!=MODE_SHUFFLE ) {
369            pl.pl.sort( rows[0], rows[rows.length-1]+1, (mode==MODE_DESC) );
370          }else {
371            pl.pl.shuffle( rows[0], rows[rows.length-1]+1 );
372          }
373          fish.setUnsaved( true );
374        }
375    
376        @Override
377        public void valueChanged( ListSelectionEvent e ) {
378          updateState();
379        }
380        
381        protected void updateState() {
382          int[] rows = pl.jtPlaylist.getSelectedRows();
383          
384          //--- At least one entry selected? ---
385          if( rows.length<=1 ) {
386            setEnabled(false);
387            return;
388          }
389          
390          //--- Continuous selection? ---
391          int start = rows[0];
392          for( int ix=1; ix<rows.length; ix++ ) {
393            start++;
394            if( start!=rows[ix] ) {
395              setEnabled(false);
396              return;
397            }
398          }
399    
400          //--- Then sorting is allowed ---
401          setEnabled(true);
402        }
403      }
404      
405    /*----------------------------------------------------------------------------*/
406    
407      public static class AllAction extends IFishAction {
408        private static final long serialVersionUID = 3978426940145414455L;
409        private final PlaylistPane pl;
410        
411        public AllAction( PlaylistPane pl, IFishPane fish, String name, Icon icon, String tip ) {
412          super( fish, name, icon, tip, KeyStroke.getKeyStroke( KeyEvent.VK_A, ActionEvent.CTRL_MASK ) );
413          this.pl = pl;
414        }
415        
416        @Override
417        protected void action() {
418          pl.jtPlaylist.selectAll();
419        }
420      }
421    
422    /*----------------------------------------------------------------------------*/
423    
424      public static class PasteAction extends IFishAction implements ListSelectionListener {
425        private static final long serialVersionUID = 3256723974544306227L;
426        private final PlaylistPane pl;
427        
428        public PasteAction( PlaylistPane pl, IFishPane fish, String name, Icon icon, String tip ) {
429          super( fish, name, icon, tip, KeyStroke.getKeyStroke( KeyEvent.VK_V, ActionEvent.CTRL_MASK ) );
430          this.pl = pl;
431          pl.jlDirectory.getSelectionModel().addListSelectionListener( this );
432          updateState();
433        }
434        
435        @Override
436        protected void action() {
437          Playlist selection = (Playlist) pl.jlDirectory.getSelectedValue();
438          if( selection!=null && selection.isStatic() ) {
439            Entry[] entries = fish.getSelectedDatabaseEntries();
440            if( entries.length>0 ) {
441              for( int ix=0; ix<entries.length; ix++ ) {
442                Entry entry = entries[ix];
443                if(! selection.contains(entry) ) {
444                  selection.addEntry( entry );
445                }
446              }
447              fish.setUnsaved( true );
448              SwingUtils.spreadColumns( pl.jtPlaylist, 300 );
449            }
450          }
451        }
452    
453        @Override
454        public void valueChanged( ListSelectionEvent e ) {
455          updateState();
456        }
457        
458        protected void updateState() {
459          Playlist selection = (Playlist) pl.jlDirectory.getSelectedValue();
460          if( selection!=null && selection.isStatic() ) {
461            setEnabled( true );
462            return;
463          }
464          setEnabled( false );
465        }
466      }
467    
468    /*----------------------------------------------------------------------------*/
469    
470      public static class RemoveAction extends IFishAction implements ListSelectionListener {
471        private static final long serialVersionUID = 3257003276250984498L;
472        private final PlaylistPane pl;
473        
474        public RemoveAction( PlaylistPane pl, IFishPane fish, String name, Icon icon, String tip ) {
475          super( fish, name, icon, tip, KeyStroke.getKeyStroke( KeyEvent.VK_DELETE, 0 ) );
476          this.pl = pl;
477          pl.jlDirectory.getSelectionModel().addListSelectionListener( this );
478          pl.jtPlaylist.getSelectionModel().addListSelectionListener( this );
479          updateState();
480        }
481        
482        @Override
483        protected void action() {
484          Playlist selection = (Playlist) pl.jlDirectory.getSelectedValue();
485          if( selection!=null && selection.isStatic() ) {
486            int[] rows = pl.jtPlaylist.getSelectedRows();
487            for( int ix=rows.length-1; ix>=0; ix-- ) {
488              Entry entry = (Entry) pl.pl.getElementAt( rows[ix] );
489              pl.pl.removeEntry( entry );
490            }
491            fish.setUnsaved( true );
492          }
493        }
494    
495        @Override
496        public void valueChanged( ListSelectionEvent e ) {
497          updateState();
498        }
499        
500        protected void updateState() {
501          Playlist selection = (Playlist) pl.jlDirectory.getSelectedValue();
502          if( selection!=null && selection.isStatic() ) {
503            if( pl.jtPlaylist.getSelectedRowCount() > 0 ) {
504              setEnabled( true );
505              return;
506            }
507          }
508          setEnabled( false );
509        }
510      }
511    
512    /*----------------------------------------------------------------------------*/
513    
514      public static class CreateAction extends IFishAction {
515        private static final long serialVersionUID = 3256720671680771892L;
516        private final PlaylistPane pl;
517        
518        public CreateAction( PlaylistPane pl, IFishPane fish, String name, Icon icon, String tip ) {
519          super( fish, name, icon, tip, KeyStroke.getKeyStroke( KeyEvent.VK_N, ActionEvent.CTRL_MASK ) );
520          this.pl = pl;
521        }
522        
523        @Override
524        protected void action() {
525          String name = JOptionPane.showInputDialog( 
526              pl.jbCreate,
527              L.tr("pl.create.name"),
528              L.tr("pl.create.title"),
529              JOptionPane.QUESTION_MESSAGE
530          );
531          if( name!=null && isValid(name) ) {
532            PlaylistDb pldb = fish.getPlaylist();
533            boolean contained = pldb.containsPlaylist( name );
534            Playlist newPL = fish.getPlaylist().getPlaylist( name );
535            if( !contained ) {
536              newPL.setStatic( true );
537              newPL.setCustomer( true );
538              fish.setUnsaved( true );
539            }
540            pl.jlDirectory.setSelectedValue( newPL, true );
541          }
542        }
543      }
544    
545    /*----------------------------------------------------------------------------*/
546    
547      public static class RenameAction extends IFishAction implements ListSelectionListener {
548        private static final long serialVersionUID = 3257847692691845175L;
549        private final PlaylistPane pl;
550        
551        public RenameAction( PlaylistPane pl, IFishPane fish, String name, Icon icon, String tip ) {
552          super( fish, name, icon, tip, KeyStroke.getKeyStroke( KeyEvent.VK_F2, 0 ) );
553          this.pl = pl;
554          pl.jlDirectory.getSelectionModel().addListSelectionListener( this );
555          updateState();
556        }
557        
558        @Override
559        protected void action() {
560          Playlist selection = (Playlist) pl.jlDirectory.getSelectedValue();
561          if( selection!=null ) {
562            if( selection.isStatic() ) {
563              Object input = JOptionPane.showInputDialog( 
564                  pl.jbRename,
565                  L.tr("pl.rename.name"),
566                  L.tr("pl.rename.title"),
567                  JOptionPane.QUESTION_MESSAGE,
568                  null,
569                  null,
570                  selection.getName()
571              );
572              if( input!=null ) {
573                String name = input.toString();
574                if( isValid(name) && !name.equals( selection.getName() ) ) {
575                  PlaylistDb model = (PlaylistDb) pl.jlDirectory.getModel();
576                  if(! model.containsPlaylist( name ) ) {
577                    model.renamePlaylist( selection, name );
578                    pl.clearPlaylist();
579                    pl.jlDirectory.setSelectedValue( selection, true );
580                    fish.setUnsaved( true );
581                  }else {
582                    JOptionPane.showMessageDialog(
583                        pl.jbRename,
584                        L.tr("pl.rename.exists"),
585                        L.tr("pl.rename.title"),
586                        JOptionPane.ERROR_MESSAGE
587                    );
588                  }
589                }
590              }
591            }
592          }
593        }
594    
595        @Override
596        public void valueChanged( ListSelectionEvent e ) {
597          updateState();
598        }
599        
600        protected void updateState() {
601          Playlist selection = (Playlist) pl.jlDirectory.getSelectedValue();
602          if( selection!=null ) {
603            if( selection.isStatic() ) {
604              setEnabled( true );
605              return;
606            }
607          }
608          setEnabled( false );
609        }
610      }
611    
612    /*----------------------------------------------------------------------------*/
613    
614      public static class DeleteAction extends IFishAction implements ListSelectionListener {
615        private static final long serialVersionUID = 3257004358649722418L;
616        private final PlaylistPane pl;
617        
618        public DeleteAction( PlaylistPane pl, IFishPane fish, String name, Icon icon, String tip ) {
619          super( fish, name, icon, tip, KeyStroke.getKeyStroke( KeyEvent.VK_DELETE, ActionEvent.SHIFT_MASK ) );
620          this.pl = pl;
621          pl.jlDirectory.getSelectionModel().addListSelectionListener( this );
622          updateState();
623        }
624        
625        @Override
626        protected void action() {
627          Playlist selection = (Playlist) pl.jlDirectory.getSelectedValue();
628          if( selection!=null ) {
629            if( selection.isStatic() ) {
630              PlaylistDb model = (PlaylistDb) pl.jlDirectory.getModel();
631              model.removePlaylist( selection );
632              pl.clearPlaylist();
633              fish.setUnsaved( true );
634            }
635          }
636        }
637    
638        @Override
639        public void valueChanged( ListSelectionEvent e ) {
640          updateState();
641        }
642        
643        protected void updateState() {
644          Playlist selection = (Playlist) pl.jlDirectory.getSelectedValue();
645          if( selection!=null ) {
646            if( selection.isStatic() ) {
647              setEnabled( true );
648              return;
649            }
650          }
651          setEnabled( false );
652        }
653      }
654    
655    }