Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/fm/gui/fmFrame.java


1   /****************************************************************************
2    * Copyright (c) 2003 Andrew Duka | aduka@users.sourceforge.net
3    * All right reserved.
4    *
5    * This program is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU Lesser General Public
7    * License as published by the Free Software Foundation; either
8    * version 2.1 of the License, or (at your option) any later version.
9    *
10   ****************************************************************************/
11  package com.fm.gui;
12  
13  import javax.swing.event.TreeSelectionListener;
14  import javax.swing.event.TreeSelectionEvent;
15  import javax.swing.event.HyperlinkListener;
16  import javax.swing.event.HyperlinkEvent;
17  import javax.swing.tree.*;
18  import javax.swing.*;
19  import java.util.*;
20  import java.util.regex.Pattern;
21  import java.awt.*;
22  import java.awt.event.*;
23  import java.io.*;
24  
25  import com.fm.rss.*;
26  import com.fm.rss.rssParseException;
27  import com.fm.update.Updateable;
28  import com.fm.update.updateException;
29  import com.fm.update.updateFactory;
30  import com.fm.gui.action.*;
31  
32  
33  /**
34   * Manin frame in the JNR GUI version
35   */
36  public class fmFrame extends JFrame implements ActionListener
37  {
38      /** Content displaying panel */
39      private fmContentPanel  contentPane;
40  
41      /** Panel with search form  */
42      private JPanel          searchPanel;
43  
44      /** Category tree (left side) */
45      private fmCategoryTree  categoryTree;
46  
47      /** Default channel storage   */
48      private ChannelStorage  storage;
49  
50      private JPopupMenu      popupMenu;
51      private JToolBar        toolBar;
52  
53      /** Runtime properties store in the fm.ini */
54      private Properties      runtimeProperties;
55  
56      /** Hyperlink router (used within content panel to handle URL events */
57      private fmHyperlinkRouter linkRouter;
58  
59      //default channel storage
60  
61  
62      public fmFrame(ChannelStorage st, Properties props)
63      {
64          super();
65  
66          runtimeProperties = props;
67          storage = st;
68  
69          // Some prior UI initialization
70          try
71          {
72              setupLookAndFeelDefaults(runtimeProperties);
73              fmUITheme.initFeedManLookAndFeel();
74          }
75          catch (IOException e)
76          {
77              JOptionPane.showMessageDialog(null,"Program was unable to find or open default resource bundle,"+
78                                                 "please close and try again or report error to aduka@users.sourceforge.net",
79                                                 "Fatal error: ",
80                                                  JOptionPane.ERROR_MESSAGE);
81              System.exit(0);
82          }
83  
84  
85          setTitle("feedMan");
86  
87          this.initFmFrame();
88      }
89  
90      public void initFmFrame()
91      {
92          this.getContentPane().removeAll();
93  
94          // SETTING UP ICON
95          this.setIconImage((fmUITheme.FM_ICON).getImage());
96  
97          ///////////////////////////////////////////////////////////////////////
98          // SEARCH PANEL
99          JPanel searchCatPanel = new JPanel(new BorderLayout());
100 
101         searchPanel = new JPanel();
102         searchPanel.setBackground(fmUITheme.LIGHT_BACKGROUND_COLOR);
103         final JTextField patternInput = new JTextField(12);
104         patternInput.setBorder(fmUITheme.FM_BUTTON_BORDER);
105         searchPanel.add(patternInput);
106         patternInput.addKeyListener(new KeyAdapter() {
107             public void keyPressed(KeyEvent e) {
108                 if (e.getKeyCode() == KeyEvent.VK_ENTER)
109                     performSearchOperation(patternInput.getText());
110             }
111         });
112 
113         ///////////////////////////////////////////////////////////////////////
114         // FIND button on search panel
115         JButton activateSearch = new JButton(fmUITheme.getString("button.find.label"));
116 
117         activateSearch.addActionListener(new ActionListener() {
118             public void actionPerformed(ActionEvent e) {
119                 performSearchOperation(patternInput.getText());
120             }
121 
122         });
123 
124         activateSearch.setToolTipText(fmUITheme.getString("button.find.tooltip"));
125         searchPanel.add(activateSearch);
126         searchPanel.setPreferredSize(new Dimension(230,35));
127         searchCatPanel.add(searchPanel, BorderLayout.SOUTH);
128 
129         ///////////////////////////////////////////////////////////////////////
130         // CATEGORY TREE
131         categoryTree = fmCategoryTree.getInstance(storage.getCategories(), true);
132         categoryTree.setBackground(fmUITheme.TREE_BACKGROUND_COLOR);
133         JScrollPane treeView = new JScrollPane(categoryTree);
134         searchCatPanel.add(treeView, BorderLayout.CENTER);
135 
136         //Listen for when the selection changes.
137         categoryTree.addTreeSelectionListener(new TreeSelectionListener() {
138             public void valueChanged(TreeSelectionEvent e) {
139                 TreePath p = categoryTree.getSelectionPath();
140 
141                 if (p == null)
142                     return;
143 
144                 fmTreeNode node = (fmTreeNode) p.getLastPathComponent();
145                 if (node == null) {
146                     return;
147                 }
148                 // we normally will never meet a string (root node)
149                 if (node.isCategory() == false)
150                 {
151                     contentPane.setChannel((rssChannel)node.getUserObject());
152                 }
153             }
154         });
155 
156         categoryTree.addMouseListener(new treeMouseListener());
157 
158 
159         ///////////////////////////////////////////////////////
160         // HYPERLINK ROUTER
161         if (runtimeProperties.containsKey(fmGuiConstants.URL_HANDLING_CMD))
162         {
163             String cmd = runtimeProperties.getProperty(fmGuiConstants.URL_HANDLING_CMD);
164 
165             if (cmd.equals(fmGuiConstants.INTERNAL_URL_HANDLER))
166                 linkRouter = new fmHyperlinkRouter(null);
167             else {
168 
169                 if (cmd.equals(fmGuiConstants.WIN32_URL_HANDLER)) {
170                     // CHECKING THAT WE HAVE WINDOWS HANDLE ONLY ON WINDOWS MACHINES
171                     String os = System.getProperty("os.name");
172                     if(os == null || ((os.startsWith("Windows") == false))) {
173                         cmd = fmGuiConstants.INTERNAL_URL_HANDLER;
174                         runtimeProperties.put(fmGuiConstants.URL_HANDLING_CMD,
175                                               fmGuiConstants.INTERNAL_URL_HANDLER);
176                     }
177                 }
178 
179                 linkRouter = new fmHyperlinkRouter(cmd);
180             }
181         }
182         else // NOT SET OR FIRST RUN
183         {
184             String os = System.getProperty("os.name");
185             if(os != null && os.startsWith("Windows")) {
186                 // Setting default windows handler
187                 runtimeProperties.put(fmGuiConstants.URL_HANDLING_CMD,
188                         fmGuiConstants.WIN32_URL_HANDLER);
189                 linkRouter = new fmHyperlinkRouter(fmGuiConstants.WIN32_URL_HANDLER);
190             }
191             else {
192                 runtimeProperties.put(fmGuiConstants.URL_HANDLING_CMD,
193                                       fmGuiConstants.INTERNAL_URL_HANDLER);
194                 linkRouter = new fmHyperlinkRouter(null);
195             }
196         }
197 
198         // INTERNAL CHANNEL NAVIGATION HANDLER
199         // Enabling handler for internal navigation
200         linkRouter.setPrefixHandler("http://channel/", new HyperlinkListener() {
201             public void hyperlinkUpdate(HyperlinkEvent e) {
202                 int channelId = Integer.parseInt(e.getURL().toString().replaceFirst("http://channel/",""));
203                 fmTreeNode tNode = categoryTree.findChannelNode(categoryTree.getRootNode(),
204                                                                 channelId);
205                 if (tNode != null) {
206                     contentPane.setChannel((rssChannel) tNode.getUserObject());
207                 }
208             }
209         });
210 
211 
212 
213         ///////////////////////////////////////////////////////
214         // CONTENT VIEW PANEL
215         contentPane = new fmContentPanel(runtimeProperties, linkRouter, categoryTree);
216 
217 
218         //Add the scroll panes to a split pane.
219         JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
220         splitPane.setLeftComponent(searchCatPanel);
221         splitPane.setRightComponent(contentPane);
222 
223         Dimension minimumSize = new Dimension(200, 300);
224         treeView.setMinimumSize(minimumSize);
225         splitPane.setDividerLocation(200);
226 
227         splitPane.setPreferredSize(new Dimension(600, 400));
228         splitPane.setOneTouchExpandable(true);
229 
230 
231         //////////////////////////////////////////////////////////////////////
232         // REFRESH FACTORY
233         Vector refreshListeners = new Vector();
234         refreshListeners.addElement(this);
235         refreshListeners.addElement(categoryTree);
236         refreshListeners.addElement(contentPane);
237 
238         updateFactory updater = new updateFactory(refreshListeners);
239         registerChannelsToUpdater(updater, categoryTree.getCategories());
240         updater.start();
241 
242 
243 
244 
245 
246         //////////////////////////////////////////////////////////////////////
247         // TOOLBAR
248         //////////////////////////////////////////////////////////////////////
249         toolBar = new JToolBar("Standard FM toolbar");
250 
251         //  New channel button
252         JButton toolbarButton = new JButton(new createChannelAction(this,
253                                                                     fmUITheme.NEW_CHANNEL_ICON,
254                                                                     categoryTree.getModel()));
255         toolbarButton.setMargin(fmUITheme.TOOLBAR_BUTTON_MARGIN);
256         toolBar.add("Create feed", toolbarButton);
257 
258         //  Save button
259         toolbarButton = new JButton(fmUITheme.SAVE_STORAGE_ICON);
260         toolbarButton.setActionCommand("Save");
261         toolbarButton.addActionListener(this);
262         toolbarButton.setToolTipText(fmUITheme.getString("button.save.tooltip"));
263         toolbarButton.setMargin(fmUITheme.TOOLBAR_BUTTON_MARGIN);
264         toolBar.add("Save storage", toolbarButton);
265 
266         // Settings button
267 
268         toolbarButton = new JButton(new customizeSettingsAction(this,
269                                                                 fmUITheme.SETTINGS_ICON,
270                                                                 runtimeProperties));
271         //toolbarButton.setIcon(fmUITheme.SETTINGS_ICON);
272         toolbarButton.setMargin(fmUITheme.TOOLBAR_BUTTON_MARGIN);
273         toolBar.add(toolbarButton);
274 
275         // Refresh button
276         toolbarButton = new JButton(new refreshAction(categoryTree,
277                                                       fmUITheme.REFRESH_ICON,
278                                                       updater));
279         toolbarButton.setMargin(fmUITheme.TOOLBAR_BUTTON_MARGIN);
280         toolBar.add("refresh", toolbarButton);
281 
282         // Stopn refresh button
283         toolbarButton = new JButton(new stopRefreshAction(categoryTree,
284                                                           fmUITheme.STOP_ICON,
285                                                           updater));
286         toolbarButton.setMargin(fmUITheme.TOOLBAR_BUTTON_MARGIN);
287         toolBar.add("stop", toolbarButton);
288 
289 
290         //Add the split pane and toolbar to the content
291         this.getContentPane().add(splitPane, BorderLayout.CENTER);
292         this.getContentPane().add(toolBar, BorderLayout.NORTH);
293 
294 
295 
296 
297         // SETTING UP MENU BAR
298         JMenuBar menuBar = new JMenuBar();
299         popupMenu = new JPopupMenu("fM popup menu");
300         //this.getContentPane().add(popupMenu);
301 
302         setJMenuBar(menuBar);
303 
304         JMenu editMenu = new JMenu(fmUITheme.getString("menu.edit"));
305         editMenu.setMnemonic(KeyEvent.VK_E);
306 
307         JMenu optionsMenu = new JMenu(fmUITheme.getString("menu.options"));
308         optionsMenu.setMnemonic(KeyEvent.VK_O);
309 
310         JMenu navigationMenu = new JMenu(fmUITheme.getString("menu.navigation"));
311         navigationMenu.setMnemonic(KeyEvent.VK_N);
312 
313         JMenu helpMenu = new JMenu(fmUITheme.getString("menu.help"));
314         helpMenu.setMnemonic(KeyEvent.VK_H);
315         helpMenu.setEnabled(false);
316 
317         // FILE MENU
318         JMenu fileMenu    = new JMenu(fmUITheme.getString("menu.file"));
319         fileMenu.setMnemonic(KeyEvent.VK_F);
320 
321         // NEW objects
322         JMenu newMenu = new JMenu("New");
323         newMenu.setMnemonic(KeyEvent.VK_N);
324 
325         JMenuItem menuItem;
326         // new feed
327         Action newChAction = new createChannelAction(this, categoryTree.getModel());
328         newMenu.add(new JMenuItem(newChAction));
329         popupMenu.add(new JMenuItem(newChAction));
330 
331         // new category
332         Action newCatAction = new createCategoryAction(categoryTree);
333         newMenu.add(new JMenuItem(newCatAction));
334         popupMenu.add(new JMenuItem(newCatAction));
335         popupMenu.addSeparator();
336 
337         fileMenu.add(newMenu);
338         fileMenu.addSeparator();
339 
340         // LOAD ITEMS
341         menuItem = new JMenuItem(fmUITheme.getString("menu.load"));
342         menuItem.setActionCommand("Load");
343         menuItem.setAccelerator(KeyStroke.getKeyStroke(
344                                            KeyEvent.VK_O, ActionEvent.CTRL_MASK));
345         menuItem.addActionListener(this);
346         fileMenu.add(menuItem);
347 
348 
349         // SAVE ITEMS
350         menuItem = new JMenuItem(fmUITheme.getString("menu.save"));
351         menuItem.setActionCommand("Save");
352         menuItem.setAccelerator(KeyStroke.getKeyStroke(
353                                            KeyEvent.VK_S, ActionEvent.CTRL_MASK));
354         menuItem.addActionListener(this);
355         fileMenu.add(menuItem);
356 
357 
358         menuItem = new JMenuItem(fmUITheme.getString("menu.save_as"));
359         menuItem.setActionCommand("Save as");
360         menuItem.setAccelerator(KeyStroke.getKeyStroke(
361                                            KeyEvent.VK_S, ActionEvent.CTRL_MASK | ActionEvent.SHIFT_MASK));
362         menuItem.addActionListener(this);
363         fileMenu.add(menuItem);
364 
365         fileMenu.addSeparator();
366 
367         // Exit ITEM
368         JMenuItem exitItem  = new JMenuItem(fmUITheme.getString("menu.exit"));
369         exitItem.setActionCommand("Exit");
370         exitItem.setAccelerator(KeyStroke.getKeyStroke(
371                                 KeyEvent.VK_X, ActionEvent.CTRL_MASK));
372         exitItem.addActionListener(this);
373         fileMenu.add(exitItem);
374 
375 
376         //////////////////////////////////////////////////////////////////////////
377         // EDIT MENU
378 
379         //
380         Vector editListeners = new Vector();
381         editListeners.add(categoryTree);
382         editListeners.add(this);
383         editListeners.add(contentPane);
384         editListeners.add(updater);
385 
386         // EDIT
387         menuItem = new JMenuItem(new editAction(categoryTree, editListeners));
388         editMenu.add(menuItem);
389         popupMenu.add(new editAction(categoryTree, editListeners));
390 
391         // REMOVE
392         menuItem = new JMenuItem(new removeAction(categoryTree));
393         editMenu.add(menuItem);
394         editMenu.addSeparator();
395         popupMenu.add(new removeAction(categoryTree));
396         popupMenu.addSeparator();
397 
398         // UPDATE
399         editMenu.add(new JMenuItem(new refreshAction(categoryTree, updater)));
400         popupMenu.add(new JMenuItem(new refreshAction(categoryTree, updater)));
401 
402         // STOP UPDATE
403         editMenu.add(new JMenuItem(new stopRefreshAction(categoryTree, updater)));
404         popupMenu.add(new JMenuItem(new stopRefreshAction(categoryTree, updater)));
405 
406         editMenu.addSeparator();
407         editMenu.add(new JMenuItem(new purgeAllAction(categoryTree)));
408 
409 
410 
411         //NAVIGATION
412 
413         // GO BACK
414         menuItem = new JMenuItem(fmUITheme.getString("menu.show_previous"));
415         menuItem.setAccelerator(KeyStroke.getKeyStroke(
416                             KeyEvent.VK_LEFT, ActionEvent.ALT_MASK));
417         menuItem.addActionListener(new ActionListener() {
418             public void actionPerformed(ActionEvent e) {
419                 contentPane.showPreviousChannel();
420             }
421         });
422         navigationMenu.add(menuItem);
423 
424         // GO FORWARD
425         menuItem = new JMenuItem(fmUITheme.getString("menu.show_next"));
426         menuItem.setAccelerator(KeyStroke.getKeyStroke(
427                             KeyEvent.VK_RIGHT, ActionEvent.ALT_MASK));
428         menuItem.addActionListener(new ActionListener() {
429             public void actionPerformed(ActionEvent e) {
430                 contentPane.showNextChannel();
431             }
432         });
433         navigationMenu.add(menuItem);
434         navigationMenu.addSeparator();
435 
436         // SHOW PREVIOUS ITEM
437         menuItem = new JMenuItem(fmUITheme.getString("menu.show_previous_item"));
438         menuItem.setAccelerator(KeyStroke.getKeyStroke(
439                             KeyEvent.VK_UP, ActionEvent.ALT_MASK));
440         menuItem.addActionListener(new ActionListener() {
441             public void actionPerformed(ActionEvent e) {
442                 contentPane.showPreviousItem();
443             }
444         });
445         navigationMenu.add(menuItem);
446 
447         // SHOW NEXT ITEM
448         menuItem = new JMenuItem(fmUITheme.getString("menu.show_next_item"));
449         menuItem.setAccelerator(KeyStroke.getKeyStroke(
450                             KeyEvent.VK_DOWN, ActionEvent.ALT_MASK));
451         menuItem.addActionListener(new ActionListener() {
452             public void actionPerformed(ActionEvent e) {
453                 contentPane.showNextItem();
454             }
455         });
456         navigationMenu.add(menuItem);
457         navigationMenu.addSeparator();
458 
459         // open LINK menu item
460         openLinkAction openLinkAct = new openLinkAction(contentPane);
461         navigationMenu.add(new JMenuItem(openLinkAct));
462 
463 
464         // OPTIONS MENU
465 
466         // AUTO SAVE ON EXIT
467         boolean autosave;
468         if (runtimeProperties.containsKey(fmGuiConstants.AUTOSAVE_ON_EXIT))
469         {
470             autosave = (runtimeProperties.getProperty(fmGuiConstants.AUTOSAVE_ON_EXIT).equals("T")) ?
471                         true : false;
472         }
473         else
474         {
475             runtimeProperties.put(fmGuiConstants.AUTOSAVE_ON_EXIT, "T");
476             autosave = true;
477         }
478 
479         JCheckBoxMenuItem cbItem = new JCheckBoxMenuItem(fmUITheme.getString("menu.autosave"),
480                                                          autosave);
481         cbItem.addItemListener(new ItemListener() {
482 
483             public void itemStateChanged(ItemEvent e)
484             {
485                 if (((JCheckBoxMenuItem)e.getSource()).isSelected() == false)
486                     runtimeProperties.put(fmGuiConstants.AUTOSAVE_ON_EXIT, "F");
487                 else
488                     runtimeProperties.put(fmGuiConstants.AUTOSAVE_ON_EXIT, "T");
489             }
490         });
491         optionsMenu.add(cbItem);
492 
493         // Show/hide toolbar
494         cbItem = new JCheckBoxMenuItem(fmUITheme.getString("menu.show_toolbar"), true);
495         cbItem.addItemListener(new ItemListener() {
496 
497             public void itemStateChanged(ItemEvent e)
498             {
499                 if (((JCheckBoxMenuItem)e.getSource()).isSelected() == false)
500                     toolBar.setVisible(false);
501                 else
502                     toolBar.setVisible(true);
503             }
504 
505         });
506         cbItem.setAccelerator(KeyStroke.getKeyStroke(
507                                    KeyEvent.VK_T, ActionEvent.CTRL_MASK | ActionEvent.ALT_MASK));
508         optionsMenu.add(cbItem);
509         optionsMenu.addSeparator();
510 
511 
512         JMenuItem customizeItem = new JMenuItem(new customizeSettingsAction(this, runtimeProperties));
513         optionsMenu.add(customizeItem);
514 
515         //////////////////////////////////
516         // MENU FINISH
517         menuBar.add(fileMenu);
518         menuBar.add(editMenu);
519         menuBar.add(navigationMenu);
520         menuBar.add(optionsMenu);
521         menuBar.add(helpMenu);
522 
523         /////////////////////////////////////////////////////////////////
524         // LOOKING FOR THE LAST OPENED CHANNEL AND DISPLAYING IT IF FOUND
525         if (runtimeProperties.containsKey(fmGuiConstants.LAST_OPEN_CHANNEL_ID))
526         {
527             int last_ch_id = Integer.parseInt(runtimeProperties.getProperty(fmGuiConstants.LAST_OPEN_CHANNEL_ID));
528 
529             fmTreeNode tNode = categoryTree.findChannelNode(categoryTree.getRootNode(),last_ch_id);
530             if (tNode != null) {
531                 ((DefaultTreeModel) categoryTree.getModel()).reload(tNode);
532                 categoryTree.setSelectionPath(new TreePath(tNode.getPath()));
533             }
534         }
535 
536         // DEFAULT WINDOW ADAPTER
537         addWindowListener(new WindowAdapter() {
538             public void windowClosing(WindowEvent e)
539             {
540                 onClose();
541             }
542         });
543 
544     }
545 
546     /**
547      * Overrides <code>pack()</code>
548      */
549     public void pack()
550     {
551          //
552 
553         // RESTORING WINDOW SETTINGS FROM RUNTIME PROPERTIES
554         if (runtimeProperties.containsKey("window.x") &&
555             runtimeProperties.containsKey("window.y") &&
556             runtimeProperties.containsKey("window.width") &&
557             runtimeProperties.containsKey("window.height"))
558         {
559             try
560             {
561                 this.setSize(Integer.parseInt(runtimeProperties.getProperty("window.width")),
562                                  Integer.parseInt(runtimeProperties.getProperty("window.height")));
563                 this.setLocation(Integer.parseInt(runtimeProperties.getProperty("window.x")),
564                                  Integer.parseInt(runtimeProperties.getProperty("window.y")));
565 
566             }
567             catch (NumberFormatException ne)
568             {
569                 super.pack();
570             }
571         }
572         else
573         {
574             super.pack();
575         }
576 
577 
578 
579     }
580 
581     /**
582      * Action event hanlder.
583      *
584      * Handled events: Load feeds,Save feeds, Save as feeds
585      *
586      * @param e
587      */
588     public void actionPerformed(ActionEvent e)
589     {
590         String actionCommand = e.getActionCommand();
591 
592         if (actionCommand.equalsIgnoreCase("Load")) // LOAD FEEDS FROM FILE
593         {
594             JFileChooser fc;
595 
596             // restoring previously opened directory
597             String prev_path = runtimeProperties.getProperty(fmGuiConstants.LAST_OPEN_DIRECTORY);
598             if (prev_path != null)
599                 fc = new JFileChooser(prev_path);
600             else
601                 fc = new JFileChooser();
602 
603             int returnVal = fc.showOpenDialog(this);
604 
605             if (returnVal == JFileChooser.APPROVE_OPTION)
606             {
607                 File file = fc.getSelectedFile();
608                 String srcPath = file.getPath();
609                 storage.setParamValue(ChannelStorage.SOURCE,srcPath);
610 
611                 try
612                 {
613                     storage.load();
614                     runtimeProperties.setProperty(fmGuiConstants.LAST_OPEN_DIRECTORY,
615                                                   file.getPath());
616                 }
617                 catch (IOException ie)
618                 {
619                     ie.printStackTrace();
620                     return;
621                 }
622                 catch (rssParseException pe)
623                 {
624                     pe.printStackTrace();
625                     return;
626                 }
627 
628                 this.categoryTree.regenerateTree(this.storage.getCategories());
629             }
630 
631         }
632         else if (actionCommand.equalsIgnoreCase("Save"))    // SAVE
633         {
634             saveStorage((String)storage.getParamValue(ChannelStorage.SOURCE)); // SAVE TO CURRENT FILE
635         }
636         else if (actionCommand.equalsIgnoreCase("Save as")) // SAVE FEEDS AS...
637         {
638             saveStorage(""); // will open choose file dialog
639         }
640         else if (actionCommand.equalsIgnoreCase("Refresh"))  // REFRESH
641         {
642             fmTreeNode node = (fmTreeNode)categoryTree.getLastSelectedPathComponent();
643             if (node == null) return;
644 
645             // we normally will never meet a string (root node)
646             try
647             {
648                 ((Updateable)node.getUserObject()).update();
649                 contentPane.setChannel((rssChannel)node.getUserObject());
650             }
651             catch (updateException ue)
652             {
653                 ue.printStackTrace();
654                 System.out.println("Update exception: " + e.toString());
655             }
656         }
657         else if (actionCommand.equalsIgnoreCase("Exit")) // Exit operation
658         {
659              onClose();
660         }
661 
662     }
663 
664 
665 
666     private class treeMouseListener extends MouseAdapter {
667 
668         public void mousePressed(MouseEvent e) {
669             displayPopupMenu(e);
670         }
671 
672         public void mouseReleased(MouseEvent e) {
673             displayPopupMenu(e);
674         }
675 
676         private void displayPopupMenu(MouseEvent e) {
677 
678             if (e.isPopupTrigger()) {
679                 popupMenu.show(e.getComponent(),
680                                e.getX(), e.getY());
681             }
682         }
683 
684     }
685 
686 
687     /**
688      * Save storage to file specified by path.
689      *
690      * If string identifying path is zero length the 'Choose file' dialog
691      * will appear.
692      *
693      * @param path
694      */
695     private void saveStorage(String path)
696     {
697         if (path.length() == 0)
698         {
699             // restoring previously opened directory for save operation
700             JFileChooser fc;
701             String prev_path = runtimeProperties.getProperty(fmGuiConstants.LAST_SAVE_DIRECTORY);
702 
703             if (prev_path != null)
704                 fc = new JFileChooser(prev_path);
705             else
706                 fc = new JFileChooser();
707 
708 
709             int returnVal = fc.showSaveDialog(this);
710 
711             if (returnVal == JFileChooser.APPROVE_OPTION)
712             {
713                 storage.setParamValue(ChannelStorage.DESTINATION,
714                                       fc.getSelectedFile().getPath());
715 
716                 runtimeProperties.setProperty(fmGuiConstants.LAST_SAVE_DIRECTORY,
717                                               fc.getSelectedFile().getPath());
718             }
719             else
720                 return;
721         }
722         else
723         {
724             storage.setParamValue(ChannelStorage.DESTINATION,path);
725         }
726 
727         try
728         {
729             storage.save();
730         }
731         catch (IOException ie)
732         {
733             ie.printStackTrace();
734         }
735 
736     }
737 
738     /**
739      * Perform post close operations
740      *
741      * This one will save our current state on local disk
742      *
743      */
744     private void onClose()
745     {
746         String file_name = runtimeProperties.getProperty("DEFAULT_INI_FILE");
747 
748         FileOutputStream out;
749         try
750         {
751             out = new FileOutputStream(file_name);
752 
753             // saving window position (possibly move names to GuiConstants)
754             runtimeProperties.put("window.x", (new Integer(this.getX())).toString());
755             runtimeProperties.put("window.y", (new Integer(this.getY())).toString());
756             runtimeProperties.put("window.width", (new Integer(this.getWidth())).toString());
757             runtimeProperties.put("window.height", (new Integer(this.getHeight())).toString());
758 
759             //saving currently expanded tree nodes
760             runtimeProperties.store(out,"");
761             out.close();
762         }
763         catch (FileNotFoundException fnfe)
764         {
765             fnfe.printStackTrace();
766         }
767         catch (IOException ie)
768         {
769             ie.printStackTrace();
770         }
771 
772         if (runtimeProperties.getProperty(fmGuiConstants.AUTOSAVE_ON_EXIT).equals("T"))
773         {
774             storage.setCategories(categoryTree.getCategories());
775             saveStorage((String)storage.getParamValue(ChannelStorage.SOURCE)); // SAVING TO CURRENT FILE
776         }
777 
778         System.exit(0);
779     }
780 
781     /**
782      * Find all matched items within all available channels
783      *
784      * <p>Results are set as new channel for content panel</p>
785      *
786      * @param pattern
787      */
788     public void performSearchOperation(String pattern)
789     {
790         if (pattern == null)
791             return;
792 
793         String resultPattern = pattern;
794         //todo move to separate function
795         {
796             // Removing regular expression constructs fromsource string
797             String[] constructs = new String[] { "\\*",
798                                                  "\\(","\\)",
799                                                  "\\[","\\]",
800                                                  "\\{","\\}",
801                                                  "\\.","\\?","\\+"};
802             Pattern s;
803             for (int i = 0, n = constructs.length; i < n; i++) {
804                 s = Pattern.compile(constructs[i]);
805                 if (s.matcher(resultPattern).find())
806                     resultPattern = resultPattern.replaceAll(constructs[i],"\\" + constructs[i]);
807             }
808 
809         }
810 
811         Pattern p = Pattern.compile(resultPattern, Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE | Pattern.MULTILINE);
812         rssChannel searchResult = new rssChannel();
813         HashMap cats = new HashMap(categoryTree.getCategories());
814 
815         if (resultPattern.length() > 0) {
816             synchronized (cats) {
817                 for (Iterator i = cats.values().iterator(); i.hasNext();)
818                     findItem((rssChannelCategory) i.next(), p, searchResult);
819             }
820         }
821 
822         if (searchResult.getItemVector().size() > 0)
823         {
824             searchResult.setTitle(fmUITheme.getString("label.search_results") +
825                     " " + pattern);
826             searchResult.setID(0);
827             contentPane.setChannel(searchResult);
828         }
829         else
830             JOptionPane.showMessageDialog(this,
831                     fmUITheme.getString("msg.nothing_found"),
832                     fmUITheme.getString("label.search_results"),
833                     JOptionPane.INFORMATION_MESSAGE);
834 
835     }
836 
837     private void findItem(rssChannelCategory start_cat, Pattern pattern, rssChannel result)
838     {
839         Map subcats = start_cat.getSubCategories();
840 
841         synchronized (subcats)
842         {
843             for (Iterator i = subcats.values().iterator(); i.hasNext();)
844             {
845                 findItem((rssChannelCategory) i.next(), pattern, result);
846             }
847         }
848 
849         Map channels = start_cat.getChannels();
850 
851         synchronized (channels)
852         {
853             Vector items;
854             rssItem item;
855             rssChannel pCh;
856 
857             for (Iterator i = channels.values().iterator(); i.hasNext();)
858             {
859                 pCh = (rssChannel)i.next();
860                 items = pCh.getItemVector();
861                 for (int k=0, n = items.size(); k < n; k++)
862                 {
863                     item = (rssItem) items.get(k);
864                     if (pattern.matcher(item.getDescription()).find() ||
865                             pattern.matcher(item.getTitle()).find() ||
866                             pattern.matcher(item.getAuthor()).find() ||
867                             pattern.matcher(item.getDateCreated().toString()).find() ||
868                             pattern.matcher(item.getLink()).find())
869                     {
870                         item.setParentInfo(pCh.getID(), pCh.getTitle());
871                         result.addItem(item);
872                     }
873                 }
874             }
875         }
876     }
877 
878     /**
879      * Perform L&F update using runtime and theme settings
880      */
881     public void performLookAndFeelUpdate() {
882 
883         try {
884             fmUITheme.initFeedManLookAndFeel();
885         }
886         catch (IOException ie) {
887             ie.printStackTrace();
888         }
889 
890         if (runtimeProperties.get(fmGuiConstants.URL_HANDLING_CMD).equals(fmGuiConstants.INTERNAL_URL_HANDLER))
891             linkRouter.setBrowserCommand(null);
892         else
893             linkRouter.setBrowserCommand((String) runtimeProperties.get(fmGuiConstants.URL_HANDLING_CMD));
894 
895         categoryTree.repaint();
896         contentPane.performLookAndFeelUpdate();
897         repaint();
898     }
899 
900 
901     /**
902      * Does all L&F dirty checks
903      * @param props
904      */
905     public void setupLookAndFeelDefaults(Properties props) {
906 
907         if (props.containsKey(fmGuiConstants.TREE_FONT))
908             fmUITheme.TREE_FONT = Font.decode((String) props.get(fmGuiConstants.TREE_FONT));
909         else
910             props.put(fmGuiConstants.TREE_FONT, fmUITheme.fontToString(fmUITheme.TREE_FONT,null));
911 
912         if (props.containsKey(fmGuiConstants.CONTENT_FONT))
913             fmUITheme.CONTENT_FONT = Font.decode((String) props.get(fmGuiConstants.CONTENT_FONT));
914         else
915             props.put(fmGuiConstants.CONTENT_FONT, fmUITheme.fontToString(fmUITheme.CONTENT_FONT,null));
916 
917         if (props.containsKey(fmGuiConstants.HEADERS_FONT))
918             fmUITheme.HEADERS_FONT = Font.decode((String) props.get(fmGuiConstants.HEADERS_FONT));
919         else
920             props.put(fmGuiConstants.HEADERS_FONT, fmUITheme.fontToString(fmUITheme.HEADERS_FONT,null));
921     }
922 
923     /**
924      * Register specified channels in the update factory
925      * @param f
926      * @param cMap Map of categories of channels to register
927      */
928 
929     public void registerChannelsToUpdater(updateFactory f, Map cMap) {
930 
931         rssChannelCategory tcat;
932         Map tMap;
933 
934         for (Iterator i = cMap.values().iterator(); i.hasNext();)
935         {
936             tcat = (rssChannelCategory) i.next();
937             registerChannelsToUpdater(f,tcat.getSubCategories());
938             tMap = tcat.getChannels();
939             for (Iterator chi = tMap.values().iterator(); chi.hasNext();)
940                 f.registerForUpdate((Updateable) chi.next(), false); // LOOK AT SARTUP SETTINGS
941         }
942     }
943 }